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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 21:57:25