Android ZXing(二維碼)庫的全面使用解析
Android ZXing(二維碼)庫解析
本文原創,轉載請註明出處。
歡迎關注我的 簡書 ,關注我的專題 Android Class 我會長期堅持為大家收錄簡書上高質量的 Android 相關博文。
寫在前面:
春天到了,天氣轉暖,風吹走了北京的霧霾也帶來了睏倦。每天感覺就是睡不醒、起不來。前一陣研究了 View 的體系,還差滑動衝突和 View 的繪製沒有落筆成文,還看了很多關於 MVP 這種程式碼模式的文章,未來爭取把它們都整理分享出來,便於記憶和交流。
不知不覺二維碼已經深刻影響了我們的生活,為我們提供了極大的便利。線下付賬、租一輛單車、或者去要一個妹子的微訊號等等。張小龍把它稱為從線下到線上的入口。正因為二維碼如此的重要,並且出現的頻率越來越高,所以 Android 應用中掃面二維碼、條形碼的需求也很常見了。本文就是來接入使用一個不錯的二維碼庫 ZXing
二維碼是什麼
在研究 ZXing 之前,我一直好奇二維碼是根據什麼生成的,並且最大能儲存多少的資訊,去查閱了一下資料,正好解決了我的疑問,在此介紹一下。
二維條碼是指在一維條碼(條形碼)的基礎上擴展出另一維具有可讀性的條碼,使用黑白矩形圖案表示二進位制資料,被裝置掃描後可獲取其中所包含的資訊。一維條碼的寬度記載著資料,而其長度沒有記載資料。二維條碼的長度、寬度均記載著資料。二維條碼有一維條碼沒有的“定位點”和“容錯機制”。容錯機制在即使沒有辨識到全部的條碼、或是說條碼有汙損時,也可以正確地還原條碼上的資訊。二維條碼的種類很多,不同的機構開發出的二維條碼具有不同的結構以及編寫、讀取方法。
總結起來就是二維碼是將有限的資訊轉成二進位制,並且表現為黑白矩陣圖,與一維的條形碼相比,二維碼擁有更好的容錯能力。
ZXing
現在我們大概知道了二維碼是怎麼生成的,有關 Android 上掃碼的庫有很多,這次來介紹的是 ZXing,一個出色的開源掃碼庫。
來看看它在 github 上的倉庫:
上面 ReadMe 檔案傳遞的資訊大概就是 ZXing 是個很厲害的庫,支援各種平臺等等…然後又找了它一些相關的連線,我發現有關 Android 的資訊少之又少,僅僅說了怎麼引入,具體使用上沒說,並且原始碼中給出的 Android Module 程式碼量有點多,掌握的成本太高,總之當時我覺得這個學習的姿勢不太對。
回到 google 重新搜尋了一下 Android ZXing,終於找到了一個正確的倉庫來引入並使用它:
這個庫是一個基於 ZXing 的 Android 二維碼解碼庫,使用起來還是非常簡單的。
我把它 fork 回之後,做了一些優化和更新,具體請檢視下文。
快速使用:
new IntentIntegrator(this).initiateScan(); // `this` is the current Activity
// Get the results:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if(result != null) {
if(result.getContents() == null) {
Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "Scanned: " + result.getContents(), Toast.LENGTH_LONG).show();
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
可以看到使用起來非常便捷,onActivityResult
帶回掃碼出來的結果,然後進行處理就OK了。下文中就不再介紹 ReadMe 中的內容,轉而介紹一下這個庫一些其他的配置。
protected Class<?> getDefaultCaptureActivity() {
return CaptureActivity.class;
}
一步步跟進 IntentIntegrator(this).initiateScan()
方法可以發現,當我不設定 CaptureActivity 時,呼叫預設的 Activity 就是 CaptureActivity
所以對於吊起的掃碼 Activity 來說,他的方向可以在 manifest 檔案中的 android:screenOrientation
屬性直接指定:
<activity
android:name="com.journeyapps.barcodescanner.CaptureActivity"
android:screenOrientation="landscape"
tools:replace="screenOrientation" />
除了最基本的掃碼使用,再來看看他 IntentIntegrator
中其它的 setXXX 屬性吧。
integrator.setPrompt 在掃描頁面新增一個文字描述,空字串時,可以取消顯示它。
integrator.setOrientationLocked 設定是否鎖定掃碼 Activity 的方向。預設為 true
integrator.setCameraId 設定使用攝像頭的 id,0 為後置攝像頭,1 為前置攝像頭。這是系統 CameraInfo 的屬性。
/**
* The facing of the camera is opposite to that of the screen.
*/
public static final int CAMERA_FACING_BACK = 0;
/**
* The facing of the camera is the same as that of the screen.
*/
public static final int CAMERA_FACING_FRONT = 1;
- integrator.setBeepEnabled 設定掃描完成時是否允許“嘟嘟”的聲音。預設為 true。原始碼中的這個設定位於 BeepManager,通過 MediaPlayer 播放了一段 .ogg 檔案。
- integrator.setBarcodeImageEnabled 儲存掃描完成後二維碼的影象。原始碼在這裡:
/**
* Save the barcode image to a temporary file stored in the application's cache, and return its path.
* Only does so if returnBarcodeImagePath is enabled.
*
* @param rawResult the BarcodeResult, must not be null
* @return the path or null
*/
private String getBarcodeImagePath(BarcodeResult rawResult) {
String barcodeImagePath = null;
if (returnBarcodeImagePath) {
Bitmap bmp = rawResult.getBitmap();
try {
File bitmapFile = File.createTempFile("barcodeimage", ".jpg", activity.getCacheDir());
FileOutputStream outputStream = new FileOutputStream(bitmapFile);
bmp.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
outputStream.close();
barcodeImagePath = bitmapFile.getAbsolutePath();
} catch (IOException e) {
Log.w(TAG, "Unable to create temporary file and store bitmap! " + e);
}
}
return barcodeImagePath;
}
integrator.setDesiredBarcodeFormats 設定掃描的二維碼格式
integrator.setTimeout 設定一個超時時間,超過這個時間之後,掃描的 Activity 將會被 finish 。
自定義
通過昨天半天的時間,算是把這個庫看明白了,寫得很好值得推薦,有心的朋友可以好好看看原始碼,有的可學。
專案中的需求各有不同,所以在 UI 上可定製就成了很重要的一點,這個庫雖然沒開放出很多方法,但是自定義起來依然自由方便,一起來看看姿勢吧。
- integrator.setCaptureActivity 我們可以通過這個方法,指定要傳入的自定義的掃描 Activity,那這個 Activity 應該怎麼去定製呢?
<com.journeyapps.barcodescanner.DecoratedBarcodeView
android:id="@+id/zxing_barcode_scanner"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:zxing_scanner_layout="@layout/custom_barcode_scanner">
</com.journeyapps.barcodescanner.DecoratedBarcodeView>
DecoratedBarcodeView
是掃描 View 的一個封裝類,具體的 UI 屬性,在 app:zxing_scanner_layout="@layout/custom_barcode_scanner"
引入的 custom_barcode_scanner
佈局檔案中進行定製修改。來看看這個佈局:
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.journeyapps.barcodescanner.BarcodeView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/zxing_barcode_surface"
app:zxing_framing_rect_width="250dp"
app:zxing_framing_rect_height="50dp"/>
<com.journeyapps.barcodescanner.ViewfinderView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/zxing_viewfinder_view"
app:zxing_possible_result_points="@color/zxing_custom_possible_result_points"
app:zxing_result_view="@color/zxing_custom_result_view"
app:zxing_viewfinder_laser="@color/zxing_custom_viewfinder_laser"
app:zxing_viewfinder_mask="@color/zxing_custom_viewfinder_mask"/>
<TextView
android:id="@+id/zxing_status_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:background="@color/zxing_transparent"
android:text="@string/zxing_msg_default_status"
android:textColor="@color/zxing_status_text"/>
</merge>
這個圖很直觀了吧,要是定製掃描線的顏色啊,或者掃描框的大小啊,都沒有問題了~
當然我把它 fork 回來之後,做了一些改動,比如修了兩個 bug,然後開放了兩個我認為比較合適的新的設定項:
setBeepResource 讓掃描之後發出的嘟嘟聲可定製,需要傳入本地的一個 raw 檔案。
setVibrateEnable 設定掃描完成之後,是否讓手機震動。
我做了修改之後的倉庫連線:
一直會持續更新它,需要的朋友保持關注吧~