Search code examples
androidxamarin.androidbroadcastreceiversms

Receive verification token as sms in Xamarin.Android


I need to create the registration for my application. I have created the sms sending server, so I can:

  1. Click on the button "Send SMS"
  2. After that, I receive the SMS with the token.
  3. I can enter this token into EditText element.
  4. Click the button "Verify".
  5. And the token will be verified.

But now I need this token automatically placed from SMS into application's text box.

  1. Click on the button "Send SMS"
  2. After that, I receive the SMS with the token.
  3. The token automatically places into EditText.
  4. And the token is verified automatically too.

I try to use BroadcastReceiver, and it works for SMS. I can show the text like following:

using Android.App;
using Android.Content;
using Android.Telephony;
using Android.Widget;

namespace ReceiveMsg
{
    [BroadcastReceiver]
    [IntentFilter(
    new[] { "android.provider.Telephony.SMS_RECEIVED" }, Priority =(int)IntentFilterPriority.HighPriority)]
public class SmsReceiver : BroadcastReceiver
{

    public static readonly string INTENT_ACTION = "android.provider.Telephony.SMS_RECEIVED";
    protected string message, address = "";

    public override void OnReceive(Context context, Intent intent)
    {
        if(intent.HasExtra("pdus"))
        {
            var smsArray = (Java.Lang.Object[])intent.Extras.Get("pdus");
            foreach(var item in smsArray)
            {
                var sms = SmsMessage.CreateFromPdu((byte[])item);
                address = sms.OriginatingAddress;
                message = sms.MessageBody;
                Toast.MakeText(context, "Number: " + address + "Message: " + message, ToastLength.Short).Show();

            }
        }
    }
}

}

But how can I put the token from SMS into the token place automatically?

I need at first place to show the user Permission manager window for the confirmation, right?

So I added this in my AndroidManifest:

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

The user allows use this SMS.
The token parsed from SMS and will be stored inside the variable and will be shown inside the Textbox.

There is a token variable in the viewmodel.cs.
So I add public interface SmsListener here:

    private string _token;
    private bool _isSuccessed, _isInvalid;
    private readonly IMvxNavigationService _navigationService;

    public bool IsSucceeded
    {
        get
        {
            return _isSuccessed;
        }
        set
        {
            _isSuccessed = value;
            RaisePropertyChanged(() => IsSucceeded);
        }
    }
    public bool IsInvalid
    {
        get
        {
            return _isInvalid;
        }
        set
        {
            _isInvalid = value;
            RaisePropertyChanged(() => IsInvalid);
        }
    }

    public string Token
    {
        get
        {
            return _token;
        }
        set
        {
            _token = value;
            RaisePropertyChanged(() => Token);
        }
    }

    public VerificationViewModel(IMvxNavigationService navigationService)
    {
        _navigationService = navigationService;

        VerifyCommand = new MvxAsyncCommand(async () => {
            IsSucceeded = await RegistrationService.VerifyToken(Token);
            IsInvalid = !IsSucceeded;
        });

    }

    public IMvxAsyncCommand VerifyCommand { get; private set; }

    public interface SmsListener
        {
        void MessageReceived(string messageText);
        }

But I still don't understand how to use listener inside SmsReceiver

How can I summarize it? In order, the user will be able to allow to use this SMS and trust the automated process?


Solution

  • I need at first place to show the user Permission manager window for the confirmation, right?

    Yes, if your target version >6.0, you need Request App Permissions.

    how can I put the token from SMS into the token place automatically?

    You can use Interface to achieve it. Please refer to this article.


    1) You need define an interface, like the SmsListener:

    public interface SmsListener {
            public void messageReceived(string messageText);
    }
    

    2) In your SmsReceiver, you need call it when you get the MessageBody;

    3) Implement the interface in your Activity which contain the EditText, and in the interface's messageReceived method to update the EditText's text.

    Note:

    Don't forget use bindListener method or other method to instantiate your interface.

    Update

    SmsReceiver:

    namespace ReceiveMsg
    {
        [BroadcastReceiver]
        [IntentFilter(new[] { "android.provider.Telephony.SMS_RECEIVED" }, Priority =(int) IntentFilterPriority.HighPriority)] 
        public class SmsReceiver : BroadcastReceiver
        {
    
            public static readonly string INTENT_ACTION = "android.provider.Telephony.SMS_RECEIVED";
            protected string message, address = "";
            private OnReceiveSMSListener mOnReceiveSMSListener;//add interface
            public override void OnReceive(Context context, Intent intent)
            {
                if (intent.HasExtra("pdus"))
                {
                    var smsArray = (Java.Lang.Object[])intent.Extras.Get("pdus");
                    foreach (var item in smsArray)
                    {
                        var sms = SmsMessage.CreateFromPdu((byte[])item);
                        address = sms.OriginatingAddress;
                        message = sms.MessageBody;
                        Toast.MakeText(context, "Number: " + address + "Message: " + message, ToastLength.Short).Show();
                        // call the interface if you get the message
                        mOnReceiveSMSListener.onReceived(message);
                    }
                }
            }
    
            // interface
            public interface OnReceiveSMSListener
            {
                void onReceived(String message);
            }
            //used in activity
            public void setOnReceiveSMSListener(OnReceiveSMSListener onReceiveSMSListener)
            {
                mOnReceiveSMSListener = onReceiveSMSListener;
            }
        }
    }
    

    Activity:

       public class MainActivity : Activity,SmsReceiver.OnReceiveSMSListener
        {
            private SmsReceiver mSMSBroadcastReceiver = new SmsReceiver();
            private EditText mEt_code;
            public void onReceived(string message)
            {
                mEt_code.Text=message + "";
            }
    
            protected override void OnCreate(Bundle savedInstanceState)
            {
                base.OnCreate(savedInstanceState);
    
                // Set our view from the "main" layout resource
                SetContentView(Resource.Layout.Main);
                mEt_code = (EditText)FindViewById(Resource.Id.et_code);
                mSMSBroadcastReceiver.setOnReceiveSMSListener(this);
            }
        }
    

    Manifest:

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