使用SmsRetriever时收到广播意图出错

10
在使用Firebase身份验证时,我想要自动输入通过短信接收到的代码。我能够手动接收短信并完成身份验证过程,但是当我使用SmsRetriever时,应用程序会崩溃,然后底部对话框会出现。以下是Logcat中显示的所有内容:
java.lang.RuntimeException: Error receiving broadcast Intent { act=com.google.android.gms.auth.api.phone.SMS_RETRIEVED flg=0x200010 pkg=com.finca.bank (has extras) } in com.google.android.gms.internal.firebase-auth-api.zzvb@45fb8c5
        at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1566)
        at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(Unknown Source:2)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:224)
        at android.app.ActivityThread.main(ActivityThread.java:7562)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
     Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'int java.lang.CharSequence.length()' on a null object reference
        at java.util.regex.Matcher.reset(Matcher.java:280)
        at java.util.regex.Matcher.<init>(Matcher.java:186)
        at java.util.regex.Pattern.matcher(Pattern.java:1034)
        at com.google.android.gms.internal.firebase-auth-api.zzvd.zzf(com.google.firebase:firebase-auth@@20.0.1:1)
        at com.google.android.gms.internal.firebase-auth-api.zzvb.onReceive(com.google.firebase:firebase-auth@@20.0.1:8)
        at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1556)
        at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(Unknown Source:2) 

以下是在我的Fragment中接收短信的代码:

private val SMS_CONSENT_REQUEST = 2  // Set to an unused request code

    private val smsVerificationReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            try {
                if (SmsRetriever.SMS_RETRIEVED_ACTION == intent.action) {
                    val extras = intent.extras
                    val smsRetrieverStatus = extras?.get(SmsRetriever.EXTRA_STATUS) as Status

                    when (smsRetrieverStatus.statusCode) {
                        CommonStatusCodes.SUCCESS -> {
                            // Get consent intent
                            val consentIntent = extras.getParcelable<Intent>(SmsRetriever.EXTRA_CONSENT_INTENT)
                            try {
                                // Start activity to show consent dialog to user, activity must be started in
                                // 5 minutes, otherwise you'll receive another TIMEOUT intent
                                startActivityForResult(consentIntent, SMS_CONSENT_REQUEST)
                            } catch (e: ActivityNotFoundException) {
                                // Handle the exception ...
                            }
                        }
                        CommonStatusCodes.TIMEOUT -> {
                            // Time out occurred, handle the error.
                        }
                    }
                }
            } catch (e: Exception) {
                Timber.e(e, "onReceive: ")
            }
        }
    }

    override fun onResume() {
        super.onResume()
        val task = SmsRetriever.getClient(requireActivity()).startSmsUserConsent(null)
        val intentFilter = IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION)
        requireActivity().registerReceiver(smsVerificationReceiver, intentFilter)
    }

    override fun onPause() {
        super.onPause()
        requireActivity().unregisterReceiver(smsVerificationReceiver)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when (requestCode) {
            // ...
            SMS_CONSENT_REQUEST ->
                // Obtain the phone number from the result
                if (resultCode == Activity.RESULT_OK && data != null) {
                    // Get SMS message content
                    val message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)
                    // Extract one-time code from the message and complete verification
                    // `message` contains the entire text of the SMS message, so you will need
                    // to parse the string.
                    message?.let { presenter.parseSms(it) }
                    // send one time code to the server
                } else {
                    // Consent denied. User can type OTC manually.
                }
        }
    }

有趣的是,进展顺利的情况很少,并且我不知道它取决于什么。此外,如果在 onReceive 中设置断点,则在调试模式下一切都会顺利进行。


1
你找到解决方法了吗?因为我也遇到了同样的问题,但我不知道该怎么解决,因为我从“com.google.android.gms.internal.firebase-auth-api”获得了内部错误。 - Alex D.
@AlexD。很遗憾,暂时我决定不使用SmsRetriever。 - DaniiarR
我遇到了同样的问题。Firebase电话验证的默认短信检索不起作用。这就是为什么我尝试使用自定义短信检索器并得到相同的崩溃的原因。 - n.arrow001
1
你是否尝试将注册广播接收器移入onCreate中,并在onStop中取消注册?我认为主要问题来自于生命周期状态。 - Steve.P
1
我想看一下你的短信格式。 - Usama Altaf
显示剩余5条评论
3个回答

15
经过多次调查,这次崩溃的根本原因似乎与Firebase身份验证即时验证功能和短信同意API之间的冲突有关。
为了解决这个问题,您有两个选择:
  1. 删除SMS同意API,仅依赖即时验证
  2. 使用SMS同意API,并通过将超时设置为0来禁用即时验证。https://firebase.google.com/docs/reference/android/com/google/firebase/auth/PhoneAuthOptions.Builder#setTimeout(java.lang.Long,%20java.util.concurrent.TimeUnit)
希望这能对这个奇怪的问题提供一些清晰的解释。

当我将超时时间设置为0后,它对我起作用了。 - Ashish Choudhary

5
在集成短信同意API时遇到了相同的错误。经过搜索和修改,找到了解决方案。在下面附上的图像中,您可以看到setTimeout方法包含一个名为timeout的参数,请将该参数值从60L更改为0L。有关该方法的更多信息请点击这里!

Just change that value from 60L to 0L.


这对我有用,非常感谢。 - NASHIR ABDULLAH

-1
为了自动验证电话号码,您必须实现验证流程的客户端和服务器端。您刚刚实现了客户端部分。要监听短信并自动输入OTP代码,您还需要实现服务器端。详细指南请参见在服务器上执行短信验证

@Muhammedshamshadp 对此感到抱歉。我已编辑我的答案并放上了正确的链接。 - Uchechukwu Nnabugwu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接