我想自动捕获或读取短信的 OTP。我做了一些类似这段代码的测试:
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),
),
],
),
)
);
}
}
这是测试短信:
12345 is your code to log in.
oneTimeCode 的 Flutter 文档: https://api.flutter.dev/flutter/services/AutofillHints/oneTimeCode-constant.html
IOS:https://developer.apple.com/documentation/uikit/uitextcontenttype
安卓: https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_SMS_OTP
希望对于还在寻找这个问题答案的人来说,我还不算太晚。我使用了两个包https://pub.dev/packages/alt_sms_autofill和https://pub.dev/packages/pin_code_fields。将这两个包添加到您的 pubspec.yaml 文件中。运行“flutter pub get”来下载包。
在您的 otp 屏幕中导入两个包:
import 'package:alt_sms_autofill/alt_sms_autofill.dart';
import 'package:pin_code_fields/pin_code_fields.dart';
在您的 AppState 扩展 State 之后,放置以下函数以获取传入的 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.
});
}
我传入的 OTP 消息格式如下所示: 您的手机验证码是625742. 在上面的函数中,它正在监听传入的短信并将其保存为一个字符串。收到短信后,我将“625742”代码设置到我的文本编辑控制器,方法是在字符串中给出代码的索引位置,然后将值设置到我的 PinFields,稍后您将看到。
在您的 initState 中调用函数:
@override
void initState() {
super.initState();
textEditingController1 = TextEditingController();
initSmsListener();
}
你应该在你的处理函数中处理你不使用的任何东西:
@override
void dispose() {
textEditingController1.dispose();
AltSmsAutofill().unregisterListener();
super.dispose();
}
然后您需要将 pinfields 放在构建函数中或像这样的列中:
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');
});
},
),
您可以使用这个包:https://pub.dev/packages/sms_autofill
但请考虑以下限制:
Android 短信约束 对于要接收的代码,需要遵循 此处描述的一些规则: https://developers.google.com/identity/sms-retriever/verify
不超过 140 字节 以前缀开头 <#> 包含一个 客户端发送回您的服务器以完成的一次性代码 验证流程以 11 个字符的哈希字符串结束 识别您的应用 SMS 的一个示例是:
<#> 示例应用程序:您的代码是 123456 FA+9qCX9VSu
我用这个
package
来接收短信检查
它的作用是通过它的监听器监听 SMS,当 SMS 到达时打印 SMS。
这是
Code
,我前段时间为此写过(我不确定这个包是否做了一些更改或更新,因为我已经有一段时间没有使用它了,但那时候它工作得很好.),
SmsReceiver receiver = new SmsReceiver();
await receiver.onSmsReceived.listen((SmsMessage msg) => checkSMS(msg));
SMS
体的打印方法,
checkSMS(SmsMessage msg) async {
print(msg.body);
}
现在您可以自动填充
SMS
并使用 OTP
中的一些 regex
取出 msg.body
并将其设置为 TextFieldController
文本以进行自动填充。
注意:它会获取每条短信,因此要获取唯一一条您需要的短信,您必须检查关键字或在您身边设置一些正则表达式以仅显示 OTP 消息或消息中的公司名称。
@Kamrul Hasan Jony 描述得很好。但是有一点应该记住,谁在实施这个。 在将 OTP 分配给控制器之前,您应该检查 app_Signature 或其他验证,以便 OTP 仅从特定的消息中获取。例如
setState(() {
_commingSms = commingSms;
String aStr = _commingSms.replaceAll(new RegExp(r'[^0-9]'),'');
String otp = aStr.substring(0,4);
if(_commingSms.contains(AppConstants.appSignature)){
textEditingController.text = otp;
//_presenter.validateOtp(widget.apiToken, widget.phone, textEditingController.text, context);
}
});
此外对于 iOS AltSmsAutofill().listenForSms 返回 iOS 版本(alt_sms_autofill: ^1.0.0)。因此,如果您在将 otp 分配给控制器之前使用某种验证,您将摆脱一切。
我使用 https://pub.dev/packages/sms_autofill 包来读取 OTP - 代码是
Pinput(
androidSmsAutofillMethod:
AndroidSmsAutofillMethod
.smsRetrieverApi,
listenForMultipleSmsOnAndroid:
true,
controller: otpController,
focusNode: otpFocus,
pinputAutovalidateMode:
PinputAutovalidateMode
.onSubmit,
inputFormatters: [
FilteringTextInputFormatter
.digitsOnly
],
validator: (value) {
if (value == "" ||
value == null ||
value.length < 4) {
otpFocus.unfocus();
return "Enter your 4 digit Otp";
}
if (otpError != '') {
return 'Invalid Otp';
}
return null;
},
onChanged: (pin) {
setState(() {
otpError = '';
});
},
onCompleted: (pin) async {
otpFocus.unfocus();
setState(() {
otpError = '';
});
btnVerifyController.start();
},
focusedPinTheme:
defaultPinTheme.copyWith(
decoration: defaultPinTheme
.decoration!
.copyWith(
borderRadius:
BorderRadius.circular(8),
border: Border.all(
color:
focusedBorderColor),
),
),
submittedPinTheme:
defaultPinTheme.copyWith(
decoration: defaultPinTheme
.decoration!
.copyWith(
color: fillColor,
borderRadius:
BorderRadius.circular(19),
border: Border.all(
color:
focusedBorderColor),
),
),
errorPinTheme: defaultPinTheme
.copyBorderWith(
border: Border.all(
color: Colors.redAccent),
),
),
我在登录页面调用了这个函数 var appSignatureID = await SmsAutoFill().getAppSignature; 我添加了这段代码并在小部件中使用了这个 appSignatureID 变量来显示 UI 中的值 - 并在内部测试中添加了该版本,因此我可以在 UI 中获取应用程序签名 ID 并且我注意到了它。 之后,我删除了在 UI 中显示的代码,并将该密钥发送到短信模板的后端