Flutter/Firebase iOS端手机号验证失败(token mismatch)求助
iOS端Firebase Phone Auth触发'verificationFailed'并报'token mismatch'错误
问题概述
Firebase的手机号验证功能在Android端完全正常,但iOS端始终触发verificationFailed回调,错误信息为**'token mismatch'**,已排查多日仍未解决。
代码片段
Firebase初始化代码
Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); // Initialize Firebase await Firebase.initializeApp( name: '<app name>', options: DefaultFirebaseOptions.currentPlatform, ).then((_) { print("Firebase initialized successfully."); }).catchError((error) { print("Error initializing Firebase: $error"); }); // Clear Firestore persistence here try { await FirebaseFirestore.instance.clearPersistence(); print('Firestore persistence cleared.'); } catch (e) { print('Error clearing Firestore persistence: $e'); } // Set Firestore settings try { FirebaseFirestore.instance.settings = const Settings( persistenceEnabled: false, sslEnabled: false, cacheSizeBytes: Settings.CACHE_SIZE_UNLIMITED, ); print('Firestore settings updated.'); } catch (e) { print('Error setting up Firestore: $e'); } globals.fbdb = FirebaseFirestore.instance; globals.fbauth = FirebaseAuth.instance; globals.fbs = FirebaseStorage.instance; // Run the app runApp(const <appname>()); }
手机号验证代码
static Future<void> verifyPhoneNumber(String phoneNumber) async { await FirebaseMessaging.instance.getToken(); print("+++ phoneNumber = ${phoneNumber}"); await globals.fbauth.verifyPhoneNumber( phoneNumber: phoneNumber, verificationCompleted: (PhoneAuthCredential credential) async { // Auto-retrieve verification code print("Verification Complete has been triggered for some reason!"); }, verificationFailed: (FirebaseAuthException e) { // Verification failed print('+++ Verification failed. Error = ${e}'); }, codeSent: (String verificationId, int? resendToken) async { // Save the verification ID for future use print('got through to codeSent section'); }, codeAutoRetrievalTimeout: (String verificationId) {}, timeout: Duration(seconds: 60), ); } }
AppDelegate.swift代码
import UIKit import Firebase import Flutter import FirebaseMessaging import FirebaseAuth @main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { // Firebase initialization GeneratedPluginRegistrant.register(with: self) Messaging.messaging().delegate = self return super.application(application, didFinishLaunchingWithOptions: launchOptions) } override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { if Auth.auth().canHandleNotification(userInfo) { print(userInfo) return } completionHandler(.newData) } override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { Auth.auth().setAPNSToken(deviceToken, type: AuthAPNSTokenType.unknown) } } extension AppDelegate: MessagingDelegate { func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { print("Firebase registration token: \(String(describing: fcmToken))") } }
环境信息
- Flutter版本:3.24.3(稳定版)
- Dart版本:3.5.3
- Devtools版本:2.37.3
- Xcode版本:15.4(15F31d)
- Android Studio版本:Koala Feature Drop | 2024.1.2
- 测试设备:iPhone 13(真机)
已排查项
- 无编译错误
- 所有插件均为最新版本
- firebase-options.dart配置正确
- 包含REVERSE_CLIENT_ID的URL Type配置正确
- Apple证书及.p8密钥已多次重新生成并确认无误
- Firebase控制台已启用手机号登录等认证方式
- Bundle名称及Firebase应用名称一致
- Google Cloud Platform中iOS自动生成密钥已锁定至iOS应用
- 已拥有Apple开发者付费账号
- 配置了正确的描述文件
- GoogleService-Info.plist位置及内容正确
- 已开启Background Fetch和Remote Notifications后台模式
解决方案建议
修正APNS Token类型设置
当前AppDelegate中设置APNS Token类型为AuthAPNSTokenType.unknown,这可能导致Token不匹配。根据测试环境明确指定类型:// 开发环境用.sandbox,生产环境用.prod Auth.auth().setAPNSToken(deviceToken, type: .sandbox)若使用Xcode自动签名,可保留自动适配,但手动指定能避免环境识别偏差。
调整Firebase初始化顺序
原生端需优先完成Firebase初始化,再注册Flutter插件,修改AppDelegate的didFinishLaunchingWithOptions方法:override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { FirebaseApp.configure() // 新增此行,确保Firebase优先初始化 GeneratedPluginRegistrant.register(with: self) Messaging.messaging().delegate = self return super.application(application, didFinishLaunchingWithOptions: launchOptions) }同步FCM Token与Auth状态
在获取FCM Token时,确保APNS Token已同步到Firebase Auth,修改MessagingDelegate的实现:func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { guard let token = fcmToken else { return } print("Firebase registration token: \(token)") // 重新同步APNS Token到Auth if let deviceToken = Messaging.messaging().apnsToken { Auth.auth().setAPNSToken(deviceToken, type: .sandbox) } }清理缓存并重新构建
- 执行
flutter clean清除Flutter缓存 - 删除Xcode的Derived Data(Xcode > 设置 > 位置 > Derived Data > 删除对应项目文件夹)
- 卸载设备上的App,重新执行
flutter run --release测试生产环境逻辑
- 执行
检查Google Cloud API密钥限制
登录Google Cloud控制台,确认对应API密钥的应用限制中已正确添加iOS应用的Bundle ID,且未限制Firebase Phone Authentication API的调用权限。
内容的提问来源于stack exchange,提问作者BigRedSwitch
相关产品推荐
相关产品推荐

