Flutter自动登录插件autologin_darwin的使用
Flutter自动登录插件autologin_darwin的使用
该插件实现了iOS和macOS平台上的自动登录功能。你可以通过以下方式来使用它。
使用
此包是被推荐使用的,这意味着你可以在项目中直接使用autologin
。当你这样做的时候,此包会自动包含在你的应用中,所以你不需要在pubspec.yaml
文件中添加它。
但是,如果你导入此包以直接使用其任何API,则应像往常一样将其添加到pubspec.yaml
文件中。
安装
为了存储凭证,此插件使用了共享网络凭据。为了使这正常工作,你需要设置关联域授权。主要文档可以在Apple开发者网站上找到。至少apple-app-site-association
文件必须在https://<your-domain>/.well-known/apple-app-site-association
可访问,并且必须包含如下内容:
{
"webcredentials": {
"apps": [
"<your-team-id>.<your-bundle-id>"
]
}
}
你的团队ID可以在ios/Runner.xcodeproj/project.pbxproj
中找到,例如,在DEVELOPMENT_TEAM
键下查找;而包ID可以在PRODUCT_BUNDLE_IDENTIFIER
键下查找。Apple会用其CDN缓存对上述文件的请求,但你可以在这里检查缓存值:https://app-site-association.cdn-apple.com/a/v1/<your-domain>
。
如果你还没有设置你的应用,请检查Apple开发者资源。
为了在iOS和macOS上使用零触登录,你需要添加iCloud能力并在Xcode项目中配置iCloud键值存储。以下是逐步指南:
- 打开你的Xcode项目。
- 在项目导航器中选择你的项目以打开项目设置。
- 在“目标”下选择你的目标。
- 转到“签名与功能”选项卡。
- 点击“+ 功能”按钮。
- 滑动并选择“iCloud”。
- 在iCloud部分中,勾选“键值存储”。
示例代码
以下是一个完整的示例代码,展示了如何在Flutter应用中使用autologin
插件。
import 'dart:async';
import 'package:autologin/autologin.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const DemoFrame());
}
/// 这个框架只是为了确保DemoPage有一个可以显示snackbar的上下文
class DemoFrame extends StatelessWidget {
const DemoFrame({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Autologin-Plugin 示例应用'),
),
body: const SingleChildScrollView(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 24),
child: Align(
child: SizedBox(
width: 400,
child: DemoPage(),
),
),
),
),
);
}
}
class DemoPage extends StatefulWidget {
const DemoPage({super.key});
[@override](/user/override)
State<DemoPage> createState() => _DemoPageState();
}
/// 大多数这些状态字段只是为了调试发生了什么
class _DemoPageState extends State<DemoPage> {
bool? isPlatformSupported;
String? usernameNote;
String? passwordNote;
bool obscurePassword = true;
final usernameController = TextEditingController();
final passwordController = TextEditingController();
String loginToken = '加载中...';
[@override](/user/override)
void initState() {
super.initState();
unawaited(initPlatformState());
usernameController.addListener(resetUsernameNote);
passwordController.addListener(resetPasswordNote);
AutologinPlugin.setup(
domain: 'rekire.github.io',
appId: 'eu.rekisoft.flutter.autologin',
appName: 'Autologin Demo',
);
AutologinPlugin.requestLoginToken().then((value) async {
if (value != null) {
setState(() => loginToken = value);
} else {
final hasZeroTouchSupport = (await AutologinPlugin.performCompatibilityChecks()).hasZeroTouchSupport;
setState(() => loginToken = hasZeroTouchSupport ? '这是首次启动' : '平台不支持');
if (hasZeroTouchSupport) {
await AutologinPlugin.saveLoginToken('首次启动 ${DateTime.now()}');
}
}
}).onError((error, stackTrace) {
setState(() => loginToken = error.toString());
});
}
[@override](/user/override)
void dispose() {
super.dispose();
usernameController.removeListener(resetUsernameNote);
passwordController.removeListener(resetPasswordNote);
}
// 平台消息是异步的,所以我们初始化在一个异步方法中。
Future<void> initPlatformState() async {
final isSupported = await AutologinPlugin.isPlatformSupported;
setState(() => isPlatformSupported = isSupported);
}
void resetUsernameNote() {
setState(() => usernameNote = null);
}
void resetPasswordNote() {
setState(() => passwordNote = null);
}
Future<void> requestCredentials() async {
final credentials = await AutologinPlugin.requestCredentials();
if (mounted) {
setState(() {
if (credentials?.username != null) {
usernameController.text = credentials!.username!;
usernameNote = null;
} else {
usernameController.text = '';
usernameNote = 'API未提供用户名';
}
if (credentials?.password != null) {
passwordController.text = credentials!.password!;
passwordNote = null;
} else {
passwordController.text = '';
passwordNote = 'API未提供密码';
}
});
}
}
Future<void> saveCredentials() async {
final success = await AutologinPlugin.saveCredentials(
Credential(username: usernameController.text, password: passwordController.text, domain: 'rekire.github.io'),
);
if (!success && mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('保存凭证失败!'),
),
);
}
}
[@override](/user/override)
Widget build(BuildContext context) {
return Column(
children: [
if (isPlatformSupported != true)
const Padding(
padding: EdgeInsets.only(bottom: 16),
child: Text('⚠️ 此${kIsWeb ? '浏览器' : '平台'}不支持 ⚠️'),
),
TextFormField(
controller: usernameController,
textInputAction: TextInputAction.next,
autofillHints: const [AutofillHints.username],
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: '用户名',
helperText: usernameNote,
),
onFieldSubmitted: (_) => saveCredentials(),
),
const SizedBox(height: 16),
TextFormField(
controller: passwordController,
obscureText: obscurePassword,
textInputAction: TextInputAction.send,
keyboardType: TextInputType.visiblePassword,
autofillHints: const [AutofillHints.password],
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: '密码',
helperText: passwordNote,
suffixIcon: IconButton(
icon: Icon(obscurePassword ? Icons.visibility : Icons.visibility_off),
onPressed: () {
setState(() => obscurePassword = !obscurePassword);
},
tooltip: obscurePassword ? '显示密码' : '隐藏密码',
),
),
onFieldSubmitted: (_) => saveCredentials(),
),
const SizedBox(height: 16),
FilledButton(
onPressed: isPlatformSupported == true ? saveCredentials : null,
child: const Text('保存凭证'),
),
const SizedBox(height: 8),
OutlinedButton(
onPressed: () {
usernameController.text = 'Some-Username';
passwordController.text = r'Example-P@§$w0rd!';
},
child: const Text('输入示例数据'),
),
const SizedBox(height: 8),
OutlinedButton(
onPressed: isPlatformSupported == true ? requestCredentials : null,
child: const Text('请求登录数据'),
),
const SizedBox(height: 8),
Text('登录令牌: $loginToken'),
],
);
}
}
更多关于Flutter自动登录插件autologin_darwin的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter自动登录插件autologin_darwin的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用autologin_darwin
插件实现自动登录功能的示例代码。这个插件主要用于macOS和iOS平台,通过Keychain服务来实现自动登录功能。
首先,确保你的Flutter项目已经创建,并且已经添加了autologin_darwin
依赖。在pubspec.yaml
文件中添加以下依赖:
dependencies:
flutter:
sdk: flutter
autologin_darwin: ^最新版本号 # 请替换为实际可用的最新版本号
然后,运行flutter pub get
来安装依赖。
接下来,你需要根据你的平台(macOS或iOS)进行一些配置。这里以macOS为例进行说明。
macOS 配置
-
在
macos/Runner/Info.plist
中添加权限请求:<key>NSAppleEventsUsageDescription</key> <string>We need to access the keychain for automatic login</string> <key>IOKitPersonalities</key> <dict> <key>HIDDevice</key> <dict> <key>CFBundleIdentifier</key> <string>com.yourcompany.yourapp</string> <key>IOKitPersonalities</key> <dict> <key>HIDKeyboardEventDriver</key> <dict> <key>CFBundleIdentifier</key> <string>com.apple.driver.AppleHIDKeyboardEventDriver</string> <key>IOClass</key> <string>IOHIDDevice</string> <key>IOMatchCategory</key> <string>IODefaultMatchCategory</string> </dict> </dict> </dict> </dict>
注意:上面的
Info.plist
配置可能需要根据实际情况进行调整,特别是CFBundleIdentifier
部分。 -
在Flutter代码中实现自动登录功能:
import 'package:flutter/material.dart'; import 'package:autologin_darwin/autologin_darwin.dart'; void main() { runApp(MyApp()); } class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { String _loginStatus = 'Not Logged In'; @override void initState() { super.initState(); _checkAutoLogin(); } Future<void> _checkAutoLogin() async { String? username = await AutologinDarwin.getUsername(); String? password = await AutologinDarwin.getPassword(); if (username != null && password != null) { setState(() { _loginStatus = 'Auto Logged In as $username'; // 在这里处理自动登录后的逻辑,比如导航到主页面 }); } else { setState(() { _loginStatus = 'Not Logged In'; // 在这里处理未登录的逻辑,比如显示登录页面 }); } } Future<void> _saveCredentials(String username, String password) async { await AutologinDarwin.saveUsername(username); await AutologinDarwin.savePassword(password); setState(() { _loginStatus = 'Credentials Saved'; }); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: Text('Auto Login Example'), ), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('Login Status: $_loginStatus'), SizedBox(height: 20), ElevatedButton( onPressed: () async { // 模拟用户输入用户名和密码 String username = 'testuser'; String password = 'testpassword'; await _saveCredentials(username, password); }, child: Text('Save Credentials'), ), ], ), ), ), ); } }
在这个示例中,我们首先检查是否已经保存了用户名和密码,如果保存了,就认为用户已经自动登录。然后提供了一个按钮来模拟保存用户名和密码的操作。
注意事项
- 权限请求:在实际应用中,你可能需要处理系统权限请求对话框,确保用户授予了访问Keychain的权限。
- 安全性:Keychain服务在macOS和iOS上是相对安全的,但仍然建议不要在Keychain中保存敏感信息(如明文密码),考虑使用更安全的存储方式,比如使用Keychain存储加密后的数据。
- 平台限制:
autologin_darwin
插件仅支持macOS和iOS,如果你需要跨平台支持,可能需要考虑其他方案。
希望这个示例能帮到你!如果有更多问题,欢迎继续提问。