Android ZXing(二維碼)庫(kù)全面使用解析

Android ZXing(二維碼)庫(kù)全面使用解析

本文原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處。
歡迎關(guān)注我的 簡(jiǎn)書 ,關(guān)注我的專題 Android Class 我會(huì)長(zhǎng)期堅(jiān)持為大家收錄簡(jiǎn)書上高質(zhì)量的 Android 相關(guān)博文。

寫在前面:

春天到了,天氣轉(zhuǎn)暖,風(fēng)吹走了北京的霧霾也帶來(lái)了困倦。每天感覺就是睡不醒、起不來(lái)。前一陣研究了 View 的體系,還差滑動(dòng)沖突和 View 的繪制沒有落筆成文,還看了很多關(guān)于 MVP 這種代碼模式的文章,未來(lái)爭(zhēng)取把它們都整理分享出來(lái),便于記憶和交流。

不知不覺二維碼已經(jīng)深刻影響了我們的生活,為我們提供了極大的便利。線下付賬、租一輛單車、或者去要一個(gè)妹子的微信號(hào)等等。張小龍把它稱為從線下到線上的入口。正因?yàn)槎S碼如此的重要,并且出現(xiàn)的頻率越來(lái)越高,所以 Android 應(yīng)用中掃面二維碼、條形碼的需求也很常見了。本文就是來(lái)接入使用一個(gè)不錯(cuò)的二維碼庫(kù) ZXing

二維碼是什么

在研究 ZXing 之前,我一直好奇二維碼是根據(jù)什么生成的,并且最大能保存多少的信息,去查閱了一下資料,正好解決了我的疑問,在此介紹一下。

二維條碼是指在一維條碼(條形碼)的基礎(chǔ)上擴(kuò)展出另一維具有可讀性的條碼,使用黑白矩形圖案表示二進(jìn)制數(shù)據(jù),被設(shè)備掃描后可獲取其中所包含的信息。一維條碼的寬度記載著數(shù)據(jù),而其長(zhǎng)度沒有記載數(shù)據(jù)。二維條碼的長(zhǎng)度、寬度均記載著數(shù)據(jù)。二維條碼有一維條碼沒有的“定位點(diǎn)”和“容錯(cuò)機(jī)制”。容錯(cuò)機(jī)制在即使沒有辨識(shí)到全部的條碼、或是說(shuō)條碼有污損時(shí),也可以正確地還原條碼上的信息。二維條碼的種類很多,不同的機(jī)構(gòu)開發(fā)出的二維條碼具有不同的結(jié)構(gòu)以及編寫、讀取方法。

二維碼

總結(jié)起來(lái)就是二維碼是將有限的信息轉(zhuǎn)成二進(jìn)制,并且表現(xiàn)為黑白矩陣圖,與一維的條形碼相比,二維碼擁有更好的容錯(cuò)能力。

ZXing

現(xiàn)在我們大概知道了二維碼是怎么生成的,有關(guān) Android 上掃碼的庫(kù)有很多,這次來(lái)介紹的是 ZXing,一個(gè)出色的開源掃碼庫(kù)。

來(lái)看看它在 github 上的倉(cāng)庫(kù):

GitHub ZXing

上面 ReadMe 文件傳遞的信息大概就是 ZXing 是個(gè)很厲害的庫(kù),支持各種平臺(tái)等等...然后又找了它一些相關(guān)的連接,我發(fā)現(xiàn)有關(guān) Android 的信息少之又少,僅僅說(shuō)了怎么引入,具體使用上沒說(shuō),并且源碼中給出的 Android Module 代碼量有點(diǎn)多,掌握的成本太高,總之當(dāng)時(shí)我覺得這個(gè)學(xué)習(xí)的姿勢(shì)不太對(duì)。

回到 google 重新搜索了一下 Android ZXing,終于找到了一個(gè)正確的倉(cāng)庫(kù)來(lái)引入并使用它:

zxing-android-embedded

這個(gè)庫(kù)是一個(gè)基于 ZXing 的 Android 二維碼解碼庫(kù),使用起來(lái)還是非常簡(jiǎn)單的。

