2010年9月4日 星期六

【Android】使用Zxing掃描器

內容為畢專用 open source 的 google code Zxing 掃描器使用,
整個程式碼主軸包含...
  1. 偵測手機上是否已安裝 Zxing。
  2. 下載 Zxing apk。
  3. 安裝 Zxing apk。
  4. 使用已安裝的 Zxing 應用程式,並取回 QR code 內容。


1、偵測手機上是否已安裝 Zxing
Intent intent = new Intent("com.google.zxing.client.android.SCAN");
if(getPackageManager().queryIntentActivities(intent, 
    PackageManager.MATCH_DEFAULT_ONLY).size() == 0) {
    //未安裝Zxing
}else{
    //已安裝Zxing
}
new Intent內容為 Zxing package,你也可以用此判斷式去偵測任何已知 package的app是否已經被安裝在device上。


2、下載 Zxing apk
必要宣告
//--------寫入SD卡的暫存檔路徑
private String currentTempFilePath = "";
//--------zxing apk 載點
private String zxingDownload_url;
//--------檔名 (由載點剪字)
private String fileName;
//--------副檔名 (由載點剪字)
private String fileExName;

下載的副程式
//-------開始下載
private void startDownload(String url) throws Exception {
    if (!URLUtil.isNetworkUrl(url)) { 
        //-------網址有誤
    }
    else {
        //-------取得URL
        URL myURL = new URL(url);
        
        //-------建立連線
        URLConnection conn = myURL.openConnection(); 
        conn.connect();
        
        //-------InputStream 下載檔案
        InputStream is = conn.getInputStream(); 
        if (is == null) {
            throw new RuntimeException("stream is null");
        }
        //-------建立暫存檔案
        File myTempFile = File.createTempFile(fileName, "."+fileExName);
        //-------取得暫存檔案路徑
        currentTempFilePath = myTempFile.getAbsolutePath();
        //-------設定串流輸出標地物為暫存檔
        FileOutputStream fos = new FileOutputStream(myTempFile);
        
        //-------串流輸出
        byte buf[] = new byte[128]; 
        do { 
            int numread = is.read(buf);
          
            if (numread <= 0) {
                break;
            }
            fos.write(buf, 0, numread); 
        } while (true);
        
        //-------開啟檔案進行安裝
        startInstall(myTempFile);
        
        //-------關閉串流
        try {
            is.close();
        }
        catch (Exception ex) {
             Log.e(LogTag, "error: " + ex.getMessage(), ex);
        }
    }
}
傳入url即 Zxing apk 載點。


3、安裝 Zxing apk
//-------開始安裝
private void startInstall(File tempFile){
    Intent intent = new Intent();
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.setAction(android.content.Intent.ACTION_VIEW);
    
    //-------設定intent的file與MimeType
    intent.setDataAndType(Uri.fromFile(tempFile), 
     "application/vnd.android.package-archive");
    startActivity(intent);
}
傳入tempFile為Zxing apk,intent設定為使用 packageInstaller 來安裝指定apk。


4、使用已安裝的 Zxing 應用程式,並取回 QR code 內容
這個部分是參照至 Zxing 的 wiki,它推薦你將 Zxing 與你的 app 分開,用你的 app 去開啟Zxing,而不是把整包 Zxing 專案的 source code 都包進你的專案。
public Button.OnClickListener mScan = new Button.OnClickListener() {
    public void onClick(View v) {
        Intent intent = new Intent("com.google.zxing.client.android.SCAN");
        intent.putExtra("SCAN_MODE", "QR_CODE_MODE");
        startActivityForResult(intent, 0);
    }
};

public void onActivityResult(int requestCode, int resultCode, Intent intent) {
    if (requestCode == 0) {
        if (resultCode == RESULT_OK) {
            String contents = intent.getStringExtra("SCAN_RESULT");
            String format = intent.getStringExtra("SCAN_RESULT_FORMAT");
            // Handle successful scan
        } else if (resultCode == RESULT_CANCELED) {
            // Handle cancel
        }
    }
}
上面的是由按鈕去觸發掃描器的範例,startActivityForResult的第二個參數是用於讓你的程式能夠區別是哪的activty開啟了掃描器;第二段程式是當Zxing完成掃描回到原activity後可以讀出 QR code 的值,content為字串內容,format為格式,cancel適用於使用倒回鍵的情況。

補充
Runnable r = new Runnable(){
    public void run(){
        try{
            startDownload(zxingDownload_url);
        } 
        catch(Exception e){ 
            Log.e(LogTag, e.getMessage(), e); 
        } 
    } 
};   
new Thread(r).start();
由於 startDownload() 會 throw Exception 所以調用時需要 try catch,另外似乎是因為 Stream
的關係,如果不用 thread 似乎沒有辦法正常下載檔案。

由於下載是寫入SD卡的關係,你的手機或模擬器必須備有SD卡,並且在AndroidManifest.xml
加入必要的權限設定。


<!--使用網路-->
<uses-permission android:name="android.permission.INTERNET" />
<!--系統I/O-->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!--自動安裝程式-->
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<!--寫入SD卡-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />


如果你打算先偵測 device 是否裝備 SD卡 並可運行,可以使用下述方法。

private boolean checkSDCard() {
    if(android.os.Environment.getExternalStorageState()
        .equals(android.os.Environment.MEDIA_MOUNTED))
        return true;
    else
        return false;
}



參考書目:Android 開發範例大全2
參考網站:Google Code Zxing

4 則留言:

  1. 請問一下
    2、下載 Zxing apk
    必要宣告

    //--------寫入SD卡的暫存檔路徑
    private String currentTempFilePath = "";
    //--------zxing apk 載點
    private String zxingDownload_url;
    //--------檔名 (由載點剪字)
    private String fileName;
    //--------副檔名 (由載點剪字)
    private String fileExName;
    裡面要輸入些什麼呢

    回覆刪除
    回覆
    1. 看你的Zxing載點放在哪,還有下載後要放在SD卡的什麼路徑,基本上這兩個是由你自己決定的。

      刪除
  2. 請問可以把ZXING 包成library
    然後打勾 is library 直接綁在APP內嗎?

    回覆刪除
  3. 要怎樣才能正常跑 ? 因為我不會這些手機程式
    不知道要加那些程式
    不曉得有沒有更完整的原始碼 並講解 .. 謝謝

    回覆刪除