You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native 0.68.2如何无需聚焦TextInput捕获物理扫码器输入?

实现 React Native 0.68.2 监听内置物理扫码器事件(无需可见 TextInput)

大部分内置手持物理扫码器会将扫描结果模拟为键盘输入流(快速输入一串字符,通常以换行符\n结尾)。基于这个特性,我们可以通过跨平台的监听方案实现需求,无需聚焦可见输入框:


Android 端:全局按键事件监听

Android 支持直接捕获全局按键事件,无需依赖输入框。可以借助react-native-keyevent库实现:

1. 依赖安装与配置

npm install react-native-keyevent --save

在android/app/src/main/java/[你的包名]/MainActivity.java中添加按键事件转发逻辑:

import com.github.kevinejohn.keyevent.KeyEventModule;
import android.view.KeyEvent;

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    KeyEventModule.getInstance().onKeyDownEvent(keyCode, event);
    return super.onKeyDown(keyCode, event);
}

2. RN 代码实现

import React, { useState, useEffect } from 'react';
import { View, Text, Platform } from 'react-native';
import KeyEvent from 'react-native-keyevent';

const ScannerHandler = () => {
  const [scannedResult, setScannedResult] = useState('');
  let currentInput = '';

  useEffect(() => {
    if (Platform.OS !== 'android') return;

    // 注册按键按下监听
    KeyEvent.onKeyDownListener((event) => {
      const keyCode = event.keyCode;
      let char = '';

      // 映射常见按键码到对应字符,可根据扫码器输出补充
      const keyMap = {
        7: '0', 8: '1', 9: '2', 10: '3', 11: '4', 12: '5', 13: '6', 14: '7', 15: '8', 16: '9',
        29: 'a', 30: 'b', 31: 'c', 32: 'd', 33: 'e', 34: 'f', 35: 'g', 36: 'h', 37: 'i',
        38: 'j', 39: 'k', 40: 'l', 41: 'm', 42: 'n', 43: 'o', 44: 'p', 45: 'q', 46: 'r',
        47: 's', 48: 't', 49: 'u', 50: 'v', 51: 'w', 52: 'x', 53: 'y', 54: 'z',
        56: '-', 57: '=', 61: ';', 63: ',', 64: '.'
      };

      if (keyCode in keyMap) {
        char = keyMap[keyCode];
        // 处理大写(Shift键按下时)
        if (event.metaState & KeyEvent.META_SHIFT_ON) {
          char = char.toUpperCase();
        }
      } else if (keyCode === 66) { // 回车键(扫码器通常以此结尾)
        if (currentInput.length > 0) {
          setScannedResult(currentInput);
          currentInput = '';
        }
        return;
      }

      if (char) currentInput += char;
    });

    // 组件卸载时移除监听
    return () => KeyEvent.removeKeyDownListener();
  }, []);

  return (
    <View>
      <Text>扫描结果:{scannedResult}</Text>
    </View>
  );
};

export default ScannerHandler;

iOS 端:隐藏 TextInput 捕获输入

iOS 不支持全局键盘事件监听,可通过隐藏的自动聚焦 TextInput捕获扫码输入:

import React, { useState, useRef } from 'react';
import { View, Text, TextInput, Platform } from 'react-native';

const ScannerHandler = () => {
  const [scannedResult, setScannedResult] = useState('');
  const hiddenInputRef = useRef(null);

  const handleScanComplete = (text) => {
    const cleanText = text.replace('\n', '').trim();
    if (cleanText) {
      setScannedResult(cleanText);
      hiddenInputRef.current?.clear();
    }
  };

  return (
    <View>
      <Text>扫描结果:{scannedResult}</Text>
      {Platform.OS === 'ios' && (
        <TextInput
          ref={hiddenInputRef}
          autoFocus={true}
          style={{ position: 'absolute', opacity: 0, height: 0, width: 0 }}
          onSubmitEditing={(e) => handleScanComplete(e.nativeEvent.text)}
          onChangeText={(text) => {
            if (text.includes('\n')) handleScanComplete(text);
          }}
        />
      )}
    </View>
  );
};

export default ScannerHandler;

跨平台整合版本

将两端逻辑合并,实现一套代码兼容双平台:

import React, { useState, useEffect, useRef } from 'react';
import { View, Text, TextInput, Platform } from 'react-native';
import KeyEvent from 'react-native-keyevent';

const ScannerHandler = () => {
  const [scannedResult, setScannedResult] = useState('');
  const hiddenInputRef = useRef(null);
  let currentAndroidInput = '';

  // Android 按键监听
  useEffect(() => {
    if (Platform.OS !== 'android') return;

    KeyEvent.onKeyDownListener((event) => {
      const keyCode = event.keyCode;
      let char = '';

      const keyMap = {
        7: '0', 8: '1', 9: '2', 10: '3', 11: '4', 12: '5', 13: '6', 14: '7', 15: '8', 16: '9',
        29: 'a', 30: 'b', 31: 'c', 32: 'd', 33: 'e', 34: 'f', 35: 'g', 36: 'h', 37: 'i',
        38: 'j', 39: 'k', 40: 'l', 41: 'm', 42: 'n', 43: 'o', 44: 'p', 45: 'q', 46: 'r',
        47: 's', 48: 't', 49: 'u', 50: 'v', 51: 'w', 52: 'x', 53: 'y', 54: 'z',
        56: '-', 57: '=', 61: ';', 63: ',', 64: '.'
      };

      if (keyCode in keyMap) {
        char = keyMap[keyCode];
        if (event.metaState & KeyEvent.META_SHIFT_ON) char = char.toUpperCase();
      } else if (keyCode === 66) {
        if (currentAndroidInput.length > 0) {
          setScannedResult(currentAndroidInput);
          currentAndroidInput = '';
        }
        return;
      }

      if (char) currentAndroidInput += char;
    });

    return () => KeyEvent.removeKeyDownListener();
  }, []);

  // iOS 输入处理
  const handleIOSScan = (text) => {
    const cleanText = text.replace('\n', '').trim();
    if (cleanText) {
      setScannedResult(cleanText);
      hiddenInputRef.current?.clear();
    }
  };

  return (
    <View>
      <Text>扫描结果:{scannedResult}</Text>
      {Platform.OS === 'ios' && (
        <TextInput
          ref={hiddenInputRef}
          autoFocus={true}
          style={{ position: 'absolute', opacity: 0, height: 0, width: 0 }}
          onSubmitEditing={(e) => handleIOSScan(e.nativeEvent.text)}
          onChangeText={(text) => text.includes('\n') && handleIOSScan(text)}
        />
      )}
    </View>
  );
};

export default ScannerHandler;

注意事项

  1. 部分扫码器可配置输出后缀(如是否带换行符),建议设置为带换行符,便于判断扫码结束。
  2. Android 端的按键码映射需根据实际扫码器输出调整,可通过打印event对象查看具体参数。
  3. iOS 端的隐藏输入框不会影响页面布局,opacity:0和宽高0确保完全不可见。

内容的提问来源于stack exchange,提问作者holydragon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 10:15:33