为什么浏览器能扫入,Flutter 输入框不行

PDA 扫码头按下 → 扫码 → 发广播 (Broadcast)
                         ↓
              浏览器内有一个 EditText(原生组件)
              Android 系统自动把广播中的条码
              填入当前获得焦点的原生输入框
                         ↓
              用户看到条码出现在地址栏 ✓
PDA 扫码头按下 → 扫码 → 发广播 (Broadcast)
                         ↓
              Flutter 的 TextField 不是原生 EditText
              它通过 TextInputConnection 模拟输入
              系统广播机制找不到"原生输入框"来填入
                         ↓
              条码数据无处可去 ✗

核心区别:

浏览器输入框Flutter TextField
本质Android 原生EditTextFlutter 自绘组件 +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=null

PDA 扫码头发出的不是标准字符,而是​原始扫描码​。Android 原生层有厂商预装的驱动把这个扫描码转成条码字符串,但转换结果​不走 KeyEvent 系统​,而是走广播。所以 dispatchKeyEvent 拿到的永远是"空壳"按键。

最后修改:2026 年 08 月 20 日
如果觉得我的文章对你有用,请随意赞赏