How to automatically read SMS in Ionic 5 apps

How to automatically read SMS in Ionic 5 apps

In this post, we will learn how to read SMS in an Ionic app automatically. Reading SMS is a popular feature found in the majority of popular apps today. Mostly, this is used for automatic approval of OTP in authentication or online payment processes.

Traditionally SMS were read by SMS after asking for?READ_SMS?permission, but that has changed since the introduction of Retriever API from Google. More on that in further sections (Step 2).

What is Ionic?5?

You probably already know about Ionic, but I’m putting it here just for the sake of beginners.?Ionic?is a complete open-source SDK for hybrid mobile app development. Ionic provides tools and services for developing hybrid mobile apps using Web technologies like CSS, HTML5, and Sass.

So, in other words — If you create Native apps in Android — you code in Java. If you create Native apps in iOS — you code in Obj-C or Swift. Both of these are powerful but complex languages. With Ionic and Cordova/Capacitor you can write a single piece of code for your app that can run on both iOS and Android (and windows!), that too with the simplicity of HTML, CSS, and JS.

Why receive SMS automatically?

Apps can communicate in a number of ways. Most apps receive information from servers using push notifications. Push notification information can be easily processed by the apps automatically. (You can read my detailed blog on?how to include push notifications in an Ionic 5 app)

But on occasions, you get information via a third party service which can be delivered effectively only using SMS. For example, when making a credit card payment, you receive an SMS containing the OTP (one-time password) for the transaction. Modern apps automatically read the SMS and capture the OTP, and complete the transaction process. This brings in a huge UX boost, where the user doesn’t have to interact with the app for a long time to make the payment.

Another example is the?Login / authentication process. Apps which are mobile number centric, mostly allow users to register with their phone number. To validate if the user has the phone number he/she claims the app server sends an OTP, and the app can verify the OTP automatically to register the user, something like this?:

Structure

We are going to build a small Ionic 5 app with the SMS reading feature. Following are the steps we’ll take

  • Step 1 — Create a sample Ionic 5 app with dummy registration flow
  • Step 2 — App hash and retriever API
  • Step 3— Implement the Cordova plugin to read SMS
  • Step 4— Build the app on android device
  • Step 5— Test automatic SMS read to approve a sample registration

Let’s dive right in

Oops, wrong dive!

Step 1 — Create a sample Ionic 5?app

I have covered this topic in detail in?this blog.

In short, the steps you need to take here are

  • Make sure you have node installed in the system (V14.x at the time of this blog post)
  • Install?ionic cli?using npm (mine is Ionic 5.5 and NPM 7.x at the time of this post)
  • Create an Ionic app using?ionic start

You can create a?blank?starter for the sake of this tutorial. On running?ionic start appName blank?, node modules will be installed. Once the installation is done, run your app on browser using

$ ionic serve
        

Here is how the app will look like.

UI for Ionic automatic SMS read app

The UI is pretty simple for a registration screen. Here’s the flow

  • The user enters the?email?and?password?and clicks?“Next”
  • OTP input shows up. At this point, your server should send an SMS to this number. We will simulate this by sending SMS from another phone to our app build device. In a real-world scenario — you can use services like?Twilio?or?Firebase phone authentication?to generate the SMS during the auth process.
  • The app reads the SMS and fills it up in the OTP input. If in a real scenario, OTP is not automatically read, the user can always input it manually. But for demo purpose, we’ll keep the OTP input?read-only
  • Once OTP is received, you can proceed to?“Register”

I leave the UI (HTML + CSS) on you, you can make it anyway you like.

Step 2 — App Hash and Retriever API

Before setting up the plugin, let’s learn a little about App Hash and SMS retriever API.

Early android apps used a?READ_SMS?permission which allowed the app to read ALL SMS from your device. In 2020, Google released the SMS Retriever API that allows you to fetch the SMS without any permission from the app. That means you don’t have to give the app “Read SMS” permission, thereby avoiding any privacy issues. In fact,?READ_SMS?permission can now get your app rejected from app store, as this comes under?Dangerous permission?category. Hence the old plugins which used?READ_SMS?permission are now effectively deprecated.

The?SMS Retriever API helps in reading SMS without permission. It reads SMS based on?App Hash — An 11 digit unique hash string used for auto verifying SMS. Google Play Services utilizes the hash string to figure out which messages to send to your application.?

This unique hash can be different for different environments. For example, if an app is signed by a debug keystore for development the hash will be different from production build or if the app is signed by Google Play.

Reading SMS with App?Hash

To read SMS using retriever API, we should know the SMS syntax which the API can read correctly. A valid verification message might look like the following:


Your OTP is: 672838 /kkeid8sksd3
        

The last 11 digits alphanumeric character is the unique hash generated for the app. That 11 digits unique character is the main key which google play services reads for the SMS using the SMS Retriever API. So basically, you’ll need the App Hash on the server side, to be sent along with the SMS.

Generating App?Hash

Google has given exact instruction for generating Key hash on?this link. I will discuss this in short here.

For debug or production keystore, you can just use this command


$ keytool -exportcert -alias <<KEYSTORE_ALIAS>> -keystore <<KEYSTORE_PATH>>| xxd -p | tr -d "[:space:]" | echo -n <<APP_PACKAGE_NAME>>`cat` | sha256sum | tr -d "[:space:]-" | xxd -r -p | base64 | cut -c1-11
// output - uv+otVdzZzc <-- App Hash
        

Where, app_package_name is the bundle_ID, which looks like?com.enappd.readsms?.?If you use app signing by Google Play, follow?this link?for additional information.

Note — Do not make your app hash public

Now, we are ready to setup the plugins and implement SMS read feature in our app.

Step 3— Implement the Cordova plugin to read?SMS

