Company Updates

How to Implement SMS Verification Codes Auto-Fill in React Native Android Apps

Problem overview

This article discusses my experience developing the solution, as well as my experience creating an open-source NPM package for React Native.

React Native SMS User Consent

The Solution

Part 1 — Our Approach

How to Start

Want to read this story later? Save it in Journal.

Additionally, to upload the solution to NPM, we will use the NPM CLI and a package builder. This process is described in Part 2 of this tutorial.

Here we will learn how the module was implemented. It’s considered that it was implemented within an app as opposed to as an external package.

Step 1 — Setting Up the Module

Step 2 — Implementing the Native Android Part

To view the actual code I ended up with, please see the subscribe method of ReactNativeSmsUserConsentModule.java, which also involves SmsBroadcastReceiver.java and SmsListener.java files that are part of the implementation.

Now we have the core of our solution, but we need some more control and convenience for real-life purposes. There are a couple more methods addressing this:

  • unsubscribe. Removes the listener and stops showing SMS User Consent modal when the SMS is received. This is a crucial method that covers such cases as when the user left the code entry screen before the SMS is received.
  • resubscribe. Since the subscribe method basically handles only one SMS and not any more, we need to unsubscribe and subscribe again every time in order to receive another one. This method handles this, making it a bit easier and safer because there is no space for errors like not calling unsubscribe and only calling subscribe and so on. Also, it catches exceptions in these two methods making it even safer. Furthermore, resubscribe is called automatically when an SMS is handled, which we will examine in the next step, so users of the package don’t need to care about re-subscribing after every single SMS. This is a huge convenience that simplifies life for the React side of the question. This, in particular, makes the final API dramatically simpler.

Step 3 — Connecting Native with React and Creating Wrapper Methods

Now we have a way to start and stop listening to SMS from the React side, but we don’t have a way of getting the SMS content when the SMS is received. Let’s add such a way. We receive the SMS text in SmsListener.java. So we create the handleSms method in ReactNativeSmsUserConsentModule.java and call it from the SmsListener.java with the SMS text as the parameter. This is how our main class receives the SMS text. After that, we emit the event using React Native’s standard native event emitter from the sendSmsEventToJs method which is created specifically for this purpose, and this is how the React side gets the SMS text. Also within the handleSms method we call resubscribe so that our code is insta-ready to receive another SMS with a verification code.

Here is how the native part looks:

React Native SMS User Consent — native flow diagram

Now, on the JS-side, we use these methods to form the actual API. Basically, it can be any file. In our package, the API lives in the src/ folder. Let’s shed light on key files in it:

  • index.android.jsAndroid-only entry point that aggregates all the API methods and exports them.
  • index.ios.js. iOS-only entry point. Since the package is Android-only, we export no-op methods from here, handling iOS for users so that they won’t have to write additional code to handle iOS.
  • nativeApi.js. The core file, which is basically the bridge connecting the Native part with the JS part. It imports NativeEventEmitter and NativeModules objects, handles them, and exports ReactNativeSmsUserConsent (the file containing native methods we exposed using @ReactMethod) and eventEmitter objects that are used by other files.
  • startSmsHandling.js. Another core file that imports ReactNativeSmsUserConsent from nativeApi.js and wraps its startNativeSmsListener and stopNativeSmsListener methods to use in JavaScript.

Now, with the startSmsHandling API method we created, users can add the auto-fill functionality to their apps:

Though this is still not optimal, we’ll examine this in the next (the last) step.

Step 4 — Implementing Convenience Methods

There are two things:

  1. Since the SMS User Consent API provides the whole SMS text and we only need a code from it, it’s a must-have function to parse the code from the SMS (retrieveVerificationCode in the example). And instead of making our users implement it, we implement it for them and provide it as a util method so that they won’t have to bother with it. Users can pass a second argument that specifies the code length, which is 6 by default.
  2. Finally, having all the enhancements we made on native and JS parts, we can leverage code that users have to write to a single line. Since the usage is quite predictable and there is not much space for variability, we can abstract the entire boilerplate by implementing a React hook that controls everything and just provides the verification code once it is received. Actually, this is exactly what I was looking for when searching for a solution, because it’s the most convenient and easy way for a user. This is what useSmsUserConsent hook is. It provides all the quite huge functionality we implemented in previous steps and compresses all the complexity into one simple React hook call:
    const code = useSmsUserConsent();

And now, the package can be used in the following way:

Here is a simple diagram showing the flow:

React Native SMS User Consent flow diagram

Part 2 — How to Market

Step 1 — Create a Dummy React Native Package

So, “create-react-native-module” generated a minimal package that can already be uploaded to NPM and used. It added all the necessary files, including package.json, Android build config and dummy implementation files on native and JS side.

Step 2 — Add the Implementation

package com.akvelon.reactnativesmsuserconsent;

I recommend editing files in Android Studio so that you can see all the warnings it provides and fix them.

Once we added the native files, we should add the React side files. index.js is the entry point, so we add js files based on it. One more thing is to make sure we populated all the needed fields in package.json. For details, please see package.json docs.

After we have added all the implementation files and populated meta-information, we can test the package by installing it to the example app. Considering that the example app is located in a folder inside our package, the command for installation is:

yarn install file:../

This is a good point of time to provide QA and make sure everything works when you use the installed package. Also, it’s a good idea to write an informative README file that describes how to use your package, its API, etc.

After that, the package is ready to publish.

Step 3 — Publication

  1. Register on NPM if you’re not registered already;
  2. From the terminal, run npm login and enter your NPM credentials;
  3. Run npm publish —-access public command from the root of your package.

To publish further versions, use the npm version command and then run npm publish.

Once the package is published, you can test it by installing the uploaded package from NPM. Also, it is a good idea to have its source code on GitHub, so that users could learn it, ask questions, open issues, make contributions, etc.

Now I am in maintenance mode, looking forward to feedback, and ready to help or answer questions, which can be asked in comments section of the original article post.

About us

If you would like to work with our strong Akvelon team — please see our open positions.

Written in collaboration with Nail Shakirov

This article was originally published on Medium by Eldar Abdullazyanov, a Frontend and React Native Developer at Akvelon.