初老のボケ防止日記

おっさんのひとりごとだから気にしないようにな。

「ZXing Android Embedded」でQRコードを気楽に使う

AndroidでQRコードの読み書きをやることになったんだけど、実は今までやったことがなかったのだ。

AndroidでのQRコード読み書き自体はもう色んな情報がネットにあふれており、Zxingを使えばいいというのはわかっていた。

github.com


でも、この手の情報は比較的初期に書かれていて、もう少し最新情報でやれないかなと調べていたらこんなものを発見。

github.com

既にいくつか使った紹介記事もあったんだけど、

Android - ZXingで、QRコードを撮れる - Qiita
Android StudioでZXingを使う。 - ちょこっと、めも。

少し違う内容が書けそうなので記事にした。

使ってみよう

環境

OS Windows 10 pro
Java 1.8.0
Android Studio 1.2.2

プロジェクトへのライブラリの追加

以下を追加するだけ。

  • app/build.gradle
repositories {
    jcenter()
}

dependencies {
    compile 'com.journeyapps:zxing-android-embedded:3.0.2@aar'
    compile 'com.google.zxing:core:3.2.0'
}

QRコードを生成する

QRコードの生成自体はzxingライブラリだけでもできるんだけど、ヘルパークラスが用意されているのでそれを使ってみる。

QrCodeDisplayActivity

package com.hatenablog.osa030.qrtest;

import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.AndroidRuntimeException;
import android.widget.ImageView;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.journeyapps.barcodescanner.BarcodeEncoder;

public class QrCodeDisplayActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_qr_code_display);

        String data = "http://osa030.hatenablog.com/";
        int size = 500;
        try {
            BarcodeEncoder barcodeEncoder = new BarcodeEncoder();
            Bitmap bitmap = barcodeEncoder.encodeBitmap(data, BarcodeFormat.QR_CODE, size, size);

            ImageView imageView = (ImageView) findViewById(R.id.imageView);
            imageView.setImageBitmap(bitmap);

        } catch (WriterException e) {
            throw new AndroidRuntimeException("Barcode Error.", e);
        }

    }
}

activity_qr_code_display.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:paddingLeft="@dimen/activity_horizontal_margin"
                android:paddingRight="@dimen/activity_horizontal_margin"
                android:paddingTop="@dimen/activity_vertical_margin"
                android:paddingBottom="@dimen/activity_vertical_margin"
                tools:context=".QrCodeDisplayActivity">

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical"
        android:layout_alignParentStart="true">

        <TextView
            android:text="@string/hello_world"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/textView"/>

        <Space
            android:layout_width="match_parent"
            android:layout_height="100dp"/>

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/imageView"
            android:layout_gravity="center"/>

    </LinearLayout>

</RelativeLayout>

実行するとこんな感じでQRコードが表示される。

f:id:osa030:20151014124204j:plain

ヘルパークラスにはzxingへのヒントオプションも渡せる。

            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
            BarcodeEncoder barcodeEncoder = new BarcodeEncoder();
            Bitmap bitmap = barcodeEncoder.encodeBitmap(data, BarcodeFormat.QR_CODE, size, size, hints);

QRコードを読み込む

「ZXing Android Embedded」で一番助かるのはQRコード読み込む手段が用意されているところ。

  1. Activityを起動してQRコードを読み込む
  2. カスタムViewを埋め込んでQRコードを読み込む

どちらの場合もカメラの権限が必要になるのだが、ライブラリ(aar)のAndroidManifest.xmlに以下が追記されており、ビルド時にマージされるのでアプリ側のAndroidManifest.xmlに追記しなくても動作はする。はず。はずだってば。もししなかったら以下を追記。

AndroidManifest.xml

    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.FLASHLIGHT"/>

ここで、「Activityを起動してQRコードを読み込む」はインテントの送受信だけなので公式の「Usage with IntentIntegrator」を見れば大体わかると思うので省略。ということで、自分のActivityにライブラリで提供されるカスタムViewを埋め込んだ場合のサンプルだけ。

QrCodeReadInViewActivity.java

package com.hatenablog.osa030.qrtest;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import com.google.zxing.ResultPoint;
import com.journeyapps.barcodescanner.BarcodeCallback;
import com.journeyapps.barcodescanner.BarcodeResult;
import com.journeyapps.barcodescanner.CompoundBarcodeView;

import java.util.List;

public class QrCodeReadInViewActivity extends AppCompatActivity {

    private CompoundBarcodeView mBarcodeView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_qr_code_read_in_view);

        mBarcodeView = (CompoundBarcodeView)findViewById(R.id.barcodeView);
        mBarcodeView.decodeSingle(new BarcodeCallback() {
            @Override
            public void barcodeResult(BarcodeResult barcodeResult) {

                TextView textView = (TextView)findViewById(R.id.textView);
                textView.setText(barcodeResult.getText());
            }

            @Override
            public void possibleResultPoints(List<ResultPoint> list) {}
        });
    }

    @Override
    public void onResume() {
        super.onResume();
        mBarcodeView.resume();
    }

    @Override
    public void onPause() {
        super.onPause();
        mBarcodeView.pause();
    }
}

activity_qr_code_read_in_view.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:paddingLeft="@dimen/activity_horizontal_margin"
                android:paddingRight="@dimen/activity_horizontal_margin"
                android:paddingTop="@dimen/activity_vertical_margin"
                android:paddingBottom="@dimen/activity_vertical_margin"
                tools:context="com.hatenablog.osa030.qrtest.QrCodeReadInViewActivity">

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical"
        android:layout_alignParentStart="true"
        android:id="@+id/qrReaderLayout">

        <TextView
            android:text="@string/hello_world"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/textView"/>

        <Space
            android:layout_width="match_parent"
            android:layout_height="100dp"/>

        <com.journeyapps.barcodescanner.CompoundBarcodeView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/barcodeView"/>
    </LinearLayout>
    
</RelativeLayout>

実行するとこんな感じでカメラが起動してQRコードを読み取れる。

f:id:osa030:20151014125412j:plain

f:id:osa030:20151014125418j:plain

Viewを埋め込む場合はCompoundBarcodeViewクラスを使えばよい。ポイントは、ActivityのonResume()/onPause()でCompoundBarcodeViewのresume()/pause()を呼んでやるだけ。これをしないとdecodeSingle()をコールしても真っ黒な画面にしかならない。

実際には「Activityを起動してQRコードを読み込む」で起動されるCaptureActivityクラスも内部でCompoundBarcodeViewクラスを使っているんだけども、CompoundBarcodeViewへの細かいデコードオプション指定は今のところIntent経由じゃないとできない*1

IntentIntegrator
CaptureActivity
CompoundBarcodeView

よくわかるバーコード・二次元シンボル

よくわかるバーコード・二次元シンボル

  • 作者: 社団法人日本自動認識システム協会
  • 出版社/メーカー: オーム社
  • 発売日: 2010/05/19
  • メディア: 単行本(ソフトカバー)
  • クリック: 16回
  • この商品を含むブログを見る
符号理論入門―数学的な基礎知識から「QRコード」の作成まで (I・O BOOKS)

符号理論入門―数学的な基礎知識から「QRコード」の作成まで (I・O BOOKS)

*1:正確にはinitializeFromIntent()にIntentに詰めて渡してやればいいと思われる