For reading SMS via the Ionic 5 app, there are few plugins available.

We will implement the Ionic recommended plugin, but other plugins can work in your app as well.

To install the plugin, run


$ ionic cordova plugin add cordova-plugin-sms-retriever-manager

$ npm install @ionic-native/sms-retriever
        

Import the plugin in?app.module.ts?and add to providers array


import { SmsRetriever } from '@ionic-native/sms-retriever/ngx';
@NgModule({
... ,
  providers: [
     SmsRetriever, 
     { provide: RouteReuseStrategy,
     useClass:    IonicRouteStrategy 
     }
  ],
...
})
export class AppModule { }
        

Page flow

As the app starts, it redirects to?Login?page. Once the OTP is approved, you redirect to?Home?page. The?app-routing.module.ts?routes?object looks like below


const routes: Routes = [
{
  path: 'home',
  loadChildren: 
  () => import('./home/home.module').then(m =>    m.HomePageModule)
},
{
  path: 'login',
  loadChildren: 
  () => import('./login/login.module').then(m => m.LoginPageModule)
},
{
  path: '',
  redirectTo: 'login',
  pathMatch: 'full'
}
];
        

OTP Flow

Import the plugin in your?login.page.ts?using


import { SmsRetriever } from '@ionic-native/sms-retriever';
        

Now, there are two methods available with the plugin

  • getAppHash — Returns a promise that resolves when successfully generate hash of APP.


this.smsRetriever.getAppHash()
.then((res: any) => console.log(res))
.catch((error: any) => console.error(error))
        

This function gives the same App Hash as we generated in previous section.?

  • startWatching?—Returns a promise that resolves when retrieves SMS text or Times out after 5 min.


this.smsRetriever.startWatching()
.then((res: any) => console.log(res))
.catch((error: any) => console.error(error));
        

Overall, our?login.page.ts?looks like this


import { Component } from '@angular/core'
import { ToastController } from '@ionic/angular';
import { SmsRetriever } from '@ionic-native/sms-retriever/ngx';
import { Router } from '@angular/router';
	

@Component({
  selector: 'app-login',
  templateUrl: './login.page.html',
  styleUrls: ['./login.page.scss'],
})
	

export class LoginPage {
  OTP: string = '';
  showOTPInput: boolean = false;
  OTPmessage: string = 'An OTP is sent to your number. You should receive it in 15 s'
	  
     constructor
      (
       private router: Router,
       private toastCtrl: ToastController, 
       private smsRetriever: SmsRetriever
      ) {
	    this.smsRetriever.getAppHash()
	      .then((res: any) => console.log(res))
	      .catch((error: any) => console.error(error));
	  }
	

	  async presentToast(message, position, duration) {
	    const toast = await this.toastCtrl.create({
	      message: message,
	      position: position,
	      duration: duration
	    });
	    toast.present();
	  }
	

	  next() {
	    this.showOTPInput = true;
	    this.start();
	  }
	

	  start() {
	    this.smsRetriever.startWatching()
	      .then((res: any) => {
	        console.log(res);
	        this.processSMS(res);
	      })
	      .catch((error: any) => console.error(error));
	  }
	

	  processSMS(data) {
	    // Design your SMS with App hash so the retriever API can read the SMS without READ_SMS permission

	    // Attach the App hash to SMS from your server, Last 11 characters should be the App Hash

	    // After that, format the SMS so you can recognize the OTP correctly

	    // Here I put the first 6 character as OTP

	    const message = data.Message;
	    if (message != -1) {
	      this.OTP = message.slice(0, 6);
	      console.log(this.OTP);
	      this.OTPmessage = 'OTP received. Proceed to register';
	      this.presentToast(
            'SMS received with correct app hash',
            'bottom',
             1500
          );
	    }
	  }
	

	  register() {
	    if (this.OTP != '') {
	      this.presentToast(
              'You are successfully registered',
              'bottom',
               1500
          );
	      this.router.navigate(['/home'])
	    }
	    else {
	      this.presentToast('Your OTP is not valid', 'bottom', 1500);
	    }
	  }
};
        

Step 4— Build an app on android?device

If you have carried out the above steps correctly, the Android build should be a breeze. Run the following command to create an Android platform


$ ionic cordova platform add android
        

Once platform is added, run the app on device (Make sure you have a device attached to the system). You’ll need an actual SIM connection to receive SMS


$ ionic cordova run android
        

Once your app is up and running on the device, we’ll send SMS from another device simulating a server behavior, or use any other application to send SMS to your phone.

Step 5— Test automatic SMS reading to approve a sample registration

In case you missed it in Step 1, here are the steps again.

  • The user enters the Email and password and clicks?“Next”
  • OTP input shows up
  • At this point, send an SMS from another device to your build device
  • The app reads the SMS and fills it up in the OTP input
  • Once OTP is received, you can proceed to?“Register”

Conclusion

In this blog, you learned how to implement automatic SMS reading in an Ionic 5 app using SMS retrieve API. This API is safe in usage as it only reads the SMS meant for your particular app, using the App Hash.?

Automatic SMS reading is useful in modules like automatic OTP reading for authentication or automatic OTP reading for online transactions.

That’s all for this blog. This was quite a read, but a very interesting feature for your next Pro app.

Stay tuned for more Ionic blogs?!

Md Ashraful Islam

Software Engineer at Wafi Solutions

1 个月

start() { this.smsRetriever.startWatching() .then((res: any) => { console.log(res); this.processSMS(res); }) .catch((error: any) => console.error(error)); } In production, I got timeout error after 5 mins,

回复

要查看或添加评论,请登录

Vaibhav Gehani的更多文章

社区洞察

其他会员也浏览了