I want to catch or read OTP of SMS messages automatically. I did some tests like this code :
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Demo Auto OTP'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
TextEditingController _textController = TextEditingController();
String _error;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Multi-Factor-Authentication"),
),
body: Form(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: _textController,
autofillHints: [ AutofillHints.oneTimeCode ],
keyboardType: TextInputType.visiblePassword,
maxLength: 6,
maxLengthEnforced: true,
style: TextStyle(fontSize: 32),
),
RaisedButton(
child: Text("Verify"),
onPressed: () => Navigator.of(context).pop(_textController.value.text),
),
],
),
)
);
}
}
And this is the test SMS message : 12345 is your code to log in.
Flutter documentation for oneTimeCode: https://api.flutter.dev/flutter/services/AutofillHints/oneTimeCode-constant.html
Flutter Autofill : https://github.com/flutter/flutter/blob/7891006299/packages/flutter/lib/src/services/autofill.dart#L362
IOS : https://developer.apple.com/documentation/uikit/uitextcontenttype
Android : https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_SMS_OTP
I hope I am not too late for people who are still looking for an answer to this question. I have used two packages https://pub.dev/packages/alt_sms_autofill and https://pub.dev/packages/pin_code_fields. Add these two packages to your pubspec.yaml file. Run 'flutter pub get' to download the packages.
In your otp screen import both packages:
import 'package:alt_sms_autofill/alt_sms_autofill.dart';
import 'package:pin_code_fields/pin_code_fields.dart';
After your AppState extends State put the following function to grab incoming SMS:
TextEditingController textEditingController1;
String _comingSms = 'Unknown';
Future<void> initSmsListener() async {
String comingSms;
try {
comingSms = await AltSmsAutofill().listenForSms;
} on PlatformException {
comingSms = 'Failed to get Sms.';
}
if (!mounted) return;
setState(() {
_comingSms = comingSms;
print("====>Message: ${_comingSms}");
print("${_comingSms[32]}");
textEditingController1.text = _comingSms[32] + _comingSms[33] + _comingSms[34] + _comingSms[35]
+ _comingSms[36] + _comingSms[37]; //used to set the code in the message to a string and setting it to a textcontroller. message length is 38. so my code is in string index 32-37.
});
}
My incoming OTP Message Format looks like this: Your phone verification code is 625742. In the above function, it is listening to incoming sms and saving it to a string. After the sms has been received, I am setting the '625742' code to my textEditing controller by giving the index position of the code in the string which then sets the value to my PinFields which you will see later.
Call functions in your initState:
@override
void initState() {
super.initState();
textEditingController1 = TextEditingController();
initSmsListener();
}
You should dispose anything you are not using inside your dispose function:
@override
void dispose() {
textEditingController1.dispose();
AltSmsAutofill().unregisterListener();
super.dispose();
}
Then you need to put the pinfields in your build function or inside a column like this:
PinCodeTextField(
appContext: context,
pastedTextStyle: TextStyle(
color: Colors.green.shade600,
fontWeight: FontWeight.bold,
),
length: 6,
obscureText: false,
animationType: AnimationType.fade,
pinTheme: PinTheme(
shape: PinCodeFieldShape.box,
borderRadius: BorderRadius.circular(10),
fieldHeight: 50,
fieldWidth: 40,
inactiveFillColor: Colors.white,
inactiveColor: ColorUtils.greyBorderColor,
selectedColor: ColorUtils.greyBorderColor,
selectedFillColor: Colors.white,
activeFillColor: Colors.white,
activeColor: ColorUtils.greyBorderColor
),
cursorColor: Colors.black,
animationDuration: Duration(milliseconds: 300),
enableActiveFill: true,
controller: textEditingController1,
keyboardType: TextInputType.number,
boxShadows: [
BoxShadow(
offset: Offset(0, 1),
color: Colors.black12,
blurRadius: 10,
)
],
onCompleted: (v) {
//do something or move to next screen when code complete
},
onChanged: (value) {
print(value);
setState(() {
print('$value');
});
},
),
Make sure to set controller to the pinfield widget and after you receive the sms use string indexs to set the code to your textfield. See the below image for example.
You may use this package: https://pub.dev/packages/sms_autofill
But consider the following limits:
Android SMS constraint For the code to be receive, it need to follow some rules as describe here: https://developers.google.com/identity/sms-retriever/verify
Be no longer than 140 bytes Begin with the prefix <#> Contain a one-time code that the client sends back to your server to complete the verification flow End with an 11-character hash string that identifies your app One example of SMS would be:
<#> ExampleApp: Your code is 123456 FA+9qCX9VSu
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With