Flutter Late变量赋值后仍触发LateInitializationError问题排查
问题
在Flutter中使用Firebase手机号认证时,定义了late String类型的verificationId变量,本期望发送OTP时为其赋值供后续使用,但调用submitOTP函数时该变量始终未初始化,触发LateInitializationError。相关Cubit代码如下:
import 'package:bloc/bloc.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:meta/meta.dart'; part 'phone_auth_state.dart'; class PhoneAuthCubit extends Cubit<PhoneAuthState> { late String verificationId; PhoneAuthCubit() : super(PhoneAuthInitial()); Future<void> submitPhoneNumber(String phoneNumber) async { emit(PhoneAuthLoading()); await FirebaseAuth.instance.verifyPhoneNumber( phoneNumber: '$phoneNumber', timeout: const Duration(seconds: 14), verificationCompleted: verificationCompleted, verificationFailed: verificationFailed, codeSent: codeSent, codeAutoRetrievalTimeout: codeAutoRetrievalTimeout, ); } void verificationCompleted(PhoneAuthCredential credential) async { print('verificationCompleted'); await signIn(credential); } void verificationFailed(FirebaseAuthException error) { print('verificationFailed : ${error.toString()}'); emit(PhoneAuthFailure(errorMessage: error.toString())); } void codeSent(String verificationId, int? resendToken) { print('codeSent'); this.verificationId = verificationId; emit(PhoneNumberSubmitted()); print("khlst code sent"); } void codeAutoRetrievalTimeout(String verificationId) { print('codeAutoRetrievalTimeout'); } Future<void> submitOTP(String otpCode) async { PhoneAuthCredential credential = PhoneAuthProvider.credential( verificationId: this.verificationId, smsCode: otpCode); await signIn(credential); } Future<void> signIn(PhoneAuthCredential credential) async { try { await FirebaseAuth.instance.signInWithCredential(credential); emit(PhoneOTPVerified()); } catch (error) { emit(PhoneAuthFailure(errorMessage: error.toString())); } } Future<void> signOut() async { await FirebaseAuth.instance.signOut(); } User getLoggedInUser() { User firebaseUser = FirebaseAuth.instance.currentUser!; return firebaseUser; } }
解决方案
核心问题分析
LateInitializationError的触发原因有两个:要么codeSent回调根本没执行(verificationId从未被赋值),要么submitOTP在codeSent执行前就被调用了。
针对性修复方案
替换
late变量为可空类型
把late String verificationId改为String? verificationId,明确变量的未初始化状态,避免强制非空带来的崩溃:class PhoneAuthCubit extends Cubit<PhoneAuthState> { String? verificationId; // ... 其他代码不变 }在
submitOTP中增加安全校验
调用认证方法前先检查verificationId是否有效,无效则直接返回错误状态:Future<void> submitOTP(String otpCode) async { if (verificationId == null) { emit(PhoneAuthFailure(errorMessage: "请先获取验证码")); return; } PhoneAuthCredential credential = PhoneAuthProvider.credential( verificationId: verificationId!, smsCode: otpCode); await signIn(credential); }确保
codeSent回调正常触发
排查以下几点确认verificationId能被赋值:- 手机号必须包含正确的国家码(例如
+8613xxxxxxxxx) - Firebase控制台已启用手机号认证方式
- 设备网络正常,能访问Firebase服务
- 查看控制台日志,确认
codeSent和khlst code sent是否打印
- 手机号必须包含正确的国家码(例如
优化状态传递逻辑
把verificationId通过状态传递,避免依赖Cubit内部变量:- 修改
PhoneNumberSubmitted状态类,添加verificationId字段:class PhoneNumberSubmitted extends PhoneAuthState { final String verificationId; PhoneNumberSubmitted(this.verificationId); } - 更新
codeSent方法:void codeSent(String verificationId, int? resendToken) { print('codeSent'); emit(PhoneNumberSubmitted(verificationId)); print("khlst code sent"); } - UI层在收到
PhoneNumberSubmitted状态后,把verificationId暂存,调用submitOTP时直接传入,彻底规避Cubit内部变量的生命周期问题。
- 修改
内容的提问来源于stack exchange,提问作者Mustafa Adel
相关产品推荐
相关产品推荐

