React Native Expo在Xcode运行时出现crypto未找到错误求助
解决Xcode运行Expo React Native应用时的
crypto不存在错误 问题根源
你遇到的ReferenceError: Property 'crypto' doesn't exist是因为Node.js内置的crypto模块在React Native的Hermes引擎环境中不可用——Hermes是轻量JS引擎,不包含Node.js的核心API。而npm run ios能运行,大概率是Expo CLI在打包时自动注入了crypto的polyfill,但直接通过Xcode运行时没有触发该逻辑。
解决方案
1. 替换为React Native兼容的加密库
使用Expo官方维护的expo-crypto,完全适配Hermes环境:
- 安装依赖:
npx expo install expo-crypto
2. 修正加密逻辑与代码问题
你的代码存在混用Node.js crypto和CryptoJS、中文全角引号、未定义函数、冗余返回语句等问题,以下是修正后的完整代码:
import React, { useEffect, useState } from 'react'; import { View, Text, Image, StyleSheet } from 'react-native'; import * as Device from 'expo-device'; import * as Crypto from 'expo-crypto'; import { useVerifyDeviceMutation } from './verifyDeviceQuery.generated'; type DeviceVerificationPayload = { deviceVariantIdentifier: string; deviceOsVersion: string; }; // 实现base64转UTF8 const base64ToUtf8 = (base64: string) => { const decoded = Crypto.decodeBase64(base64); return String.fromCharCode(...new Uint8Array(decoded)); }; const encrypt = async (payload: DeviceVerificationPayload) => { const algorithm = 'aes-256-cbc'; const encryptionAlgoKey = 'Key'; // 注意:替换为实际密钥,禁止硬编码 const encryptionKey = base64ToUtf8(encryptionAlgoKey); // SHA256生成256位密钥 const keyHash = await Crypto.digestStringAsync( Crypto.CryptoDigestAlgorithm.SHA256, encryptionKey ); const key = Crypto.decodeBase64(keyHash); // 从密钥前16字节生成IV(AES-CBC要求16字节IV) const iv = key.slice(0, 16); const stringifiedPayload = JSON.stringify(payload); const encodedPayload = new TextEncoder().encode(stringifiedPayload); // 执行加密并转十六进制字符串 const encryptedBuffer = await Crypto.encryptAsync( algorithm, encodedPayload, key, { iv } ); return Array.from(new Uint8Array(encryptedBuffer)) .map(byte => byte.toString(16).padStart(2, '0')) .join(''); }; export default function HomeScreen() { const deviceVerificationGuid = 'deviceVerificationGuid'; const [isVerifying, setIsVerifying] = useState<boolean>(true); const [deviceVerificationFailure, setDeviceVerificationFailure] = useState<boolean>(false); const [verifyDevice, { loading }] = useVerifyDeviceMutation({ onCompleted: () => setIsVerifying(false), onError: () => { setIsVerifying(false); setDeviceVerificationFailure(true); } }); useEffect(() => { const performVerification = async () => { try { const deviceVariantIdentifier = Device.modelName || ''; const deviceOsVersion = Device.osVersion || ''; const signature = await encrypt({ deviceVariantIdentifier, deviceOsVersion }); await verifyDevice({ variables: { input: { deviceVariantIdentifier, deviceOsVersion, signature, deviceVerificationGuid } } }); } catch (err) { setIsVerifying(false); setDeviceVerificationFailure(true); console.error('Verification failed:', err); } }; performVerification(); }, [deviceVerificationGuid, verifyDevice]); if (!deviceVerificationGuid || isVerifying) { return ( <View style={styles.container}> <Image source={require('./assets/loadicon.gif')} style={styles.image} /> </View> ); } if (deviceVerificationFailure) { return ( <View style={styles.container}> <Text>Device verification failed</Text> </View> ); } return ( <View style={styles.container}> {/* User Interface Logic */} <Text>Home Screen</Text> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, image: { width: 100, height: 100, }, });
3. 额外注意事项
- 禁止硬编码密钥,建议从后端接口获取或用
expo-secure-store存储 - 确保Xcode项目为最新状态,可执行
npx expo prebuild重新生成 - 加密逻辑需与后端解密逻辑完全匹配(比如编码格式、IV生成规则)
内容的提问来源于stack exchange,提问作者devcoder93
相关产品推荐
相关产品推荐

