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
相关产品推荐
相关产品推荐

