2010年9月4日 星期六

【Android】使用Zxing掃描器

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


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


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

下載的副程式
  1. //-------開始下載
  2. private void startDownload(String url) throws Exception {
  3. if (!URLUtil.isNetworkUrl(url)) {
  4. //-------網址有誤
  5. }
  6. else {
  7. //-------取得URL
  8. URL myURL = new URL(url);
  9. //-------建立連線
  10. URLConnection conn = myURL.openConnection();
  11. conn.connect();
  12. //-------InputStream 下載檔案
  13. InputStream is = conn.getInputStream();
  14. if (is == null) {
  15. throw new RuntimeException("stream is null");
  16. }
  17. //-------建立暫存檔案
  18. File myTempFile = File.createTempFile(fileName, "."+fileExName);
  19. //-------取得暫存檔案路徑
  20. currentTempFilePath = myTempFile.getAbsolutePath();
  21. //-------設定串流輸出標地物為暫存檔
  22. FileOutputStream fos = new FileOutputStream(myTempFile);
  23. //-------串流輸出
  24. byte buf[] = new byte[128];
  25. do {
  26. int numread = is.read(buf);
  27. if (numread <= 0) {
  28. break;
  29. }
  30. fos.write(buf, 0, numread);
  31. } while (true);
  32. //-------開啟檔案進行安裝
  33. startInstall(myTempFile);
  34. //-------關閉串流
  35. try {
  36. is.close();
  37. }
  38. catch (Exception ex) {
  39. Log.e(LogTag, "error: " + ex.getMessage(), ex);
  40. }
  41. }
  42. }
傳入url即 Zxing apk 載點。


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


4、使用已安裝的 Zxing 應用程式,並取回 QR code 內容
這個部分是參照至 Zxing 的 wiki,它推薦你將 Zxing 與你的 app 分開,用你的 app 去開啟Zxing,而不是把整包 Zxing 專案的 source code 都包進你的專案。
  1. public Button.OnClickListener mScan = new Button.OnClickListener() {
  2.     public void onClick(View v) {
  3.         Intent intent = new Intent("com.google.zxing.client.android.SCAN");
  4.         intent.putExtra("SCAN_MODE", "QR_CODE_MODE");
  5.         startActivityForResult(intent, 0);
  6.     }
  7. };
  8.  
  9. public void onActivityResult(int requestCode, int resultCode, Intent intent) {
  10.     if (requestCode == 0) {
  11.         if (resultCode == RESULT_OK) {
  12.             String contents = intent.getStringExtra("SCAN_RESULT");
  13.             String format = intent.getStringExtra("SCAN_RESULT_FORMAT");
  14.             // Handle successful scan
  15.         } else if (resultCode == RESULT_CANCELED) {
  16.             // Handle cancel
  17.         }
  18.     }
  19. }
上面的是由按鈕去觸發掃描器的範例,startActivityForResult的第二個參數是用於讓你的程式能夠區別是哪的activty開啟了掃描器;第二段程式是當Zxing完成掃描回到原activity後可以讀出 QR code 的值,content為字串內容,format為格式,cancel適用於使用倒回鍵的情況。

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

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


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


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

  1. private boolean checkSDCard() {
  2.     if(android.os.Environment.getExternalStorageState()
  3.         .equals(android.os.Environment.MEDIA_MOUNTED))
  4.         return true;
  5.     else
  6.         return false;
  7. }



參考書目: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. 要怎樣才能正常跑 ? 因為我不會這些手機程式
    不知道要加那些程式
    不曉得有沒有更完整的原始碼 並講解 .. 謝謝

    回覆刪除