当前位置: 首页 > 知识库问答 >
问题:

Firebase Auth Phone OTP在Android中无法自动读取

轩辕佑运
2023-03-14

我正在使用最新的firebase sdk进行身份验证,但otp自动填充不起作用。OTP短信被成功接收,当我手动输入时,它工作正常,没有任何问题。但我需要在没有用户参与的情况下自动获得OTP。

我的代码:

    mAuth = FirebaseAuth.getInstance();
    editText = findViewById(R.id.sixdigit);
    mTextViewCountDown = findViewById(R.id.text_view_countdown);

    progress = new ProgressDialog(GVerifyotpActivity.this);
    progress.setMessage("Waiting....");
    progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);

    String phonenumber = getIntent().getStringExtra("phonenumber");
    sendVerificationCode(phonenumber);

    findViewById(R.id.pnext).setOnClickListener(v -> {
        String code = editText.getText().toString().trim();
        if (code.isEmpty() || code.length() < 6) {
            editText.setError("Enter code...");
            editText.requestFocus();
            return;
        }
        verifyCode(code);
    });

    mButtonStartPause = findViewById(R.id.button_start_pause);
    mButtonStartPause.setOnClickListener(view -> {
        resetTimer();
        startTimer();
        resendVerificationCode(phonenumber, mResendToken);
    });
}

private void verifyCode(String code) {
    PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code);
    signInWithCredential(credential);
    if(progress!=null && !progress.isShowing()) {
        progress.show();
    }
}

private void signInWithCredential(PhoneAuthCredential credential) {
    mAuth.signInWithCredential(credential)
            .addOnCompleteListener(task -> {
                if (task.isSuccessful()) {
                     //Success!
                    }).addOnFailureListener(unused-> Toast.makeText(this, R.string.try_1, Toast.LENGTH_SHORT).show());
                } else {
                    Toast.makeText(GVerifyotpActivity.this, Objects.requireNonNull(task.getException()).getMessage(), Toast.LENGTH_LONG).show();
                }
            });
}

private void sendVerificationCode(String number) {
    PhoneAuthOptions options =
            PhoneAuthOptions.newBuilder(mAuth)
                    .setPhoneNumber(number)       // Phone number to verify
                    .setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
                    .setActivity(this)                 // Activity (for callback binding)
                    .setCallbacks(mCallbacks)          // OnVerificationStateChangedCallbacks
                    .build();
    PhoneAuthProvider.verifyPhoneNumber(options);

}

private void startTimer() {
    new CountDownTimer(mTimeLeftInMillis, 1000) {
        @Override
        public void onTick(long millisUntilFinished) {
            mTimeLeftInMillis = millisUntilFinished;
            updateCountDownText();
        }

        @Override
        public void onFinish() {
            mButtonStartPause.setEnabled(true);
        }
    }.start();
}

private void resetTimer() {
    mTimeLeftInMillis = START_TIME_IN_MILLIS;
    updateCountDownText();
    mButtonStartPause.setEnabled(false);
}

private void resendVerificationCode(String phoneNumber,
                                    PhoneAuthProvider.ForceResendingToken token) {
    PhoneAuthOptions options =
            PhoneAuthOptions.newBuilder(mAuth)
                    .setPhoneNumber(phoneNumber)       // Phone number to verify
                    .setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
                    .setActivity(this)                 // Activity (for callback binding)
                    .setCallbacks(mCallbacks)          // OnVerificationStateChangedCallbacks
                    .setForceResendingToken(token)     // ForceResendingToken from callbacks
                    .build();
    PhoneAuthProvider.verifyPhoneNumber(options);
}

private void updateCountDownText() {
    int minutes = (int) (mTimeLeftInMillis / 1000) / 60;
    int seconds = (int) (mTimeLeftInMillis / 1000) % 60;
    String timeLeftFormatted = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);
    mTextViewCountDown.setText(timeLeftFormatted);
}

public void testPhoneAutoRetrieve() {
    // [START auth_test_phone_auto]
    // The test phone number and code should be whitelisted in the console.
    String phoneNumber = "+9471268xxxxx";
    String smsCode = "123456";

    FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
    FirebaseAuthSettings firebaseAuthSettings = firebaseAuth.getFirebaseAuthSettings();

    // Configure faking the auto-retrieval with the whitelisted numbers.
    firebaseAuthSettings.setAutoRetrievedSmsCodeForPhoneNumber(phoneNumber, smsCode);

    PhoneAuthOptions options = PhoneAuthOptions.newBuilder(firebaseAuth)
            .setPhoneNumber(phoneNumber)
            .setTimeout(120L, TimeUnit.SECONDS)
            .setActivity(this)
            .setCallbacks(new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
                @Override
                public void onVerificationCompleted(PhoneAuthCredential credential) {
                    // Instant verification is applied and a credential is directly returned.
                    // ...
                    Log.d("TAGRR", "onVerificationCompleted: "+credential);
                }

                // [START_EXCLUDE]
                @Override
                public void onVerificationFailed(FirebaseException e) {
                    Log.d("TAGRR", "onVerificationFailed: "+e);
                }
                // [END_EXCLUDE]
            })
            .build();
    PhoneAuthProvider.verifyPhoneNumber(options);
    // [END auth_test_phone_auto]
}


