NEW ANSWER (as of June '23):
We will be using this package to autofill sms otp: https://pub.dev/packages/sms_autofill. Add it to your pubspec.yaml.
First of all make sure the sms you are receiving in your android phones should contain '<#>' at the beginning of the sms and you app signature key at the end of the sms. An example sms should look like:
<#> You otp code is 543216 app_signature.
There are multiple ways to generate app signature key, you can also use the sms_autofill package to get your app signature key using the below code:
await SmsAutoFill().getAppSignature;
It will return you your app signature in a String format, just add it at the end of your sms. You can remove the above code or ignore it if you already have your app signature.
First lets draw the widget:
PinFieldAutoFill(
decoration: BoxLooseDecoration(
strokeColorBuilder: PinListenColorBuilder(Colors.black, Colors.black26),
bgColorBuilder: const FixedColorBuilder(Colors.white),
strokeWidth: 2,
),
autoFocus: true,
cursor: Cursor(color: Colors.red, enabled: true, width: 1),
currentCode: '',
onCodeSubmitted: (code) {},
codeLength: 6,
onCodeChanged: (code) {
print(code);
},
),
Then in your onInit() state listen for sms code:
await SmsAutoFill().listenForCode();
This will listen for the SMS with the code during 5 minutes and when received, autofill the above widget.
In your onDispose method do not forget to dispose the listener:
SmsAutoFill().unregisterListener();
OLD ANSWER:
This answer can be used if someone wants to read an user's sms. Also, if you use the bottom implementation PlayStore might reject your app if you do not provide proper explanation on why you would like to read an user's sms. 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.