Flutter Android端Apple登录触发firebase_auth/unknown null错误排查
Flutter Android端Apple登录Firebase认证报错[firebase_auth/unknown] null问题排查
我在Flutter应用中使用sign_in_with_apple: ^4.3.0插件实现Apple登录功能,iOS端运行完全正常,但Android端调用signInWithCredential时抛出[firebase_auth/unknown] null错误。
配置与尝试过程
- 已创建Apple的
ServiceID,最初在Domains and Subdomains中添加Firebase项目URL,Return URLs配置Firebase控制台的认证处理程序,但Android端出现Unable to process request due to missing initial state.错误 - 改用AKS上的Node.js服务器搭建回调端点,将服务器域名加入
ServiceID的Domains and Subdomains,端点URL加入Return URLs后,登录流程和弹窗正常,但Android端获取的凭证缺失authorizationCode,且userIdentifier为null(iOS端正常返回该字段)
相关代码与输出
1. Apple凭证获取代码(Dart)
Future<Map<String, dynamic>> authorizeAppleIdCredentials() async { final rawNonce = _generateNonce(); final nonce = _sha256ofString(rawNonce); final Uri uri = Uri.parse( 'https://xxx.xxxxx.cloudapp.azure.com/server/api/apple_callback' // 'https://xxxx-xxxx.firebaseapp.com/__/auth/handler' // 仍会报Unable to process request due to missing initial state错误 ); WebAuthenticationOptions webOptions = WebAuthenticationOptions(clientId: 'xxxx', redirectUri: uri); /// 请求当前登录Apple账号的凭证 final AuthorizationCredentialAppleID appleIdCredential = await SignInWithApple.getAppleIDCredential( webAuthenticationOptions: webOptions, scopes: [ AppleIDAuthorizationScopes.email, AppleIDAuthorizationScopes.fullName, ], nonce: nonce, ).catchError((e) { print( 'UserRepository.authorizeAppleIDCredentials() SignInWithApple.getAppleIDCredential error: $e'); }); Map<String, dynamic> authorizedAppleCredential = { 'appleIdCredential': { 'email': appleIdCredential.email, 'familyName': appleIdCredential.familyName, 'givenName': appleIdCredential.givenName, 'userIdentifier': appleIdCredential.userIdentifier, 'identityToken': appleIdCredential.identityToken, 'authorizationCode': appleIdCredential.authorizationCode, 'state': appleIdCredential.state }, 'rawNonce': rawNonce }; dev.log( 'UserRepository.authorizeAppleIDCredentials() SignInWithApple.getAppleIDCredential is $appleIdCredential\n' 'authorizedAppleCredential is $authorizedAppleCredential'); return authorizedAppleCredential; }
Android端打印结果:
authorizedAppleCredential is {appleIdCredential: {email: myMAil@gmail.com, familyName: surname, givenName: vincenzo, userIdentifier: null, identityToken: some token, state: null}, rawNonce: jsH8DDAoURn1Vf8z.hvxM_sAqxu.PGGP}
iOS端打印结果:
authorizeAppleIdCredentials is: {appleIdCredential: {email: myMaili@gmail.com, familyName: surname, givenName: vincenzo, userIdentifier: xxxxx.xxxxxxxxx.xxxxx, identityToken: some token, authorizationCode: some auth code, state: null}, rawNonce: BmhreGGUY.3E-Ni0_9yi3yJ_0v6bZ0Me}
2. 创建OAuth凭证代码(Dart)
Future<OAuthCredential> createAppleOauthCredential( {required Map<String, dynamic> authorizedAppleCredential, required String rawNonce}) async { // 从Apple返回的凭证创建OAuthCredential print( 'UserRepository.createAppleOauthCredentials apple idToken is ${authorizedAppleCredential['appleIdCredential']['identityToken']}'); // 正常输出 print( 'UserRepository.createAppleOauthCredentials rawNonce is ${authorizedAppleCredential['rawNonce']}'); // 正常输出 final oauthCredential = OAuthProvider("apple.com").credential( idToken: authorizedAppleCredential['appleIdCredential']['identityToken'], rawNonce: rawNonce, ); return oauthCredential; }
打印结果(iOS/Android一致):
AuthCredential(providerId: apple.com, signInMethod: oauth, token: null, accessToken: null)
3. Firebase登录代码(Dart)
Future<User?> signInWithCredential( {required AuthCredential oauthCredential}) async { // 使用Firebase登录,若本地生成的nonce与identityToken中的不匹配则登录失败 UserCredential userCredential = await _firebaseAuth .signInWithCredential(oauthCredential) .catchError((e) { print('_firebaseAuth.signInWithCredential(oauthCredential) error: $e'); }); dev.log( 'UserRepository.signInWithCredential() user is: ${userCredential.user}'); return userCredential.user; }
Android端报错:
_firebaseAuth.signInWithCredential(oauthCredential) error: [firebase_auth/unknown] null
4. Node.js回调端点代码
exports.callback = async (req, res) => { const package_name = 'xxxxx'; const redirect = `intent://callback?${new URLSearchParams( req.body ).toString()}#Intent;package=${package_name};scheme=signinwithapple;end`; console.log('apple callback req is: ', req); console.log(`Redirecting to ${redirect}`); res.redirect(307, redirect); };
5. AndroidManifest.xml配置
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="xxxxx" > <!-- io.flutter.app.FlutterApplication会在onCreate中调用FlutterMain.startInitialization(this),一般无需修改 --> <uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.INTERNET" /> <queries> <!--UrlLauncher 适配打开https链接--> <intent> <action android:name="android.intent.action.VIEW" /> <data android:scheme="https" /> </intent> </queries> <application android:name="${applicationName}" android:allowBackup="false" android:label="xxx" android:icon="@mipmap/ic_launcher"> <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notification" /> <activity android:name=".MainActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> <intent-filter android:autoVerify="true"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="flutterstripe" android:host="safepay" /> </intent-filter> </activity> <!-- 配置Apple登录回调Activity,支持浏览器跳转唤起 --> <activity android:name="com.aboutyou.dart_packages.sign_in_with_apple.SignInWithAppleCallback" android:exported="true" > <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="signinwithapple" /> <data android:path="/callback" /> </intent-filter> </activity> <!-- Flutter启动屏配置 --> <meta-data android:name="io.flutter.embedding.android.SplashScreenDrawable" android:resource="@drawable/launch_background" /> <!-- Flutter渲染首帧后应用的主题 --> <meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" /> <meta-data android:name="flutterEmbedding" android:value="2" /> </application> </manifest>
疑问
请问我的配置或代码哪里存在错误?
内容的提问来源于stack exchange,提问作者Vincenzo
相关产品推荐
相关产品推荐

