Pages

顯示具有 Android 標籤的文章。 顯示所有文章
顯示具有 Android 標籤的文章。 顯示所有文章

2017年6月20日 星期二

Android SOAP client

這次的問題需要使用 soap 格式來和 WSDL server 連線傳遞資訊。因為 Android 沒有支援 soap 的 library 所以需要額外掛載支援 soap 的 Ksoap2 jar。
但是試過 Ksoap2 後發現它包出來的格式和WSDL的格式無法符合,讓server 無法解析。在<soapenv:Envelope>中無法自訂自己的namespace資訊。所以只能自己動手包出request,以下詳細說明各段所需程式碼。
基本所需的變數
private final String MAIN_REQUEST_URL = "http://tmpuri.org/";
private final String NAMESPACE = "http://namespaceuri.org/";
private String SOAP_ACTION = "http://namespaceurimethod.org/";
private HttpURLConnection SERVER_CONNECTION;

此request範例是我遇到的 WSDL server內定的格式,所以可能會跟別人遇到的有點誤差,自行調整
request範例
String requestString = "<Request>"+
    "<Access/>"+
    "<RequestContent>"+
    "<Parameter>"+
    "<Record>"+
    "<Field name=\"user\" value=\"hello\" />"+
    "<Field name=\"pwd\" value=\"abc1234\" />"+
    "</Record>"+
    "</Parameter>"+
    "<Document />"+
    "</RequestContent>"+
    "</Request>";
String actionName = "CheckLogin";

包出SOAP格式
public String getSoapEnvelope(String actionName, String requestString) {
    SOAP_ACTION += actionName;
    String soapEnvelope = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:sv=\""+NAMESPACE+"\">" +
               "<soapenv:Header/>" +
               "<soapenv:Body>";
    soapEnvelope += " <tip:"+actionName+"><sv:request>";
    //add request
    soapEnvelope += requestString;
    soapEnvelope += "</sv:request></sv:"+actionName+">";
    soapEnvelope += "</soapenv:Body></soapenv:Envelope>";
    return soapEnvelope;
}

包出soap envolope後,就可以把這個字串透過http request傳送給server
建立http request
public String sendRequestToSystem(String soapEnvelope) {
    BufferedReader rd = null;
    String line;
    String resultXML = "";
    try {
 //create connection
        URL url = new URL(MAIN_REQUEST_URL);
        HttpURLConnection soapServerConnection = (HttpURLConnection) url.openConnection();
        soapServerConnection.setDoOutput(true);
        soapServerConnection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
        soapServerConnection.setRequestProperty("SOAPAction", SOAP_ACTION);
        soapServerConnection.setRequestProperty("POST", MAIN_REQUEST_URL+" HTTP/1.1");
        soapServerConnection.setRequestProperty("Content-Length", "" + soapEnvelope.length());
        soapServerConnection.setRequestProperty("Accept-Encoding", "gzip,deflate");
        soapServerConnection.setRequestMethod("POST");
        byte[] postData = soapEnvelope.getBytes();
        //send data to soap server
        DataOutputStream wr = new DataOutputStream(this.soapServerConnection.getOutputStream());
        wr.write(postData);
        wr.close();
        //read data from soap server
        BufferedReader rd = new BufferedReader(new java.io.InputStreamReader(soapServerConnection.getInputStream()));
        while ((line = rd.readLine()) != null) {
     line = line.replace("&lt;", "<");
     line = line.replace("&gt;", ">");
     resultXML += line;
 }
    } catch (MalformedURLException e) {
 e.printStackTrace();
    } catch (ProtocolException e) {
 e.printStackTrace();
    } catch (IOException e) {
 e.printStackTrace();
    } catch (Exception e) {
 e.printStackTrace();
    }
    return resultXML;       
}

依照上述流程透過 resultXML變數就可以取得 soap response資訊
推薦一個測試WSDL的工具: SOAP UI
可以建立一個WSDL的project連線到server 測試每個request 很方便.

2015年9月23日 星期三

[android] record video

        在專案中要使用 android 的 camera 來實作錄影與拍照功能. 雖然網路上有許多範例但是還是會遇到一些問題.

以下是使用Camera 必備的 Activity 架構
public class MainActivity extends Activity implements SurfaceHolder.Callback{

