Written by: Tornike Kurdadze | Sat Jul 27 2024 Dart Extensions

What is SMS autofill?

SMS autofill is a feature that allows users to autofill OTP codes sent via SMS. This feature is available on both Android and iOS.

How to use SMS autofill in Flutter?

iOS

SMS autofill works out of the box on iOS. You don’t need to do anything to enable it. Just create a TextField and set the autofillHints property to AutofillHints.oneTimeCode.

TextField(
  autofillHints: const [
    AutofillHints.oneTimeCode,
  ],
);

The only thing you need to do is to send an SMS in the format that iOS expects.

Apple isn’t very clear about the format, but it seems that the message should:

  • Numeric Code Format: The OTP itself should be a numeric code (typically 4-6 digits) that can be easily recognized by the system.
  • Positioning: The numeric code should be placed prominently in the message, preferably at the beginning or right after a clear indicator that it is a code.
  • Clear Indicator: Use clear and consistent terminology to indicate that the numeric code is an OTP. For example, words like “code,” “OTP,” or “verification code” should be used.
  • Avoid Special Characters: Special characters and emojis should be avoided around the numeric code as they might interfere with the autofill detection.
  • Language and Spelling: Some languages might not be supported, so it’s better to use English.

Example:

Your verification code is 123456
Tu código de verificación es 123456

The result:

Dart extensions

Android

On Android we have two options to enable SMS autofill:

  • Using the SMS Retriever API
  • Using the SMS User Consent API

For both options, you need use native SDK, hopefully, there are plugins available for Flutter that make it easier to use these APIs. One of them is smart_auth. So let’s see how to use it.

Let’s start with the boring part

  1. Add the plugin to your Flutter project:
flutter pub add smart_auth
  1. Then, import the plugin in your Dart code:
import 'package:smart_auth/smart_auth.dart';
  1. Create an instance of SmartAuth
final smartAuth = SmartAuth();
  1. Let’s implement the removeSmsListener before we forget about it:
  @override
  void dispose() {
    smartAuth.removeSmsListener();
    super.dispose();
  }

Now the fun part, as I mentioned earlier, we have two options to enable SMS autofill on Android.

Implement the getSmsCode method:

void getSmsCode() async {
  final res = await smartAuth.getSmsCode(useUserConsentApi: true);
  if (res.codeFound) {
    debugPrint('userConsent success: ${res.code}');
    // Use the code to fill the TextField or do whatever you want
  } else {
    debugPrint('userConsent failed: $res');
  }
}

Note, that the SMS format is't really clear for Android as well so it's better to use the same format as for iOS

The result:

User Consent API

The SMS Retriever API is a bit more complex, but it’s easiest for the user.

Firstly, we need to get the App signature, you can use the following code to get it:

void getAppSignature() async {
  final res = await smartAuth.getAppSignature();
  debugPrint('Signature: $res');
}

Note that the signature is different for debug and release builds, so you need to run this code in release mode or use this guide

Then, the SMS you send should be in the following format:

Your verification code is: 123456
kg+TZ3A5qzS

Note that, the last line is the App signature

Now, let’s implement the getSmsCode method:

void getSmsCode() async {
  final res = await smartAuth.getSmsCode();
  if (res.codeFound) {
    debugPrint('userConsent success: ${res.code}');
    // Use the code to fill the TextField or do whatever you want
  } else {
    debugPrint('userConsent failed: $res');
  }
}

The result:

SMS Retriever API

That’s it! Now you can autofill OTP codes in your Flutter app on both Android and iOS.

Coffee makes me feel like I have my shit together 😀, so here you go 💙