我把它 fork 回之后,做了一些優(yōu)化和更新,具體請(qǐng)查看下文。

中文版 ZXing Android Embedded

快速使用:

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);
    }
}

可以看到使用起來(lái)非常便捷,onActivityResult帶回掃碼出來(lái)的結(jié)果,然后進(jìn)行處理就OK了。下文中就不再介紹 ReadMe 中的內(nèi)容,轉(zhuǎn)而介紹一下這個(gè)庫(kù)一些其他的配置。

    protected Class<?> getDefaultCaptureActivity() {
        return CaptureActivity.class;
    }

一步步跟進(jìn) IntentIntegrator(this).initiateScan() 方法可以發(fā)現(xiàn),當(dāng)我不設(shè)置 CaptureActivity 時(shí),調(diào)用默認(rèn)的 Activity 就是 CaptureActivity

所以對(duì)于吊起的掃碼 Activity 來(lái)說(shuō),他的方向可以在 manifest 文件中的 android:screenOrientation 屬性直接指定:

        <activity
            android:name="com.journeyapps.barcodescanner.CaptureActivity"
            android:screenOrientation="landscape"
            tools:replace="screenOrientation" />

除了最基本的掃碼使用,再來(lái)看看他 IntentIntegrator 中其它的 setXXX 屬性吧。

  • integrator.setPrompt 在掃描頁(yè)面添加一個(gè)文字描述,空字符串時(shí),可以取消顯示它。

  • integrator.setOrientationLocked 設(shè)置是否鎖定掃碼 Activity 的方向。默認(rèn)為 true

  • integrator.setCameraId 設(shè)置使用攝像頭的 id,0 為后置攝像頭,1 為前置攝像頭。這是系統(tǒng) 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 設(shè)置掃描完成時(shí)是否允許“嘟嘟”的聲音。默認(rèn)為 true。源碼中的這個(gè)設(shè)置位于 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 設(shè)置掃描的二維碼格式

  • integrator.setTimeout 設(shè)置一個(gè)超時(shí)時(shí)間,超過這個(gè)時(shí)間之后,掃描的 Activity 將會(huì)被 finish 。

自定義

通過昨天半天的時(shí)間,算是把這個(gè)庫(kù)看明白了,寫得很好值得推薦,有心的朋友可以好好看看源碼,有的可學(xué)。

項(xiàng)目中的需求各有不同,所以在 UI 上可定制就成了很重要的一點(diǎn),這個(gè)庫(kù)雖然沒開放出很多方法,但是自定義起來(lái)依然自由方便,一起來(lái)看看姿勢(shì)吧。

  • integrator.setCaptureActivity 我們可以通過這個(gè)方法,指定要傳入的自定義的掃描 Activity,那這個(gè) Activity 應(yīng)該怎么去定制呢?
    <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 的一個(gè)封裝類,具體的 UI 屬性,在 app:zxing_scanner_layout="@layout/custom_barcode_scanner" 引入的 custom_barcode_scanner 布局文件中進(jìn)行定制修改。來(lái)看看這個(gè)布局:

<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>
自定義掃描框

這個(gè)圖很直觀了吧,要是定制掃描線的顏色啊,或者掃描框的大小啊,都沒有問題了~

當(dāng)然我把它 fork 回來(lái)之后,做了一些改動(dòng),比如修了兩個(gè) bug,然后開放了兩個(gè)我認(rèn)為比較合適的新的設(shè)置項(xiàng):

  • setBeepResource 讓掃描之后發(fā)出的嘟嘟聲可定制,需要傳入本地的一個(gè) raw 文件。

  • setVibrateEnable 設(shè)置掃描完成之后,是否讓手機(jī)震動(dòng)。

我做了修改之后的倉(cāng)庫(kù)連接:

ZXing Android Embedded

一直會(huì)持續(xù)更新它,需要的朋友保持關(guān)注吧~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,836評(píng)論 6 540
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,275評(píng)論 3 428
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,904評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,633評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,368評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,736評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,740評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,919評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,481評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,235評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,427評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,968評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,656評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,055評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,348評(píng)論 1 294
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,160評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,380評(píng)論 2 379

推薦閱讀更多精彩內(nèi)容