Flutter一次性密码服务插件otp_service的使用
Flutter一次性密码服务插件otp_service的使用
本插件旨在帮助开发者在Flutter应用中集成一次性密码(One-Time Password)功能。通过该插件,用户可以轻松实现短信验证码、邮件验证码等功能。
开始使用
首先,确保你已经添加了otp_service
插件到你的pubspec.yaml
文件中:
dependencies:
otp_service: ^1.0.0
然后运行flutter pub get
以安装依赖。
完整示例代码
以下是一个完整的示例代码,展示了如何在Flutter应用中使用otp_service
插件。
示例代码
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:otp_service/otp_service.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _isLimited = false;
int _countTime = 0;
late Timer _timer;
String _error = '';
String _otp = '';
final _focusNode = FocusNode();
[@override](/user/override)
void initState() {
super.initState();
_otp = '';
_countTime = 60;
_isLimited = false;
_startTimer();
}
[@override](/user/override)
void dispose() {
_timer.cancel();
super.dispose();
}
void _startTimer() {
const oneSec = Duration(seconds: 1);
_timer = Timer.periodic(
oneSec,
(Timer timer) {
if (_countTime == 0) {
setState(() {
timer.cancel();
});
} else {
setState(() {
_countTime--;
});
}
},
);
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(
appBar: AppBar(
title: const Text('OTP 示例'),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
OTPWidgetService(
onKeyboard: (isShow) {
debugPrint('onKeyboard: $isShow');
},
errorString: _error,
errorTextStyle: TextStyle(color: Colors.red[300]),
lineColor: Colors.black26,
onTap: () {
debugPrint('onTap');
},
onChanged: (otp) {
_otp = otp;
debugPrint('OTP: $otp');
setState(() {
_error = '';
});
},
textStyle: TextStyle(color: Colors.black, fontSize: 36),
),
const SizedBox(height: 16),
OutlinedButton(
onPressed: () {
setState(() {
_error = _otp.isEmpty ? '此字段是必需的。' : _otp.length < 6 ? '验证码无效。' : '';
});
},
child: Text("验证"),
),
const SizedBox(height: 16),
if (_countTime > 0)
RichText(
text: TextSpan(
children: [
TextSpan(
text: _isLimited
? '重发限制已达到。您可以在24小时后重新发送验证码('
: '您可以在',
style: TextStyle(color: Colors.black)),
TextSpan(
text: _isLimited ? formatOTPTime : formatOTPTimeNotHour,
style: TextStyle(color: Colors.black26)),
TextSpan(
text: _isLimited ? ')秒后重试。' : '秒后重试。',
style: TextStyle(color: Colors.black)),
],
),
)
else
OutlinedButton(
onPressed: () {
_countTime = 60;
_startTimer();
},
child: Text("重新发送验证码"),
),
const SizedBox(height: 16),
],
),
),
),
),
),
);
}
Widget buildNoteWidget() {
return RichText(
text: TextSpan(
children: [
TextSpan(
text: _isLimited
? '重发限制已达到。您可以在24小时后重新发送验证码('
: '您可以在',
style: TextStyle(color: Colors.black),),
TextSpan(
text: _isLimited ? formatOTPTime : formatOTPTimeNotHour,
style: TextStyle(color: Colors.black54)),
TextSpan(
text: _isLimited ? ')秒后重试。' : '秒后重试。',
style: TextStyle(color: Colors.black)),
],
),
);
}
String get formatOTPTime => _formatOTPTime();
String get formatOTPTimeNotHour => _formatOTPTime(isFull: false);
String _formatOTPTime({bool isFull = true}) {
final duration = Duration(seconds: _countTime);
String twoDigits(int n) => n.toString().padLeft(2, '0');
final hours = twoDigits(duration.inHours);
final minutes = twoDigits(duration.inMinutes.remainder(60));
final seconds = twoDigits(duration.inSeconds.remainder(60));
return [if (isFull) hours, minutes, seconds].join(':');
}
}
代码解释
-
导入必要的库
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:otp_service/otp_service.dart';
-
主函数
void main() { runApp(const MyApp()); }
-
定义主应用状态
class MyApp extends StatefulWidget { const MyApp({super.key}); [@override](/user/override) State<MyApp> createState() => _MyAppState(); }
-
定义状态类
class _MyAppState extends State<MyApp> { bool _isLimited = false; int _countTime = 0; late Timer _timer; String _error = ''; String _otp = ''; final _focusNode = FocusNode(); [@override](/user/override) void initState() { super.initState(); _otp = ''; _countTime = 60; _isLimited = false; _startTimer(); } [@override](/user/override) void dispose() { _timer.cancel(); super.dispose(); }
-
启动计时器
void _startTimer() { const oneSec = Duration(seconds: 1); _timer = Timer.periodic( oneSec, (Timer timer) { if (_countTime == 0) { setState(() { timer.cancel(); }); } else { setState(() { _countTime--; }); } }, ); }
-
构建应用UI
[@override](/user/override) Widget build(BuildContext context) { return MaterialApp( home: GestureDetector( onTap: () => FocusScope.of(context).unfocus(), child: Scaffold( appBar: AppBar( title: const Text('OTP 示例'), ), body: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, children: [ OTPWidgetService( onKeyboard: (isShow) { debugPrint('onKeyboard: $isShow'); }, errorString: _error, errorTextStyle: TextStyle(color: Colors.red[300]), lineColor: Colors.black26, onTap: () { debugPrint('onTap'); }, onChanged: (otp) { _otp = otp; debugPrint('OTP: $otp'); setState(() { _error = ''; }); }, textStyle: TextStyle(color: Colors.black, fontSize: 36), ), const SizedBox(height: 16), OutlinedButton( onPressed: () { setState(() { _error = _otp.isEmpty ? '此字段是必需的。' : _otp.length < 6 ? '验证码无效。' : ''; }); }, child: Text("验证"), ), const SizedBox(height: 16), if (_countTime > 0) RichText( text: TextSpan( children: [ TextSpan( text: _isLimited ? '重发限制已达到。您可以在24小时后重新发送验证码(' : '您可以在', style: TextStyle(color: Colors.black)), TextSpan( text: _isLimited ? formatOTPTime : formatOTPTimeNotHour, style: TextStyle(color: Colors.black26)), TextSpan( text: _isLimited ? ')秒后重试。' : '秒后重试。', style: TextStyle(color: Colors.black)), ], ), ) else OutlinedButton( onPressed: () { _countTime = 60; _startTimer(); }, child: Text("重新发送验证码"), ), const SizedBox(height: 16), ], ), ), ), ), ), ); }
-
其他辅助方法
Widget buildNoteWidget() { return RichText( text: TextSpan( children: [ TextSpan( text: _isLimited ? '重发限制已达到。您可以在24小时后重新发送验证码(' : '您可以在', style: TextStyle(color: Colors.black),), TextSpan( text: _isLimited ? formatOTPTime : formatOTPTimeNotHour, style: TextStyle(color: Colors.black54)), TextSpan( text: _isLimited ? ')秒后重试。' : '秒后重试。', style: TextStyle(color: Colors.black)), ], ), ); } String get formatOTPTime => _formatOTPTime(); String get formatOTPTimeNotHour => _formatOTPTime(isFull: false); String _formatOTPTime({bool isFull = true}) { final duration = Duration(seconds: _countTime); String twoDigits(int n) => n.toString().padLeft(2, '0'); final hours = twoDigits(duration.inHours); final minutes = twoDigits(duration.inMinutes.remainder(60)); final seconds = twoDigits(duration.inSeconds.remainder(60)); return [if (isFull) hours, minutes, seconds].join(':'); }
更多关于Flutter一次性密码服务插件otp_service的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter一次性密码服务插件otp_service的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
otp_service
是一个用于在 Flutter 应用中生成和处理一次性密码(OTP)的插件。它可以帮助你实现基于时间的 OTP(TOTP)或基于计数器的 OTP(HOTP),广泛应用于双因素认证(2FA)场景。
以下是如何在 Flutter 项目中使用 otp_service
插件的步骤:
1. 添加依赖
首先,你需要在 pubspec.yaml
文件中添加 otp_service
插件的依赖:
dependencies:
flutter:
sdk: flutter
otp_service: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get
来安装依赖。
2. 导入插件
在需要使用 OTP 服务的 Dart 文件中导入 otp_service
插件:
import 'package:otp_service/otp_service.dart';
3. 生成 OTP
使用 OtpService
类来生成 OTP。你可以生成基于时间的 OTP(TOTP)或基于计数器的 OTP(HOTP)。
生成 TOTP
String secret = 'JBSWY3DPEHPK3PXP'; // 你的密钥
int period = 30; // 有效期(秒)
int digits = 6; // OTP 位数
String totp = OtpService.generateTOTP(secret, period, digits);
print('Generated TOTP: $totp');
生成 HOTP
String secret = 'JBSWY3DPEHPK3PXP'; // 你的密钥
int counter = 1; // 计数器值
int digits = 6; // OTP 位数
String hotp = OtpService.generateHOTP(secret, counter, digits);
print('Generated HOTP: $hotp');
4. 验证 OTP
你可以使用 OtpService
来验证用户输入的 OTP 是否正确。
验证 TOTP
String userInput = '123456'; // 用户输入的 OTP
String secret = 'JBSWY3DPEHPK3PXP'; // 你的密钥
int period = 30; // 有效期(秒)
int digits = 6; // OTP 位数
bool isValid = OtpService.validateTOTP(userInput, secret, period, digits);
print('Is TOTP valid? $isValid');
验证 HOTP
String userInput = '123456'; // 用户输入的 OTP
String secret = 'JBSWY3DPEHPK3PXP'; // 你的密钥
int counter = 1; // 计数器值
int digits = 6; // OTP 位数
bool isValid = OtpService.validateHOTP(userInput, secret, counter, digits);
print('Is HOTP valid? $isValid');
5. 处理 OTP URI
otp_service
还支持解析和生成 OTP URI,通常用于二维码生成和扫描。
解析 OTP URI
String otpUri = 'otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example&algorithm=SHA1&digits=6&period=30';
OtpUri parsedUri = OtpService.parseOtpUri(otpUri);
print('Secret: ${parsedUri.secret}');
print('Issuer: ${parsedUri.issuer}');
print('Algorithm: ${parsedUri.algorithm}');
print('Digits: ${parsedUri.digits}');
print('Period: ${parsedUri.period}');
生成 OTP URI
String otpUri = OtpService.generateOtpUri(
type: OtpType.totp,
secret: 'JBSWY3DPEHPK3PXP',
issuer: 'Example',
accountName: 'alice@google.com',
algorithm: 'SHA1',
digits: 6,
period: 30,
);
print('Generated OTP URI: $otpUri');
6. 处理异常
在使用 otp_service
时,可能会遇到一些异常情况,例如无效的密钥或 URI。你可以使用 try-catch
块来处理这些异常:
try {
String totp = OtpService.generateTOTP(secret, period, digits);
print('Generated TOTP: $totp');
} catch (e) {
print('Error generating TOTP: $e');
}
7. 完整示例
以下是一个完整的示例,展示了如何使用 otp_service
生成和验证 TOTP:
import 'package:flutter/material.dart';
import 'package:otp_service/otp_service.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('OTP Service Example'),
),
body: Center(
child: OTPExample(),
),
),
);
}
}
class OTPExample extends StatelessWidget {
final String secret = 'JBSWY3DPEHPK3PXP';
final int period = 30;
final int digits = 6;
[@override](/user/override)
Widget build(BuildContext context) {
String totp = OtpService.generateTOTP(secret, period, digits);
bool isValid = OtpService.validateTOTP(totp, secret, period, digits);
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Generated TOTP: $totp'),
SizedBox(height: 20),
Text('Is TOTP valid? $isValid'),
],
);
}
}