二維碼掃描開源庫ZXing定制化
最近在用ZXing這個開源庫做二維碼的掃描模塊,開發過程的一些代碼修改和裁剪的經驗和大家分享一下。
我的代碼庫:
https://github.com/SickWorm/ZXingDialog
代碼沒有在github維護,所以沒有log。但是所有修改的地方我都加上了“@ch”的注釋,以方便定位
官方源碼:
https://github.com/zxing/zxing
實現功能:
1、功能裁剪(只保留QRCode二維碼掃描功能,去掉條形碼等其他碼掃描功能)
2、移除資源依賴,提供Dialog形式的掃碼功能
3、API兼容(源碼只兼容4.0以上,現兼容至2.1)
4、轉換為豎屏(源碼為橫屏)
5、掃碼速度優化(主要分三點,現只完成了一點)
6、設備兼容(針對低分辨率設備)
本文還會提到:
7、自定義界面
8、優化調試方法
1、建立工程
ZXing源碼并沒有提供一個完整的實例工程給我們使用,構建一個工程我們需要源碼下的三個文件夾的文件:
core/
android-core/
android/
大概步驟如下:
1、創建一個新工程
2、把android目錄下的所有文件覆蓋到新工程(內含有資源文件和AndroidManifest.xml等構建app所需的文件)
3、把android-core所有Java文件拷入到src目錄下(注意!android-core中的src文件夾需要進行一些改動,原來路 徑是android-core\src\main\java\com\google\zxing\client\android\camera,我們要把 中間的main\java兩層文件夾去掉,不然在Eclipse中無法識別包路徑)
4、把core目錄下的所有Java文件拷入到src目錄下(注意!和步驟3一樣需要去掉main\java兩層文件夾)。這樣ZXing已經可以運行了,我的src目錄是這樣的:
可以直接運行,效果還不錯。如果你遇到一些錯誤,有可能是編譯的JDK版本低于1.7導致的。源碼里使用了ArrayList<>這樣的寫法,1.7以前是不支持的。你可以選擇修改源碼或者提高編譯JDK版本。
但你可能不滿足于這個界面,掃描框太大了,而且是橫屏全屏的,還要求API 15(Android 4.0.3)。下面我們會對這些需求進行修改。
2、代碼優化
1、功能裁剪(只保留QRCode二維碼掃描功能,去掉條形碼等其他碼掃描功能)
我的目標是只保留二維碼識別,不需要其他多余的功能。這一部分的步驟我不打算詳細說明,因為我已經不記得了。。大家可以直接看我的代碼的結果。
可以直接刪掉的是:
com.google.zxing.aztec.** aztec格式的二維碼
com.google.zxing.client.android.book.* Google 圖書相關的功能
com.google.zxing.client.android.clickboard.* 不清楚,復制黏貼?
com.google.zxing.client.android.encode.* 用于生成各種碼
com.google.zxing.client.android.history.* 保存掃碼記錄
com.google.zxing.client.android.result.** 掃碼應用功能相關的功能性代碼
com.google.zxing.client.android.share.* 分享功能
com.google.zxing.client.android.wifi.* WiFi相關,不清楚具體用途
com.google.zxing.datamatrix.** datamatrix格式二維碼
com.google.zxing.maxicode.** maxicode格式二維碼
com.google.zxing.multi.** 貌似是用于多格式支持的?我沒有用到這個包,如果有了解的麻煩告知
com.google.zxing.oned.** one dimension一維碼,也就是條形碼(你去百度搜oned會發現奇怪的東西。。)
com.google.zxing.pdf417.** PDF417格式條形碼
需要修改的是:
com.google.zxing.client.android.CaptureActivity:去掉其他功能的相關代碼,只保留核心功能,即掃碼功 能。界面為一個FrameLayout里面包含一個SurfaceView。代碼移除就不詳細說了,直接看上傳的代碼吧,這個文件我參考了 http://www.cnblogs.com/keyindex/archive/2011/06/08/2074900.html 這個鏈接里的CaptureActivity的修改。
com.google.zxing.MultiFormatReader:這個是指定支持解碼的格式,需要把除QR_CODE以外的格式全部去掉,否則會因為刪掉了解碼包而報錯。具體也請看上傳的代碼。
com.google.zxing.client.result.ProductResultParser:parse函數中,同上。
com.google.zxing.client.android.DecodeThread:構造器中,同上。
另外:
com.google.zxing.client.result 我沒有刪減這個包的代碼,應該也是能優化的
2、移除資源依賴,提供Dialog形式的掃碼功能
經過了第1步的精簡,其實只剩下了2個地方需要修改:
1.掃描界面
2.掃描成功時播放的beep聲音文件
1:去除了其余功能后,對于核心功能我們只需要一個SurfaceView和一個畫界面的View就可以了。代碼如下:
/** * use Java code to build layout instead of xml file * @ch */ private void buildLayout() { requestWindowFeature(Window.FEATURE_NO_TITLE); FrameLayout layout = new FrameLayout(this); LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); layout.setLayoutParams(params); surfaceView = new SurfaceView(this); surfaceView.setLayoutParams(params); layout.addView(surfaceView); viewfinderView = new ViewfinderView(this, null); layout.addView(viewfinderView); setContentView(layout); }
ViewfinderView是ZXing自帶的View,如果要修改界面,直接修改它就可以了,我們第7點會提到。
2:由于我最終的目的是能打包成jar包,所以beep文件不能放在res里,而是放在assets里。
//待補充
3、API兼容(源碼只兼容4.0以上,現兼容至2.1)
這部分修改在源碼中標記為//@ch api compatible。
CaptureActivity.java: //@ch api compatible if (VERSION.SDK_INT < 11) { //surfaceview will push buffer automatically surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } //API 11之前需要手動設置,否則會無法顯示。API11之后為默認設置。 CameraConfigurationManager.java: //@ch api compatible if (VERSION.SDK_INT < 13) { theScreenResolution.x = display.getWidth(); theScreenResolution.y = display.getHeight(); } else { display.getSize(theScreenResolution); } //getSize是API 13之后的新API,之前需要用getWidth和getHeight。 AutoFocusManager.java //@ch api compatible if (VERSION.SDK_INT > 11) { newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { newTask.execute(); } //源碼中這里設置了多線程的模式,THREAD_POOL_EXECUTOR表示這個task最多只有5個線程同時運行,超過5個的就要等待。在低于API 11的版本中,此為默認選項。其實這里只有單線程,所以隨便執行吧。 OpenCameraInterface.java: //@ch api compatible if (VERSION.SDK_INT < 9) { return openWithLowApi(); } ...... /** * for lower than API 9 * @ch api compatible */ public static Camera openWithLowApi() { //If the device does not have a back-facing camera, this returns null Camera camera = Camera.open(); return camera; } //源碼的打開攝像頭是能區分前后攝像頭的,然而API 9之前并沒有前置攝像頭這個概念,所以做了一下處理
就幾個地方,不過也找了我個把小時了。
4、轉換為豎屏(源碼為橫屏)
ZXing默認是橫屏,但是我們一般的APP都會做成豎屏,如果掃碼的時候強制切換成橫屏那樣體驗就不好了。在修改ZXing的豎屏的時候,我按 照的是一般APP的豎屏設置方法,結果發現沒有源碼的效果好,需要把碼放到很小才能完成。后面在調試過程中發現掃碼解析的區域和屏幕畫出來的區域不一樣, 才知道這部分的修改出了問題。然后我搜索找到一篇前輩的文章,參考了一下發現沒有改完全。