Read the SMS activation code automatically in Xamarin Forms instead of manually typing it by user

前端 未结 2 930
孤街浪徒
孤街浪徒 2021-01-03 13:27

I wrote a project with Xamarin Forms. When every user has signed up, I send him/her an activation Code to confirm it and the user has to insert it to enter the app. But I am

相关标签:
2条回答
  • 2021-01-03 14:04

    First add the required permissions in AndroidManifest:

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

    Here is SmsReceiver class in Android project:

    using System.Linq;
    using System.Text.RegularExpressions;
    using Android.App;
    using Android.Content;
    using Android.Runtime;
    using Android.Telephony;
    using Java.Lang;
    using Xamarin.Forms;
    namespace MyProject.Android
    {
        [BroadcastReceiver(Enabled = true, Label = "SMS Receiver")]
        [IntentFilter(new string[] { "android.provider.Telephony.SMS_RECEIVED", Intent.CategoryDefault })]
        public class SmsReceiver : BroadcastReceiver
        {
            private const string IntentAction = "android.provider.Telephony.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<RegisterSecondPageModel, string>(new RegisterSecondPageModel(), "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;
            }
    
        }
    }
    

    Note: In order to filter out the coming SMSes and detect only our own SMS we can apply these two filters:

    1- Ignoring all SMSes that their sender numbers are not our SMS sender number.

    2- Sometimes our SMS sender might send different SMSes to our clients, for example one SMS to send an activation code, and another to inform and confirm user's successfully registration in system. That said, we gotta distinguish them. For that we can search message body in order to find some pre-defined keywords. Of course our SMS server has to stick to a defined body format. "Activation", "Code", "Activation code" could be some example keywords in English language. Of course keywords should be defined in each language accordingly.

    Here is RegisterSecondPageModel inside PCL project:

    public class RegisterSecondPageModel
    {
      public RegisterSecondPageModel()
       {
         SubscribeToOtpReceiving();
       }
    
      private void SubscribeToOtpReceiving()
      {
         MessagingCenter.Subscribe<RegisterSecondPageModel, string>(this, "OtpReceived", (sender, code) =>
                        {
                            ActivationCode = code;
                        });
      }
    }
    

    Another note is that as Jason already said, iOS doesn't allow apps to read SMSes.

    0 讨论(0)
  • 2021-01-03 14:07

    If you're already sure about your clients having a SIM card in their device, then you can create a token and authenticate backwards, sending an SMS containing your token to from clients' device to your number.

    Pros:

    • No blocked numbers: Sending messages from client is not blocked even if you're on their blacklist or they're blocking advertisements and unknown senders.
    • No costs on your side for authentication.
    • This works also in iOS which you can't read but can send messages.

    Cons:

    • Client may be using another number in another device. This can be overcome by creating easy-to-type tokens which expire fast enough not to attract brute force attacks.
    • Client may not be able to send an SMS to your number due to several reasons including but not limited to not having enough account charge.
    0 讨论(0)
提交回复
热议问题