    private SurfaceView surfaceview;
    private MediaRecorder mediarecorder;
    private SurfaceHolder surfaceHolder;
    private Button startButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ...
    }

    @Override
    protected void onResume(){
        camera = Camera.open();
        if (phoneConfigure.orientation == Configuration.ORIENTATION_PORTRAIT)
            camera.setDisplayOrientation(90);
        super.onResume();
    }
 
    @Override
    protected void onPause(){
        camera.stopPreview();
        camera.setPreviewCallback(null);
        camera.release();
        super.onPause();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // TODO Auto-generated method stub
       Camera.Parameters parameters = camera.getParameters();
       parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); 
  
       camera.setParameters(parameters);
       camera.startPreview();
    }
 
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
 
      // TODO Auto-generated method stub
      try {
  
          camera.setPreviewDisplay(surfaceHolder);
   
      } catch (IOException e) {
          // TODO Auto-generated catch block
          camera.release();
          camera = null;
          e.printStackTrace();
      }
    }
 
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
         // TODO Auto-generated method stub 
 
    }  

  
}

下面是錄影的相關重要程式碼

 public void startRecord(int videoWidth,int videoHeight){
 
 mediarecorder = new MediaRecorder();
  
 camera.stopPreview();  
 camera.unlock();
 mediarecorder.setCamera(camera);
 mediarecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
 mediarecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
 mediarecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
 mediarecorder.setVideoSize(videoWidth,videoHeight);
 if (phoneConfigure.orientation == Configuration.ORIENTATION_PORTRAIT)
     mediarecorder.setOrientationHint(90);
 mediarecorder.setOutputFile(createVideoFilePath(fileExtention));
 mediarecorder.setPreviewDisplay(surfaceHolder.getSurface());
  
 try {
     mediarecorder.prepare();
     mediarecorder.start(); 
 }catch (Exception e) {
     mediarecorder.stop();
     mediarecorder.release();
     e.printStackTrace();
     toast(e.getCause().toString());
 }
 }

 public void stopRecord(){
     if (mediarecorder != null) {
         mediarecorder.stop();
         mediarecorder.release();
         mediarecorder = null;
     }
 }
完整相關程式碼: Github

2015年9月8日 星期二

[android] external sdcard path 取得

 20171215:更新多種其他android手機SD path路徑方式
在 android 4.4版本之後 無法任意存取sd card的位置, 只能寫入與存取自己app 下的資料夾
 /Android/Data/<app-packagename>/
  ex: (/Android/Data/com.example.myapp/)

先利用 getExternalFilesDir(null);
可以自動在內部儲存空間和SD card創立 /Android/Data/<app-packagename>/ 資料夾

因為每個手機的sdcard 路徑都會不同
利用 System.getenv("SECONDARY_STORAGE"); 來取得sd card 的路徑 (ex, /storage/sdcard1/) 最後sdcard的路徑就可以寫成
getExternalFilesDir(null);
String path = System.getenv("SECONDARY_STORAGE") + "/Android/Data/com.example.myapp/";
android 6.0 SD card path
 private String androidMarshmallowSDcardPath() {
  String rootPath = null;
  File f = new File("/storage");
  if (f.isDirectory()) {
   String[] s = f.list();
   for (int i = 0; i < s.length; i++) {
    if(s[i].matches(".*-+.*")) {
     rootPath ="/storage/" + s[i];
     break;
    }else if(s[i].matches("exfat_uuid")) {// SONY Z3 SD card path name
     rootPath ="/storage/" + s[i];
     break;
    }
   }
  }
  return rootPath;
 }
如果把SD card 格式化成內部儲存空間,例如 HTC M8手機以上有支援此功能
SDcardPath = "/storage/emulated/0/Android/data/com.example.myapp/";
//SONY Xperia Miro
if(android.os.Build.MODEL.matches(".*ST23a+.*")) {
     SDcardPath = "/mnt/ext_card" +"/Android/data/com.phison.sdcardtest/";
}
相關permission
<uses-permission android:name="android.permissions.WRITE_EXTERNAL_STORAGE" />

2013年8月13日 星期二

在Android 使用 base64 的 class

這次要在Android 上跑一個AES的範例,出現一些問題
在Android 上無法使用
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
解決辦法是要import 不同的函式
首先 先下載:apache.commons的元件
我抓的版本為 :commons-codec-1.8-bin.zip (反正抓最新版就好)
在以下路徑 匯入函式庫:
project > Build Path > Add External Archives >
匯入commons-codec-1.8.jar
接著就改成import下面的函式
import org.apache.commons.codec.binary.Base64;

加密的寫法:
String outputString = new String(Base64.encodeBase64(inputString.getBytes()));

解密的寫法:
byte[] data = Base64.decodeBase64(msg.getBytes());
byte[] result = getCipher(CryptMode.DECODE).doFinal(data);
參考: base64 AES範例
 
 
Blogger Templates