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

Xamarin Forms自动读取OTP异常:SMS广播接收器未触发求助

Xamarin Forms Android自动读取OTP广播接收器不触发问题排查与解决

问题概述

在Xamarin Forms中实现自动读取OTP功能时,Android端SMSReceivedReceiver的OnReceive方法未触发,调试断点无响应,MessagingCenter订阅状态正常。

核心问题排查与修复步骤

1. 修正广播接收器的系统IntentAction

系统接收SMS的标准Action是Android.Telephony.Sms.Intents.SmsReceivedAction,而非自定义的"SMS_RECEIVED",修改广播接收器的注解和代码:

using System.Linq;
using System.Text.RegularExpressions;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Telephony;
using FinMobility.Interface;
using Java.Lang;
using Xamarin.Forms;

namespace FinMobility.Droid.Dependency
{
    [BroadcastReceiver(Enabled = true, Exported = true, Label = "SMS Receiver")]
    // 使用系统标准SMS接收Action
    [IntentFilter(new string[] { Android.Telephony.Sms.Intents.SmsReceivedAction })]
    public class SMSReceivedReceiver : BroadcastReceiver
    {
        // 替换为系统常量
        private const string IntentAction = Android.Telephony.Sms.Intents.SmsReceivedAction;
        private static readonly string Sender = "SMS Sender number here";
        private static readonly string[] OtpMessageBodyKeywordSet = { "Keyword1", "Keyword2" };

        public override void OnReceive(Context context, Intent intent)
        {
            try
            {
                // 添加日志确认方法是否触发
                Android.Util.Log.Info("SMSReceiver", "OnReceive method triggered");
                
                if (intent.Action != IntentAction) return;
                var bundle = intent.Extras;
                if (bundle == null) return;
                var pdus = bundle.Get("pdus");
                var castedPdus = JNIEnv.GetArray<Object>(pdus.Handle);
                var msgs = new SmsMessage[castedPdus.Length];
                string sender = null;
                string msgBody = string.Empty;

                for (var i = 0; i < msgs.Length; i++)
                {
                    var bytes = new byte[JNIEnv.GetArrayLength(castedPdus[i].Handle)];
                    JNIEnv.CopyArray(castedPdus[i].Handle, bytes);
                    string format = bundle.GetString("format");
                    msgs[i] = SmsMessage.CreateFromPdu(bytes, format);
                    if (sender == null)
                        sender = msgs[i].OriginatingAddress;
                    msgBody += msgs[i].MessageBody;
                }

                // 统一判断,避免循环内提前return导致遗漏多段短信
                if (!sender.Contains(Sender)) return;
                bool foundKeyword = OtpMessageBodyKeywordSet.Any(k => msgBody.Contains(k));
                if (!foundKeyword) return;

                var code = ExtractNumber(msgBody);
                MessagingCenter.Send<IRegisterSecondPageModel, string>(new IRegisterSecondPageModel(), "OtpReceived", code);
            }
            catch (System.Exception ex)
            {
                Android.Util.Log.Error("SMSReceiver", ex.Message);
            }
        }

        private static string ExtractNumber(string text)
        {
            if (string.IsNullOrEmpty(text)) return "";
            var regPattern = @"\d+";
            var number = Regex.Match(text, regPattern).Value;
            return number;
        }
    }
}

2. 补充动态权限申请(Android 6.0+)

Android 6.0及以上版本,RECEIVE_SMS和READ_SMS属于危险权限,必须动态申请,在MainActivity中添加权限逻辑:

using Android.Content.PM;
using Android.Runtime;

public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
    private const int RequestSmsPermissions = 100;
    private string[] _smsPermissions = new string[] 
    { 
        Android.Manifest.Permission.ReceiveSms, 
        Android.Manifest.Permission.ReadSms 
    };

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        // 检查并申请权限
        CheckSmsPermissions();
        // ...其他初始化代码
    }

    private void CheckSmsPermissions()
    {
        if ((CheckSelfPermission(Android.Manifest.Permission.ReceiveSms) != Permission.Granted) ||
            (CheckSelfPermission(Android.Manifest.Permission.ReadSms) != Permission.Granted))
        {
            RequestPermissions(_smsPermissions, RequestSmsPermissions);
        }
    }

    public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
    {
        base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == RequestSmsPermissions)
        {
            bool allGranted = grantResults.All(r => r == Permission.Granted);
            if (!allGranted)
            {
                Android.Widget.Toast.MakeText(this, "需要短信权限才能自动获取验证码", Android.Widget.ToastLength.Long).Show();
            }
        }
    }

    // 移除手动注册代码,避免与注解注册冲突
    protected override void OnResume()
    {
        base.OnResume();
        // _smsReceivedBroadcastReceiver = new SMSReceivedReceiver();
        // RegisterReceiver(_smsReceivedBroadcastReceiver, new IntentFilter("SMS_RECEIVED"));
    }
}

3. 移除重复的广播注册

既使用[BroadcastReceiver]注解静态注册,又在MainActivity手动注册会导致冲突,直接注释掉MainActivity中手动注册的代码。

4. 确认AndroidManifest.xml配置

确保权限已正确添加,Xamarin会自动处理注解的广播接收器,无需手动添加<receiver>节点:

<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />

5. 修正ViewModel中的MessagingCenter订阅逻辑

将日志输出移至订阅回调内,确保获取到验证码后再输出:

public class IRegisterSecondPageModel
{
    public string ActivationCode { get; private set; }

    public IRegisterSecondPageModel()
    {
        SubscribeToOtpReceiving();
    }

    private void SubscribeToOtpReceiving()
    {
        MessagingCenter.Subscribe<IRegisterSecondPageModel, string>(this, "OtpReceived", (sender, code) =>
        {
            ActivationCode = code;
            Console.WriteLine("Code : " + ActivationCode);
        });
    }
}

内容的提问来源于stack exchange,提问作者Gautham Mudaliar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 01:53:10