androidxamarinxamarin.androidxamarin-forms-4

Auto Read OTP in Xamarin Forms


I am trying to implement Auto Read OTP functionality in xamarin forms

I took reference from here but when a sms is received dependency is not triggered, debug point is put on the dependency but it does not get triggered.

I have tried the below code in dependency

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")]
    [IntentFilter(new string[] { "SMS_RECEIVED"})]
    public class SMSReceivedReceiver : BroadcastReceiver
    {
        private const string IntentAction = "SMS_RECEIVED";
        private static readonly string Sender = "SMS Sender number here";
        private static readonly string[] OtpMessageBodyKeywordSet = { "Keyword1", "Keyword2" }; //You must define your own Keywords
        public override void OnReceive(Context context, Intent intent)
        {
            try
            {
                if (intent.Action != IntentAction) return;
                var bundle = intent.Extras;
                if (bundle == null) return;
                var pdus = bundle.Get("pdus");
                // var castedPdus = JNIEnv.GetArray(pdus.Handle);
                var castedPdus = JNIEnv.GetArray<Object>(pdus.Handle);
                var msgs = new SmsMessage[castedPdus.Length];
                var sb = new StringBuilder();
                string sender = null;
                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;
                    sb.Append(string.Format("SMS From: {0}{1}Body: {2}{1}", msgs[i].OriginatingAddress,
                        System.Environment.NewLine, msgs[i].MessageBody));
                    //Toast.MakeText(context, sb.ToString(), ToastLength.Long).Show();
                    //Log.Error("Vahid", sb.ToString());

                    var msgBody = msgs[i].MessageBody;
                    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)
            {
                //Toast.MakeText(context, ex.Message, ToastLength.Long).Show();
            }
        }
        private static string ExtractNumber(string text)
        {
            if (string.IsNullOrEmpty(text)) return "";
            var regPattern = @"\d+";
            var number = Regex.Match(text, regPattern).Value;
            return number;
        }
    }
}
Manifest File
<uses-permission android:name="android.permission.RECEIVE_SMS" />
  <uses-permission android:name="android.permission.READ_SMS" />

MainActivity

private BroadcastReceiver _smsReceivedBroadcastReceiver;
protected override void OnResume()
        {
            base.OnResume();
            
            _smsReceivedBroadcastReceiver = new SMSReceivedReceiver();
            RegisterReceiver(_smsReceivedBroadcastReceiver, new IntentFilter("SMS_RECEIVED"));
}

This is the class file

public class IRegisterSecondPageModel
{
    public IRegisterSecondPageModel()
    {
        SubscribeToOtpReceiving();
    }

    public string ActivationCode { get; private set; }

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

This is xaml.cs file

IRegisterSecondPageModel ob = new IRegisterSecondPageModel();

This triggers the MessagingCenter.Subscribe

As far as i know for now if any message is received OnReceived method in the dependency should be triggered but it is not getting triggered if any one can help me with this it will be a big help


Solution

  • You can try to change the "SMS_RECEIVED" to "android.provider.Telephony.SMS_RECEIVED". Such as:

    namespace FinMobility.Droid.Dependency
    {
        [BroadcastReceiver(Enabled = true, Exported = true, Label = "SMS Receiver")]
        [IntentFilter(new string[] { "android.provider.Telephony.SMS_RECEIVED"})]
        public class SMSReceivedReceiver : BroadcastReceiver
        {
            private const string IntentAction = "android.provider.Telephony.SMS_RECEIVED";
    

    And the sms peermission is dangerous permission, you can use the following code to request it:

    if(AndroidX.Core.App.ActivityCompat.CheckSelfPermission(Xamarin.Essentials.Platform.CurrentActivity, Android.Manifest.Permission.ReadSms) != Permission.Granted)
    {
        AndroidX.Core.App.ActivityCompat.RequestPermissions(Xamarin.Essentials.Platform.CurrentActivity, new string[] { Android.Manifest.Permission.ReadSms }, 100);
    }
    

    Update:

    Please add the following code in the MainActivity:

    if(AndroidX.Core.App.ActivityCompat.CheckSelfPermission(Xamarin.Essentials.Platform.CurrentActivity, Android.Manifest.Permission.ReceiveSms) != Permission.Granted)
    {
        AndroidX.Core.App.ActivityCompat.RequestPermissions(Xamarin.Essentials.Platform.CurrentActivity, new string[] { Android.Manifest.Permission.ReceiveSms }, 100);
    }
    if(AndroidX.Core.App.ActivityCompat.CheckSelfPermission(Xamarin.Essentials.Platform.CurrentActivity, Android.Manifest.Permission.ReadSms) != Permission.Granted)
    {
        AndroidX.Core.App.ActivityCompat.RequestPermissions(Xamarin.Essentials.Platform.CurrentActivity, new string[] { Android.Manifest.Permission.ReadSms }, 101);
    }
    

    Update2: Here is my full code in the MainActivity:

    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
        {
            protected override void OnCreate(Bundle savedInstanceState)
            {
                base.OnCreate(savedInstanceState);
    
                Xamarin.Essentials.Platform.Init(this, savedInstanceState);
                global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
                LoadApplication(new App());
                if (AndroidX.Core.App.ActivityCompat.CheckSelfPermission(Xamarin.Essentials.Platform.CurrentActivity, Android.Manifest.Permission.ReceiveSms) != Permission.Granted)
                {
                    AndroidX.Core.App.ActivityCompat.RequestPermissions(Xamarin.Essentials.Platform.CurrentActivity, new string[] { Android.Manifest.Permission.ReceiveSms }, 101);
                }
                if (AndroidX.Core.App.ActivityCompat.CheckSelfPermission(Xamarin.Essentials.Platform.CurrentActivity, Android.Manifest.Permission.ReadSms) != Permission.Granted)
                {
                    AndroidX.Core.App.ActivityCompat.RequestPermissions(Xamarin.Essentials.Platform.CurrentActivity, new string[] { Android.Manifest.Permission.ReadSms }, 100);
                }
                RegisterReceiver(new SMSReceivedReceiver(), new Android.Content.IntentFilter("android.provider.Telephony.SMS_RECEIVED"));
            }
         ......
    }
    

    And the result image:

    enter image description here

    You can copy it to your project and test it on the smulator or some other devices.