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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 05:18:07