1. はじめに
経緯
現在参画中のプロジェクトでスマホ向けアプリを開発しています。
個人情報をフォームに入力して送信すると、
DBにデータがインサートされるという比較的シンプルな構成のものです。
ところが、アプリの結合テスト段階で、思わぬ落とし穴にハマりました。
「実装は問題なさそうなのに、なぜかバーコードが読めない」状態が続き、かなりの時間を溶かしました…。
どこかの誰かが同じ轍を踏まないよう、備忘録として残します。
結論(先に一言だけ)
プログラムのバグではありませんでした。
原因は、テストデータとして用意した Excel で生成した Code39 のバーコードでした。
2. 実装
目的
スマホ向けアプリにおいて、フォームのテキスト入力項目に対し、
スマホのカメラを使用してバーコードを読み取り、
取得した値をテキスト欄へ自動入力できるようにする。
実装概要
本記事ではバーコード読み取り自体の実装詳細には踏み込みません。
フロントエンドは React + TypeScript で実装。
バーコードの読み取りには ZXing(@zxing/browser)を使用。
UI には MUI(Material UI)を使用。
カメラ起動は Dialog 上に video 要素を表示する構成。
読み取り対象のバーコード形式は DecodeHintType.POSSIBLE_FORMATS を用いて Code39 に限定。
ざっくりとした流れ
- カメラアイコン押下でスキャナーダイアログを表示
- ZXing の BrowserMultiFormatReader で背面カメラを起動
- 読み取り成功時にコード文字列を取得
- 形式チェック後、フォームのテキスト欄に反映
- 読み取り完了後はスキャナーを停止
使用ライブラリ
- @zxing/browser … Web カメラを使ったバーコード読み取り用ライブラリ
- @zxing/library … DecodeHintType などの設定に使用
バーコードの値は英数字という要件のもと Code39 を含む複数形式を扱える点から ZXing を選択しました。
3. 原因
なぜ特定に時間が掛かったか
本来であれば Android Studio のエミュレーターを使って実装段階から検証を進めたかったのですが、開発環境がある顧客先の社内ネットワークの認証プロキシの制約により SDK がインストールできず、今回は断念。
そのため、「自分の実装が正しいとは限らない」という前提が常に頭にありました。
※Android Studio の環境構築で詰まった話は、以前別の記事にまとめています
そして、今回の結合テストでは当初テスト用に用意されていた実機が iPhone と iPad のみでした。
さらに厄介だったのが、デバッグ用の PC が手元になかったことです。
そのため Safari の開発者ツールを使ったコンソールログの確認ができず、
- ZXing が何を検出しているのか
- どの段階で失敗しているのか
- そもそも decode が呼ばれているのか
といった情報が分かりませんでした。
手探りのデバッグになり、読み取り部分の実装に alert を仕込んで
「どこまで処理が進んでいるか」を少しずつ確認するしかありませんでした。
ただし、
- 読み取り結果の中身
- 失敗理由
- フォーマット判定の詳細
といった細かい情報までは追えず、決定的な原因特定には至りませんでした。
読めない…何を疑ったか
真っ先に疑ったのは次の点です。
- カメラ権限の問題?
- iPhone / Safari 固有の挙動?
- ZXing の設定?
- 端末依存?
- 解像度やピント?
「実装や環境側に原因があるはずだ」という前提のもと、次のような対応を試しました。
- facingMode の指定方法を変える
- decodeFromConstraints を使う
- Dialog の開閉タイミングを調整する
- DecodeHintType.TRY_HARDER で読み取り精度を上げる
- muted や playsInline を追加しカメラを安定して起動させる
- DecodeHintType.POSSIBLE_FORMATS を削除して読み取り対象を拡大
など、それっぽい修正を色々と盛っていきました。
しかし結果は変わらず、バーコードは一向に読み取れませんでした。
どれも一般的には間違っていない対応です。
ただし今回の問題に対しては、本質ではありませんでした。
結果として、肝心の「バーコードが読めない」問題は解決せず、
コードだけが少しずつ複雑になっていきました。
「実装としては正しくなっていくのに、問題は解決しない」という、つらいパターン…
もしやバーコードのせいでは…?
ふと、「もしかしてバーコード自体が悪いのでは…?」という疑念が頭をよぎりました。
今回の現場では、セキュリティの懸念から自己判断で Web 上のバーコード生成サイトの利用を避け、Excel で Code39 のバーコードを作成していました。
正直なところ、用意した時点で一抹の不安はありました。
試しに、Web 上で公開されている ZXing 製のバーコードリーダーのデモで、自分が用意したバーコードを恐る恐る読み取ってみると……何も反応しません。
ならば、と Web のバーコード生成サイトで Code39 のバーコードを作成。
デモのバーコードリーダーで読み取る。
⇒ 成功
同じバーコードを、自分の実装で読み取ってみる。
⇒ 成功
この時点で、「実装ではなく、Excel で作成したバーコードが原因」であることが確定しました。
なお、この時までZXing の公式デモが存在すること自体を知りませんでした。
お恥ずかしい。
なぜ Excel の Code39 だと読み取れないのか
残念ながら、Excel で生成した Code39 がなぜ ZXing で読み取れなかったのかについて、
仕様レベルでの明確な原因までは突き止められていません。
Excel では、セルに文字列を入力し、フォントを CODE_39 に指定するだけで、一見それっぽいバーコードが生成されます。
しかしこの方法では、
- セル幅や行高の変更
- 拡大・縮小
- 印刷倍率の影響
などにより、バーコードの縦横比やバー幅の比率を作り手が自由に変えられてしまいます。
バーコードは単なる画像ではなく、黒と白の幅の比率で情報を表現する「信号」です。
そのため、これらの比率が崩れると、見た目が正しそうでも読み取れなくなる可能性があります。
今回のケースでも、見た目上は問題なさそうに見えるバーコードであっても、ZXing では一切反応しない、という結果になりました。
以上の点から、テストデータとして Excel で生成したバーコードを使用することは、私はおすすめしません。
なお、もし本件についてより詳細な原因や仕様をご存じの方がいらっしゃいましたら、コメントでご教授いただけますと幸いです。
余談
ちなみに、ご存じの方も多いと思いますが、Code39 では開始・終了文字として *(アスタリスク)を前後に付ける必要があります。
ですが、Excel でバーコードを作成する場合、この * は 自動では付与されません。
そのため、以下のように手動で付ける必要があります。
※ アスタリスクが付いていても読み取りはできませんでした。
4. まとめ・反省
今回の学びをまとめると、以下の通りです。
-
「実装が正しいか分からない」という前提があると、 問題の切り分けが難しくなり、調査が迷走しやすい(実装を疑い続けるバイアスが掛かった)
-
デバッグ環境がないと、原因を一段深く誤認しやすい
(ログやデバッグ手段が限られていると、「動かない理由」を実装側に寄せて考えてしまいがち) -
Excel で作成したバーコードは、仕様的に信用しすぎない
-
作成したバーコードが読み取れるかは、使用しているライブラリと同系統の Web 上のデモで事前に検証すべき
今回の落とし穴は、「見た目は正しそうでも、読み取れない Code39 が存在する」 という点でした。
バーコードに限らず、「入力データ」や「テストデータ」を疑う視点は、
他の機能開発でも同じように重要だと感じました。
「実装は合っているはずなのに動かない」 と悩んでいる方の、原因切り分けのヒントになれば幸いです。

