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
相关产品推荐
相关产品推荐

