Expo React Native中TestFlight环境Apple登录失效,遭苹果审核驳回
我的Apple登录功能在Expo Go和模拟器中运行正常,但在TestFlight环境下点击后无任何反应,苹果审核团队反馈:
我们发现应用存在一个或多个Bug,具体表现为使用Apple登录时,应用停留在登录界面。
相关代码如下:
const loginWithApple = () => { const nonce = Math.random().toString(36).substring(2, 10); return Crypto.digestStringAsync(Crypto.CryptoDigestAlgorithm.SHA256, nonce) .then((hashedNonce) => AppleAuthentication.signInAsync({ requestedScopes: [ AppleAuthentication.AppleAuthenticationScope.FULL_NAME, AppleAuthentication.AppleAuthenticationScope.EMAIL ], nonce: hashedNonce }) ) .then(async (appleCredential) => { const { identityToken } = appleCredential; const provider = new firebase.auth.OAuthProvider('apple.com'); const credential = await provider.credential({ idToken: identityToken, rawNonce: nonce }); await firebase.auth().signInWithCredential(credential).then((res) => { const profileInfo = res.user.providerData[0]; const uid = res.user.uid; let action = addUserOnFirestore( uid, profileInfo.email, profileInfo.displayName?.split(" ")[0], profileInfo.displayName?.split(" ")[2], profileInfo.photoURL, res, props.navigation ); setIsLoading(true); try { dispatch(action); } catch (err) { setError(err.message); } setIsLoading(false); }); // Successful sign in is handled by firebase.auth().onAuthStateChanged }) .catch((error) => { console.log('Error : ', error); }); }
Apple开发者后台配置验证
确认App Identifier已开启Sign In with Apple功能,且TestFlight使用的Bundle ID与后台配置完全一致;同时检查Apple登录的Service ID是否正确关联到该Bundle ID。Nonce生成与哈希的合规性
Apple要求nonce长度至少为10个字符,当前代码生成的nonce(substring(2,10))仅8位,可能不符合要求,建议调整为Math.random().toString(36).substring(2,20)确保长度达标;另外验证Expo生产环境中Crypto.digestStringAsync的哈希结果是否正常,避免哈希过程出现静默失败。错误处理的可视化补充
当前catch块仅通过console.log输出错误,TestFlight环境无法查看控制台日志,导致无法定位具体问题。建议添加用户可见的错误提示,比如:import { Alert } from 'react-native'; // 在catch块中添加 Alert.alert('登录失败', error.message || '使用Apple登录时出现异常,请稍后重试');Firebase Auth配置检查
确认Firebase控制台已启用Apple登录提供商,且配置的Service ID与Apple开发者后台一致;同时验证GoogleService-Info.plist文件是否正确集成到Expo生产打包流程中。异步代码逻辑优化
代码中存在.then嵌套async/await的情况,可能导致Promise链异常被隐藏。建议统一使用async/await写法,同时修复潜在的数组越界问题:const loginWithApple = async () => { try { const nonce = Math.random().toString(36).substring(2, 20); const hashedNonce = await Crypto.digestStringAsync(Crypto.CryptoDigestAlgorithm.SHA256, nonce); const appleCredential = await AppleAuthentication.signInAsync({ requestedScopes: [ AppleAuthentication.AppleAuthenticationScope.FULL_NAME, AppleAuthentication.AppleAuthenticationScope.EMAIL ], nonce: hashedNonce }); const { identityToken } = appleCredential; const provider = new firebase.auth.OAuthProvider('apple.com'); const credential = await provider.credential({ idToken: identityToken, rawNonce: nonce }); const res = await firebase.auth().signInWithCredential(credential); const profileInfo = res.user.providerData[0]; const uid = res.user.uid; // 修复displayName split的数组越界问题 const nameParts = profileInfo.displayName?.split(" ") || []; let action = addUserOnFirestore( uid, profileInfo.email, nameParts[0] || '', nameParts[1] || '', // 原代码用索引2,大概率是笔误 profileInfo.photoURL, res, props.navigation ); setIsLoading(true); dispatch(action); } catch (error) { console.error('Apple登录错误:', error); Alert.alert('登录失败', error.message || '无法完成Apple登录,请稍后重试'); } finally { setIsLoading(false); // 移到finally确保无论成功失败都会更新状态 } }注意原代码中
profileInfo.displayName?.split(" ")[2]存在数组越界风险,用户的displayName通常是"名 姓",索引2为undefined,建议改为索引1或添加默认值。Expo打包配置验证
确认app.json的ios配置中已添加"usesAppleSignIn": true,且Bundle ID与开发者后台一致;同时检查Expo生产打包时是否正确包含了Apple登录所需的配置项。
内容的提问来源于stack exchange,提问作者emile kaba

