Androidアプリの開発者であってもほとんどの人には関係がないが、自分的には大いに関わりがあって一部の人にも難問に感じることかもしれないので記事にしておこうと思う。
世の中には倉庫や配送業を主なターゲットとしたビジネス用携帯端末が存在する。宅配便のドライバーが荷物を集荷や配達に来た時、バーコードリーダーでピッピッピッと伝票のバーコードを読んでいるのを見たことがないだろうか? あんな感じの端末である。「PDA」や「ハンディターミナル」と呼ばれているが、ここではとりあえず「PDA」としておこう。
PDAに搭載されているOSは、メーカー独自のものか、「Windows Embedded Compact」という組み込み用Windowsがほとんどだった。どちらも設計が古く、開発ツールも対応OSがWindows7止まりだったりする。Windows Embedded CompactなんてMicrosoftがサポートを終了してしまっている。それでも「Windows Embedded Compactの開発する場合どんなツールが必要か?」とメーカーの担当者に訊いたら「Visual Studio 2005」という答えが返ってきた。10年以上前のVSかよ! 当然ながらVS2005なんてもはや販売されていない。Microsoftのサブスクリプションを買えば古いバージョンもダウンロードができると担当者が言っていたけど、そんなもんダウンロードできないぞ。仕事で使う端末は一度買うと5年10年と壊れるまで使い続けていくものである。10年後にアプリをアップデートしたくなってもVS2005が必須かよ! 2028年でもVS2005かよ!
そんな中、一部のメーカーからAndroid OSを搭載したPDAが発売された。
自分が関わっているのはデンソーウェーブのBHT-1600という製品で、Android6.0搭載のPDAだ。バーコードリーダーとごっついプロテクタが付いているが、中身はAndroidスマホとほぼ同じ。Android6.0は今となってはやや古くなってきているものの、Androidはその気になれば今でも滅茶苦茶古いバージョンに対応したアプリを作ることができるので、開発環境に対する懸念もない。
BHT-1600のアプリ開発をするうえで、普通のスマホと違うのはやはりバーコードリーダーの制御の部分だろう。参考資料がSDKに付いてくるサンプルプログラムしかないので大変だ。
そんなわけで自分がちょっと躓いたところを書いて忘れないようにしておこうと思う。
バーコードリーダー制御の基本
BHT-1600のバーコードリーダーを扱うにはReaderManegerクラスのインスタンスを作成し、それを通じて設定を変更したり、バーコード読み取りを実行したりする。ReaderManagerはコンストラクタ経由でインスタンス化するのではなくstaticなメソッドInitInstance()を呼び出して取得する。
readerManager = ReaderManager.InitInstance(this);
バーコードをスキャンした時のイベントを拾うためにBroadcastReceiverにIntentFilterを登録。
ifilter = new IntentFilter();
ifilter.addAction(GeneralString.Intent_SOFTTRIGGER_DATA); //ソフトウェアトリガーでスキャンした時のイベント
ifilter.addAction(GeneralString.Intent_PASS_TO_APP); //ハードウェアトリガーでスキャンした時のイベント
registerReceiver(bcReceiver, ifilter);
もちろんイベントを受信したときの処理も登録しておく
private final BroadcastReceiver bcReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(GeneralString.Intent_SOFTTRIGGER_DATA) ||
action.equals(GeneralString.Intent_PASS_TO_APP)) {
//スキャンデータの取得
String scanData = intent.getStringExtra(GeneralString.BcReaderData) ;
textView.setText(scanData.trim()); //テキストボックスに表示
}
}
} ;
これで、ハードウェアキーや
readerManager.SoftScanTrigger(); //ソフトウェアキーでスキャン
という具合にソフトウェアキーでスキャンを実行すればOKなのだが、ひとつ注意点がある。
バーコードリーダーの設定を変更しようとすると例外が発生する
ReaderManagerのインスタンスを作成した直後に設定を読みだしたり変更しようとすると例外が発生する。
以下のコードはReaderManagerのインスタンスを取得した後にバーコードリーダーの設定を変更するプログラムなのだが、3行目でエラーになってしまう。
readerManager = ReaderManager.InitInstance(this);
ReaderOutputConfiguration config = new ReaderOutputConfiguration();
if (readerManager.Get_ReaderOutputConfiguration(config) == ClResult.S_OK) {
config.szCharsetName = "Shift_JIS";
config.enableKeyboardEmulation = KeyboardEmulationType.None;
readerManager.Set_ReaderOutputConfiguration(config);
}
何故かというとif文の中のreaderManager.Get_ReaderOutputConfiguration(config) の結果がnullになるためだ。
ぬるぽおおお!!文法間違ってないのにどうしてえええ?!読み取ったデータをシフトJISで受け取りたいのにどうしたらいいんだあああ!!
と私は頭を抱えた。
これはReaderManagerのインスタンスを作った直後はまだバーコードリーダーとの接続が確立されていないためらしい。設定の読込みや変更は接続が確立されてからしなければならないのだが、どうやってそのタイミングを知るのかというと、BroadcastReceiverでGeneralString.Intent_READERSERVICE_CONNECTEDを拾ってやればよい。そしてそのイベント処理の中で設定の変更処理を行うのである。
つまりIntenFilterにGeneralString.Intent_READERSERVICE_CONNECTEDも追加。
BroadcastReceiverに登録し、
ifilter = new IntentFilter();
ifilter.addAction(GeneralString.Intent_SOFTTRIGGER_DATA); //ソフトウェアトリガーでスキャンした時のイベント
ifilter.addAction(GeneralString.Intent_PASS_TO_APP); //ハードウェアトリガーでスキャンした時のイベント
ifilter.addAction(GeneralString.Intent_READERSERVICE_CONNECTED); //バーコードリーダーとの接続が確立したときのイベント
registerReceiver(bcReceiver, ifilter);
readerManager = ReaderManager.InitInstance(this);
レシーバーの中で設定を変更する
private final BroadcastReceiver bcReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(GeneralString.Intent_SOFTTRIGGER_DATA) ||
action.equals(GeneralString.Intent_PASS_TO_APP)) {
//スキャンデータの取得
String scanData = intent.getStringExtra(GeneralString.BcReaderData) ;
textView.setText(scanData.trim()); //テキストボックスに表示
} else if (action.equals(GeneralString.Intent_READERSERVICE_CONNECTED)) {
//スキャナーとの接続が確立されたときの処理
ReaderOutputConfiguration config = new ReaderOutputConfiguration();
if (readerManager.Get_ReaderOutputConfiguration(config)== ClResult.S_OK) {
config.szCharsetName = "Shift_JIS"; //文字コードをシフトJISに
config.enableKeyboardEmulation = KeyboardEmulationType.None; //キーボードエミュレーションなし
readerManager.Set_ReaderOutputConfiguration(config); //設定登録
}
}
}
} ;
まあ、ここに書いたことは、SDK付属のサンプルプログラムをよーく読むとすぐにわかるんだけどね。特殊な機器は資料が少ないから上手くいかないと途方に暮れてしまう。私のように資料は流し読みしてとりあえずコーディングを始めてしまう人は要注意だ。
【新品】DENSO/4.7型タブレット/Android/無線LAN/BHT-1600QWB-A6N-S
|