为什么浏览器能扫入,Flutter 输入框不行
PDA 扫码头按下 → 扫码 → 发广播 (Broadcast)
↓
浏览器内有一个 EditText(原生组件)
Android 系统自动把广播中的条码
填入当前获得焦点的原生输入框
↓
用户看到条码出现在地址栏 ✓PDA 扫码头按下 → 扫码 → 发广播 (Broadcast)
↓
Flutter 的 TextField 不是原生 EditText
它通过 TextInputConnection 模拟输入
系统广播机制找不到"原生输入框"来填入
↓
条码数据无处可去 ✗核心区别:
| 浏览器输入框 | Flutter TextField | |
|---|---|---|
| 本质 | Android 原生EditText | Flutter 自绘组件 +TextInputConnection模拟 |
| 系统能否自动填入 | 能,系统认识EditText | 不能,系统不认识 Flutter 的模拟输入框 |
键盘事件(KeyEvent) | 能收到 | 收不到(unicode=0, chars=null) |
广播(Broadcast) | 厂商做了自动填入适配 | Flutter 层没有这个机制 |
最终方案:原生层注册 BroadcastReceiver
PDA 扫码头按下 → 扫码 → 发广播 (Broadcast)
↓
MainActivity 中注册的 BroadcastReceiver 收到广播
从 Intent extra 中提取条码字符串
↓
通过 EventChannel 发送给 Flutter
↓
Flutter 的 listen 回调收到条码
调用 onCodeScanned(code)
显示"已识别" ✓关键代码位置
// 1. 定义广播 Action 和条码 Key
private val SCAN_ACTIONS = listOf(
"nlscan.action.SCANNER_RESULT", // 新大陆
"android.intent.ACTION_DECODE_DATA", // 通用/优博讯
"com.android.server.scannerservice.broadcast",
"android.server.scanner.broadcast",
)
private val SCAN_BARCODE_KEYS = listOf(
"SCAN_BARCODE1", "barcode_string", "barcode",
"scannerdata", "scanner_data", "data",
)
// 2. 注册广播接收器
private fun registerScanReceiver() {
scanReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
// 从 Intent extra 中遍历各个 key 取条码
// 通过 eventSink 发送给 Flutter
}
}
val filter = IntentFilter()
for (action in SCAN_ACTIONS) { filter.addAction(action) }
registerReceiver(scanReceiver, filter, Context.RECEIVER_EXPORTED)
}
// 3. 在 configureFlutterEngine 中注册 EventChannel + 调用 registerScanReceiver()Flutter 侧(BarcodeScannerCard):
// 1. 订阅原生层推送的扫码数据
_pdaSubscription = EventChannel('com.zkzl.hazardouswaste/pda_scanner')
.receiveBroadcastStream()
.cast<String>()
.listen((code) {
widget.onCodeScanned(code);
_showRecognizedIndicator();
});为什么键盘事件方案行不通
keyCode=142, unicode=0, chars=nullPDA 扫码头发出的不是标准字符,而是原始扫描码。Android 原生层有厂商预装的驱动把这个扫描码转成条码字符串,但转换结果不走 KeyEvent 系统,而是走广播。所以 dispatchKeyEvent 拿到的永远是"空壳"按键。