private PhoneAuthProvider.OnVerificationStateChangedCallbacks
        mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {

    @Override
    public void onCodeSent(@NonNull String s, @NonNull PhoneAuthProvider.ForceResendingToken forceResendingToken) {
        super.onCodeSent(s, forceResendingToken);
        verificationId = s;
        mResendToken = forceResendingToken;
    }

    @Override
    public void onVerificationCompleted(@NonNull PhoneAuthCredential credential) {
        // This callback will be invoked in two situations:
        // 1 - Instant verification. In some cases the phone number can be instantly
        //     verified without needing to send or enter a verification code.
        // 2 - Auto-retrieval. On some devices Google Play services can automatically
        //     detect the incoming verification SMS and perform verification without
        //     user action.
        Log.d("TAGP", "onVerificationCompleted:" + credential);

        String code = credential.getSmsCode();
        if (code != null) {
            editText.setText(code);
        }
        signInWithCredential(credential);
        if(progress!=null && !progress.isShowing()) {
            progress.show();
        }
    }

    @Override
    public void onVerificationFailed(FirebaseException e) {
        Toast.makeText(GVerifyotpActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
    }
}; 

依赖关系

implementation 'com.google.firebase:firebase-auth:21.0.1'
implementation 'com.google.android.gms:play-services-auth-api-phone:17.5.1'
implementation 'com.google.android.gms:play-services-auth:19.2.0' 

Android DeviceCheck API添加成功,Firebase设置中插入SHA-256密钥!SafetyNet激活!

classpath 'com.android.tools.build:gradle:4.2.2'
classpath 'com.google.gms:google-services:4.3.8' 

一切都是根据Firebase文档完成的[https://firebase.google.com/docs/auth/android/phone-auth]

我用testPhoneAutoRetrieve()方法进行了测试,它可以工作,但在真正的sim卡上却无法工作!未从收到的短信中获取凭据!

找到日志

Ignoring header X-Firebase-Locale because its value was null.

FirebaseAuth: [SmsRetrieverHelper] Timed out waiting for SMS. 
PhoneAuthProvider: Sms auto retrieval timed-out.

有什么我忘了的吗?应用程序名称字符限制有问题吗?示例应用程序名称-MyApp:Abc,Xyz(国家)

  1. 列表项

共有1个答案

施利
2023-03-14

我遇到了同样的问题,我的问题是由于应用程序名称太长而无法包含哈希码。以下是一些解决方法

  1. 你需要确保收到的消息包含应用程序的哈希值。以下是正确的格式:

123456是您对%APP_NAME%的验证码

如果您的SMS末尾不包含hashCode,您可能必须将您的应用程序名称缩短至不超过15个字符。

如果您的应用程序已在Google Play上发布,则SMS中的名称将与Google Play商店中的名称相同。

如果您将名称更改为15个字符并且错误仍然存在,您可能需要等待至少24小时才能在Firebase上反映更改。

如果以上所有问题仍然没有解决,请检查您的接收器在代码中是否配置良好。

查看GooglePlay关于应用程序名称的新政策:常见应用程序名称违规示例

 类似资料:
  • 我得到这个错误: ntime:致命异常:主进程:com.example。puzzle\u项目,PID:4100 java.lang.RuntimeException:无法启动活动ComponentInfo{com.example.puzzle\u项目/com.example.puzzle\u项目.MainActivity}:java.lang.NullPointerException:尝试在空对象

  • 我正在使用NFC读取Mifare Classic 1K卡。 该代码适用于所有Android5.0及以下版本的Android设备,但当我在Android5.1设备上测试代码时,它不起作用。 我的代码, 当我在Android5.1中扫描卡片时,返回,否则在5.1以下的版本中,它可以正常工作。

  • 我正在尝试使用clojure创建一个简单的android应用程序,它可以读取csv文件,并允许用户对数据进行类似正则表达式的搜索。问题是,当我尝试读取数据时,会出现以下异常。 我的研究表明,这通常意味着Clojure正在寻找某样东西,但找不到。但是我不知道它可能是什么或者为什么。 下面是引发异常的Clojure代码: 据我所知,“kamus.csv”在正确的目录中,所以我不认为是这样。如果我在re

  • 问题内容: 大家好(这是我的第一个问题,请不要太粗鲁)。我是编码初学者,并且在Android Studio中遇到了此错误:“ Gradle项目同步失败”,错误为“错误:无法从/ Users / sgrumo / Downloads / gvr-android-sdk- master读取packageName /samples/sdk-treasurehunt/src/main/AndroidMan

  • 问题内容: 我试图导入各种我不记得它们确切名称的库。不幸的是, Xcode 6(使用)不能像使用Objective-c 在 Xcode 5中那样自动完成它们。 例如: 等等 我被迫向Google输入确切的框架名称,然后返回并复制粘贴。 通常,自动完成功能的效果非常差。我在Xcode 6中做错了吗? 我是否应该在设置中设置任何标志以使其正常工作? 问题答案: apple dev论坛中的此修复程序对我