Android 13中调用getParcelable方法出现NullPointerException问题
Android 13下SmsRetriever获取OTP时的NullPointerException解决
问题详情
使用Firebase电话认证+BroadcastReceiver自动读取OTP时,仅在Android 13(TIRAMISU)设备上触发以下空指针异常:
Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Class.isInterface()' on a null object reference at java.lang.Class.isAssignableFrom(Class.java:589) at android.os.Parcel.readParcelableCreatorInternal(Parcel.java:4882) at android.os.Parcel.readParcelableInternal(Parcel.java:4795) at android.os.Parcel.readValue(Parcel.java:4561) at android.os.Parcel.readValue(Parcel.java:4341) at android.os.Parcel.-$$Nest$mreadValue() at android.os.Parcel$LazyValue.apply(Parcel.java:4439) at android.os.Parcel$LazyValue.apply(Parcel.java:4398) at android.os.BaseBundle.getValueAt(BaseBundle.java:394) at android.os.BaseBundle.getValue(BaseBundle.java:374) at android.os.BaseBundle.getValue(BaseBundle.java:357) at android.os.BaseBundle.get(BaseBundle.java:696) at android.os.Bundle.getParcelable(Bundle.java:947) at com.adithya.memoneet.v1.presentation.auth.OTPAutoReader.onReceive(OTPAutoReader.kt:27) at android.app.ActivityThread.handleReceiver(ActivityThread.java:4544) at android.app.ActivityThread.-$$Nest$mhandleReceiver() at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2308) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:240) at android.os.Looper.loop(Looper.java:351) at android.app.ActivityThread.main(ActivityThread.java:8381) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:584) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1013)
触发点为代码行:
bundle.getParcelable(SmsRetriever.EXTRA_STATUS, Status::class.java)
问题原因
- 类导入错误:代码中使用的
Status类可能误导入了Android系统自带的android.os.Status,而非Google Play Services提供的com.google.android.gms.auth.api.phone.Status,导致Parcel读取时无法匹配正确的Parcelable类型,触发空指针。 - Android 13 Parcelable校验变更:Android 13对Parcelable的类型校验更严格,未显式指定正确目标类时,会出现类解析失败的情况。
解决方案
1. 确认正确的类导入
确保代码导入的是Google Play Services的Status类:
import com.google.android.gms.auth.api.phone.Status
避免导入系统类android.os.Status。
2. 修改Parcelable读取逻辑
统一在所有SDK版本下显式指定正确的Status类,同时处理旧API的废弃警告:
val status: com.google.android.gms.auth.api.phone.Status? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { bundle.getParcelable(SmsRetriever.EXTRA_STATUS, com.google.android.gms.auth.api.phone.Status::class.java) } else { @Suppress("DEPRECATION") bundle.getParcelable(SmsRetriever.EXTRA_STATUS, com.google.android.gms.auth.api.phone.Status::class.java) }
若使用AndroidX的core-ktx库,可简化兼容逻辑:
// 需依赖androidx.core:core-ktx val status = bundle.getParcelableCompat<com.google.android.gms.auth.api.phone.Status>(SmsRetriever.EXTRA_STATUS)
3. 额外检查
- 确保Google Play Services依赖版本足够新,避免序列化兼容问题:
implementation "com.google.android.gms:play-services-auth-api-phone:18.0.1"
- 确认BroadcastReceiver已在Manifest中正确注册,Android 13及以上需申请
POST_NOTIFICATIONS权限(若通过前台服务启动SmsRetriever)。
修改后的完整代码示例
import com.google.android.gms.auth.api.phone.CommonStatusCodes import com.google.android.gms.auth.api.phone.SmsRetriever import com.google.android.gms.auth.api.phone.Status import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.os.Build import android.os.Bundle import android.util.Log import java.util.regex.Pattern class OTPAutoReader : BroadcastReceiver() { private var otpSmsListener: OTPSMSListener? = null fun init(otpSmsListener: OTPSMSListener) { this.otpSmsListener = otpSmsListener } override fun onReceive(context: Context?, intent: Intent?) { if (SmsRetriever.SMS_RETRIEVED_ACTION == intent?.action) { val bundle: Bundle? = intent.extras if (bundle != null) { val status: Status? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { bundle.getParcelable(SmsRetriever.EXTRA_STATUS, Status::class.java) } else { @Suppress("DEPRECATION") bundle.getParcelable(SmsRetriever.EXTRA_STATUS, Status::class.java) } if (status != null) { when (status.statusCode) { CommonStatusCodes.SUCCESS -> { val message: String? = bundle.getString(SmsRetriever.EXTRA_SMS_MESSAGE) Log.i("TAG >> SUCCESS", message ?: "") message?.let { try { val pattern = Pattern.compile("\\d{6}") val matcher = pattern.matcher(message) if (matcher.find()) { val otp = matcher.group(0) otp?.let { otpSmsListener?.onSuccess(it) } ?: run { otpSmsListener?.onFailure("OTP not received") } } else { otpSmsListener?.onFailure("OTP not received") } } catch (e: Exception) { e.printStackTrace() otpSmsListener?.onFailure("Failed to retrieve SMS") } } ?: run { otpSmsListener?.onFailure("Failed to retrieve SMS") } } CommonStatusCodes.TIMEOUT -> { Log.i("TAG >> TIMEOUT", "timeout") otpSmsListener?.onFailure("timeout") } } } else { otpSmsListener?.onFailure("Failed to retrieve status") } } else { otpSmsListener?.onFailure("No data received from intent") } } } interface OTPSMSListener { fun onSuccess(otp: String) fun onFailure(msg: String) } }
内容的提问来源于stack exchange,提问作者Priyanshu
相关产品推荐
相关产品推荐

