Android Studio - QR code scanning === * [name=Ander Liu] ###### tags: `Android Studio` [TOC] ## Zxing * **ZXing** ("zebra crossing") is an open-source, multi-format 1D/2D barcode image processing library implemented in Java, with ports to other languages. * 這堂課,我們打算使用 **Zxing** 這個 library to implement QR code scanning * The Supported Formats of **Zxing** | 1D product | 1D industrial | 2D | | ---------- | ------------- | -------------- | | UPC-A | Code 39 | QR Code | | EAN-8 | Code 128 | Aztec (beta) | | EAN-13 | Codabar | PDF 417 (beta) | | | ITF | MaxiCode | | | RSS-14 | | | | RSS-Expanded | | * [Official APP on Google Play](https://play.google.com/store/apps/details?id=com.google.zxing.client.android) * 我們基本上是根據此網站來設置 https://github.com/journeyapps/zxing-android-embedded ## Adding dependency with Gradle :::danger Android SDK 需要 19 以上 ::: * 我們先把 library 加進來 * 開啟 **build.gradle**,在適當的位置加入以下 dependency ```groovy=1 dependencies { implementation 'com.journeyapps:zxing-android-embedded:3.6.0' implementation 'com.android.support:appcompat-v7:25.3.1' // Minimum 23+ is required } ``` ![](https://i.imgur.com/GPH8qc6.png) ## Hardware Acceleration * Hardware accelation is required since [`TextureView`](https://developer.android.com/reference/android/view/TextureView) is used * 開啟 **AndroidManifest.xml**,在適當的位置 enable hardwareAccelerated 屬性 ```xml=1 <application android:hardwareAccelerated="true" ... > ``` ## Usage with IntentIntegrator * 此為 the source code of the `IntentIntegrator` https://github.com/journeyapps/zxing-android-embedded/blob/master/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java * `IntentIntegrator`顧名思義,就是 [`intent`](https://developer.android.com/reference/android/content/Intent)的integrate版。可以call一些method來設定要開啟的掃描acticity的屬性,最後 call [`initiateScan()`](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L258)來開啟掃描acticity :::warning 有關 [`intent`](https://developer.android.com/reference/android/content/Intent),之後會再介紹 ::: * 以下為可能會用到的 method * 第 98 行 [IntentIntegrator(Activity activity)](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L98) `the Constructor` * 第 146 行 [IntentIntegrator forFragment(Fragment fragment)](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L146) * 第 167 行 [IntentIntegrator setPrompt(String prompt)](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L167) `Set a prompt to display on the capture screen, instead of using the default.` * 第 179 行 [IntentIntegrator setOrientationLocked(boolean locked)](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L179) `By default, the orientation is locked. Set to false to not lock.` * 第 189 行 [IntentIntegrator setCameraId(int cameraId)](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L189) `Use the specified camera ID.` * 第 214 行 [IntentIntegrator setBeepEnabled(boolean enabled)](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L214) `Set to false to disable beep on scan.` * 第 225 行 [IntentIntegrator setBarcodeImageEnabled(boolean enabled)](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L225) `Set to true to enable saving the barcode image and sending its path in the result Intent.` * 第 247 行 [IntentIntegrator setDesiredBarcodeFormats(String... desiredBarcodeFormats)](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L247) `Set the desired barcode formats to scan.` * 第 258 行 [void initiateScan()](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L258) `Initiates a scan for all known barcode types with the default camera.` ```java=1 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); } } ``` * 第 1 行,[`initiateScan()`](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L258),用來啟動掃描Activity,可以寫在 onClick() 或是 onCreate() 等等method裡面 * 第 3-16行,[`onActictyResult()`](https://developer.android.com/reference/android/app/Activity#onActivityResult(int,%20int,%20android.content.Intent)),目的是取得掃描Activity傳回來的結果,不需要動這部分,直接貼到 **MainActivity.java** 即可 :::warning 有關*啟動 Activity 以取得結果*,之後會再介紹 ::: * result.getContents() 為結果,如果打算顯示掃描結果,複製結果,開啟URL,便需要利用此結果 ### Customize options * 此為其他客製化功能,和 [`initiateScan()`](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L258)一樣,寫在 onClick() 或是 onCreate() 等等method裡面 ```java=1 IntentIntegrator integrator = new IntentIntegrator(this); integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE); integrator.setPrompt("Scan a QR code"); integrator.setCameraId(0); // Use a specific camera of the device integrator.setBeepEnabled(false); integrator.setBarcodeImageEnabled(true); integrator.initiateScan(); ``` ### Changing the orientation 1. 開啟 **AndroidManifest.xml**,加入以下code ```xml=1 <activity android:name="com.journeyapps.barcodescanner.CaptureActivity" android:screenOrientation="fullSensor" tools:replace="screenOrientation" /> ``` ![](https://i.imgur.com/6n7RvwW.png) 2. [`setOrientationLocked()`](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L179) set false to not lock,和 [`initiateScan()`](https://github.com/journeyapps/zxing-android-embedded/blob/6556f815584f921e21bb088d2f6423baa99d0547/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java#L258)寫在一起 ```java= IntentIntegrator integrator = new IntentIntegrator(this); integrator.setOrientationLocked(false); integrator.initiateScan(); ``` ## Button and Text display 1. layout 如下所示 ![](https://i.imgur.com/4WTOU8k.png) 2. 在 **MainActivity.java** 寫一個 onClick() method,裡面放剛剛的那些code ```java=1 public void onClick(View view){ IntentIntegrator integrator = new IntentIntegrator(this); integrator.setOrientationLocked(false); integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE); integrator.setPrompt("Scan a QR code"); integrator.setCameraId(0); // Use a specific camera of the device integrator.setBeepEnabled(false); integrator.setBarcodeImageEnabled(true); integrator.initiateScan(); } ``` 3. 在 [`onActictyResult()`](https://developer.android.com/reference/android/app/Activity#onActivityResult(int,%20int,%20android.content.Intent))裡面加入第 4 行和第 12 行,用 [`TextView`](https://developer.android.com/reference/android/widget/TextView)顯示結果 ```java=1 // Get the results: @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { TextView textView = findViewById(R.id.textView); 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(); textView.setText(result.getContents()); } } else { super.onActivityResult(requestCode, resultCode, data); } } ``` 4. 把 onClick() 設置到 button 上 :::success Done!!! ::: ![](https://i.imgur.com/8yNv0o9.png =270x480) ![](https://i.imgur.com/GVmwK1V.png =270x480) ## Reference * [Github | Zxing](https://github.com/journeyapps/zxing-android-embedded) * [Github | IntentIntegrator.java](https://github.com/journeyapps/zxing-android-embedded/blob/master/zxing-android-embedded/src/com/google/zxing/integration/android/IntentIntegrator.java) * [Useful Reference](http://lmgtfy.com/?q=Android+QR+code) ## Future feature * Scan a photo * [Copy to clipboard](https://developer.android.com/guide/topics/text/copy-paste#java) * Open the URL link ## Homepage * [Homepage](/@NDR/Homepage) *[SDK]: Software Development Kit *[URL]: Uniform Resource Locator