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

Expo Go正常的React Native扫码APP在Android真机打包后无法识别QR码求助

React Native扫码APP打包后无法识别QR码问题

问题描述

使用React Native开发的QR码扫码APP,在Expo Go中测试完全正常,首次尝试即可成功扫码。但通过eas build -p android --profile preview命令打包安装到Android真机后,APP能正常打开并显示相机画面,但对准QR码时无任何响应,且无法查看真机日志,附上相关代码寻求解决办法。

可能的解决方案

1. 补充权限配置

Expo Go会自动处理部分权限逻辑,但EAS打包的独立APP需要在app.json或app.config.js中明确声明相机权限。检查配置文件,确保添加安卓相机权限:

"android": {
  "permissions": ["CAMERA"]
}

2. 明确指定条码识别格式

独立构建环境中,Expo Camera默认可能未启用所有条码格式。可以在Camera组件中添加barCodeScannerSettings属性,明确指定只识别QR码:

<Camera
  onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
  style={styles.preview}
  barCodeScannerSettings={{
    barCodeTypes: [Camera.Constants.BarCodeType.qr],
  }}
/>

3. 避免异步回调阻塞扫码逻辑

handleBarCodeScanned作为异步函数,扫码后立刻发起网络请求可能阻塞主线程,影响扫码识别。建议将网络请求逻辑移到useEffect中,分离扫码回调与业务操作:

const handleBarCodeScanned = ({ data }) => {
  console.log('扫描到条码:', data);
  setScanned(true);
  setScannedData(`数据: ${data}`);
};

useEffect(() => {
  if (scanned && scannedData) {
    const fetchServerData = async () => {
      try {
        const response = await fetch('https://www.chesifastasera.com/handleQR.php', {
          method: 'POST',
          headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({ qrData: scannedData.replace('数据: ', '') }),
        });

        if (!response.ok) {
          throw new Error(`HTTP错误!状态码: ${response.status}`);
        }

        const responseData = await response.text();
        setServerResponse(responseData);
      } catch (error) {
        setError(error.message);
      }
    };
    fetchServerData();
  }
}, [scanned, scannedData]);

4. 禁用ProGuard混淆或添加规则

EAS打包安卓APP默认可能开启ProGuard,可能混淆Expo Camera的扫码相关代码。可以在android/app/proguard-rules.pro中添加保护规则:

-keep class expo.modules.camera.** { *; }
-keep class com.google.android.gms.** { *; }

相关代码(已翻译中文注释)

import React, { useState, useEffect } from 'react';
import { View, StyleSheet, Button, Text, Alert } from 'react-native';
import { Camera } from 'expo-camera';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    justifyContent: 'flex-end',
  },
  preview: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  scanText: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
    color: 'red', // 错误文本用红色
  },
  qrFrame: {
    width: 150,
    height: 150,
    borderRadius: 10,
    borderColor: '#FFF',
    borderWidth: 2,
    position: 'absolute',
    justifyContent: 'center',
    alignItems: 'center',
  },
  qrCodeText: {
    fontSize: 16,
    textAlign: 'center',
    color: '#FFF',
  },
});

export default function App() {
  const [hasCameraPermission, setHasCameraPermission] = useState(null);
  const [scanned, setScanned] = useState(false);
  const [scannedData, setScannedData] = useState('');
  const [serverResponse, setServerResponse] = useState('');
  const [error, setError] = useState(null);

  useEffect(() => {
    (async () => {
      try {
        const { status } = await Camera.requestCameraPermissionsAsync();
        if (status !== 'granted') {
          throw new Error('相机权限被拒绝');
        }
        setHasCameraPermission(true);
      } catch (error) {
        console.error('请求相机权限时出错:', error.message);
        setHasCameraPermission(false);
      }
    })();
  }, []);

  const handleBarCodeScanned = async ({ data }) => {
    console.log('扫描到条码:', data);
    setScanned(true);
    setScannedData(`数据: ${data}`);

    try {
      const response = await fetch('https://www.chesifastasera.com/handleQR.php', {
        method: 'POST',
        headers: {
          Accept: 'application/json',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ qrData: data }),
      });

      console.log('服务器响应状态:', response.status);

      if (!response.ok) {
        throw new Error(`HTTP错误!状态码: ${response.status}`);
      }

      const responseData = await response.text();
      console.log('服务器响应数据:', responseData);
      setServerResponse(responseData);

      // 这里可以添加基于服务器响应的其他操作

    } catch (error) {
      console.error('请求服务器时出错:', error.message);
      setError(error.message); // 设置错误信息用于在APP中显示
    }
  };

  const resetScanner = () => {
    console.log('重置扫描器...');
    setScanned(false);
    setScannedData('');
    setServerResponse('');
    setError(null); // 重试时清除错误
  };

  if (hasCameraPermission === null) {
    console.log('正在检查相机权限...');
    return <View />;
  }

  if (hasCameraPermission === false) {
    console.log('相机权限被拒绝。');
    return <Text>相机权限被拒绝</Text>;
  }

  console.log('渲染相机组件...');
  return (
    <View style={styles.container}>
      <Camera
        onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
        style={styles.preview}
      >
        <View style={styles.qrFrame}>
          <Text style={styles.qrCodeText}>{scannedData}</Text>
        </View>
      </Camera>
      {error && (
        <Text style={styles.scanText}>{`错误: ${error}`}</Text>
      )}
      {scanned && !error && (
        <View>
          <Text style={styles.scanText}>{`服务器响应: ${serverResponse}`}</Text>
          <Button title="重新扫描" onPress={resetScanner} />
        </View>
      )}
    </View>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 09:51:27