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

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)

问题原因

  1. 类导入错误:代码中使用的Status类可能误导入了Android系统自带的android.os.Status,而非Google Play Services提供的com.google.android.gms.auth.api.phone.Status,导致Parcel读取时无法匹配正确的Parcelable类型,触发空指针。
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 12:03:10