Flutter ICP认证插件flutter_icp_auth的使用
Flutter ICP认证插件flutter_icp_auth的使用
✨ 功能
- LOG IN:允许用户通过互联网身份登录。
- AUTO LOGIN:允许用户自动登录。
- RELOAD:基于会话数据/委托对象,在应用重新加载或打开时自动登录用户。
- LOGOUT:提供用户登出功能。
⚠️ 重要信息
1. isLocal
参数
isLocal
用于表示您是使用主网链接还是本地运行应用程序。- 如果
isLocal
为true
,则将backendCanisterId
和middlePageCanisterId
替换为本地部署的 canister ID。 - 如果
isLocal
为false
,则将backendCanisterId
和middlePageCanisterId
替换为主网部署的 canister ID。
- 如果
2. 后端函数
对于本地或主网 backendCanisterId
,请确保您的后端有以下函数:
Rust 示例
use ic_cdk::api::caller;
#[ic_cdk::query]
fn whoami() -> String {
let principal_id = caller().to_string();
format!("principal id - : {:?}", principal_id)
}
Motoko 示例
import Principal "mo:base/Principal";
actor {
public shared (msg) func whoami() : async Text {
Principal.toText(msg.caller);
};
};
对于主网,您可以使用我们的 canister ID:cni7b-uaaaa-aaaag-qc6ra-cai
3. 中间页 Canister ID
对于本地或主网 middlePageCanisterId
,请确保您有以下内容:
- 本地:从 GitHub 克隆并本地部署。
- 主网:
- 您可以将克隆的 中间页 部署到主网,并使用主网 canister ID。
- 或者,您可以使用我们的主网 ID:
nplfj-4yaaa-aaaag-qjucq-cai
4. IDL 和服务
您可以使用 candid_dart 生成 did 文件和 IDL 服务,然后在应用程序中使用它们,如示例应用程序所示。或者,您可以手动添加/编写文件或代码。
🚀 开始使用
1. 设置
- 添加依赖项到
pubspec.yaml
dependencies: flutter_icp_auth: ^1.0.0 agent_dart: ^1.0.0-dev.22
- 导入包到
main.dart
import 'package:agent_dart/agent_dart.dart'; import 'package:flutter_icp_auth/flutter_icp_auth.dart';
- 配置 AndroidManifest.xml 的深度链接
打开
android/app/src/main/AndroidManifest.xml
,添加以下片段,并替换android:scheme
和android:host
为您应用程序的值:<meta-data android:name="flutter_deeplinking_enabled" android:value="true" /> <intent-filter android:autoVerify="true"> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="your_app_scheme" android:host="your_app_callback" /> <data android:scheme="https" /> </intent-filter>
2. 初始化
- 声明变量
bool isLocal = false; // 确认是否在本地运行项目 Service idlService = FieldsMethod.idl; // Idl 服务 (位置: lib/integration.dart) String backendCanisterId = 'cni7b-uaaaa-aaaag-qc6ra-cai'; // 替换为您的后端 canisterId String middlePageCanisterId = 'nplfj-4yaaa-aaaag-qjucq-cai'; // 替换为您的中间页 canisterId
- 定义 initState 和 dispose 方法
[@override](/user/override) void initState() { super.initState(); AuthLogIn.checkLoginStatus(isLocal, backendCanisterId).then((loggedIn) { setState(() { isLoggedIn = loggedIn; if (loggedIn) { _principalId = AuthLogIn.getPrincipal; } }); if (!loggedIn) { UrlListener.handleInitialUri(_fetchAgent, () {}); UrlListener.initListener(_fetchAgent); } }); } [@override](/user/override) void dispose() { UrlListener.cancelListener(); super.dispose(); }
- 手动登录
Future<void> _manualLogin(Uri uri) async { List<dynamic> result = await AuthLogIn.fetchAgent( uri.queryParameters, isLocal, backendCanisterId, idlService); if (result.isNotEmpty) { setState(() { isLoggedIn = uri.queryParameters['status'] == "true" ? true : false; _principalId = result[0]; }); } else { setState(() { isLoggedIn = false; _principalId = "Log in to see your principal"; }); } }
3. 使用 IIDLogin 按钮
当传递参数给 IIDLogin 按钮时,请记得传递您的 app:host 和 app:callback:
- 登录按钮调用
AuthLogIn.authenticate(isLocal, middlePageCanisterId, "exampleCallback", "example");
- 登出按钮调用
List<Object> logoutValidation = await AuthLogout.logout(isLocal, backendCanisterId);
❗ 故障排除
-
ZipFileEncoder.close 和 SingingBlockZipFileEncoder.close 错误
- 前往
agent_dart
包的位置:agent_dart-1.0.0-dev.22/lib/archiver/encoder.dart:162:8
- 将以下代码:
替换为:void close() { _encoder.writeBlock(_output); _encoder.endEncode(); _output.close(); }
Future<void> close() async{ _encoder.writeBlock(_output); _encoder.endEncode(); await _output.close(); }
- 前往
-
minSdkVersion 错误
- 前往代码位置:
example/android/app/build.gradle
- 将
minSdkVersion
更改为 23defaultConfig { minSdkVersion 23 targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName }
- 前往代码位置:
ℹ️ 附加信息
- 示例文件位置:
example/lib/main.dart
- 该包依赖以下依赖项:
agent_dart: ^1.0.0-dev.22
flutter_custom_tabs: ^2.0.0+1
flutter_secure_storage: ^9.2.1
shared_preferences: ^2.2.3
uni_links: ^0.5.1
完整示例 Demo
import 'dart:async';
import 'integration.dart';
import 'package:flutter/material.dart';
import 'package:agent_dart/agent_dart.dart';
import 'package:flutter_icp_auth/flutter_icp_auth.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter IID Login',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurpleAccent),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter IID Login'),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
[@override](/user/override)
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _principalId = "Log in to see your principal";
bool isLoggedIn = false;
// 必须在应用程序中声明这些变量
bool isLocal = false; // 确认是否在本地运行项目
Service idlService = FieldsMethod.idl; // Idl 服务 (位置: lib/integration.dart)
String backendCanisterId = 'cni7b-uaaaa-aaaag-qc6ra-cai'; // 替换为您的后端 canisterId
String middlePageCanisterId = 'nplfj-4yaaa-aaaag-qjucq-cai'; // 替换为您的中间页 canisterId
[@override](/user/override)
void initState() {
super.initState();
AuthLogIn.checkLoginStatus(isLocal, backendCanisterId).then((loggedIn) {
setState(() {
isLoggedIn = loggedIn;
if (loggedIn) {
_principalId = AuthLogIn.getPrincipal;
}
});
if (!loggedIn) {
UrlListener.handleInitialUri(_manualLogin, () {});
UrlListener.initListener(_manualLogin);
}
});
}
[@override](/user/override)
void dispose() {
UrlListener.cancelListener();
super.dispose();
}
Future<void> _manualLogin(Uri uri) async {
List<dynamic> result = await AuthLogIn.fetchAgent(
uri.queryParameters, isLocal, backendCanisterId, idlService);
if (result.isNotEmpty) {
setState(() {
isLoggedIn = uri.queryParameters['status'] == "true" ? true : false;
_principalId = result[0];
});
} else {
setState(() {
isLoggedIn = false;
_principalId = "Log in to see your principal";
});
}
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Center(child: Text(widget.title)),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(
width: 200,
height: 100,
child: Image.asset('assets/images/logo.png'),
),
const Text(
'Principal ID:',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
Text(
_principalId,
style: const TextStyle(
fontSize: 12,
),
),
const SizedBox(
height: 40,
),
isLoggedIn == false
? ElevatedButton(
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: Colors.pink,
elevation: 8,
),
onPressed: () async {
await AuthLogIn.authenticate(isLocal,
middlePageCanisterId, "exampleCallback", "example");
},
child: const Text(
'Log In',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
)
: ElevatedButton(
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: Colors.pink,
elevation: 8,
),
onPressed: () async {
List<Object> logoutValidation =
await AuthLogout.logout(isLocal, backendCanisterId);
setState(() {
isLoggedIn = logoutValidation.whereType<bool>().first;
_principalId = isLoggedIn
? logoutValidation[1].toString()
: "Log in to see your principal";
});
},
child: const Text(
'Log Out',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
)
],
),
),
),
);
}
}
这个完整的示例展示了如何在 Flutter 应用程序中集成和使用 flutter_icp_auth
插件进行 ICP 认证。
更多关于Flutter ICP认证插件flutter_icp_auth的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter ICP认证插件flutter_icp_auth的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中集成和使用flutter_icp_auth
插件的详细步骤及代码示例。flutter_icp_auth
插件通常用于在中国大陆的应用中实现ICP(Internet Content Provider)认证,以确保应用符合当地的法律法规要求。
步骤 1: 添加依赖
首先,在你的pubspec.yaml
文件中添加flutter_icp_auth
插件的依赖。
dependencies:
flutter:
sdk: flutter
flutter_icp_auth: ^最新版本号 # 请替换为最新的版本号
然后运行flutter pub get
来安装依赖。
步骤 2: 导入插件
在你的Dart文件中导入flutter_icp_auth
插件。
import 'package:flutter_icp_auth/flutter_icp_auth.dart';
步骤 3: 配置ICP信息
你需要在你的应用中配置ICP信息,这通常包括ICP许可证号和网站域名。
void main() {
// 在应用启动时配置ICP信息
FlutterIcpAuth.configure(
icpLicenseNumber: '你的ICP许可证号', // 替换为你的ICP许可证号
icpWebsiteDomain: '你的网站域名', // 替换为你的网站域名
);
runApp(MyApp());
}
步骤 4: 检查ICP认证状态
你可以在应用的关键位置检查ICP认证状态,比如启动页面或用户登录后。
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
// 检查ICP认证状态
_checkIcpAuthStatus();
}
Future<void> _checkIcpAuthStatus() async {
try {
bool isAuthenticated = await FlutterIcpAuth.checkAuthStatus();
if (isAuthenticated) {
print('ICP认证通过');
// 执行通过后的逻辑,比如跳转到主页
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
} else {
print('ICP认证未通过');
// 执行未通过的逻辑,比如显示错误信息或退出应用
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('ICP认证未通过'),
content: Text('你的应用未通过ICP认证,无法继续使用。'),
actions: <Widget>[
FlatButton(
child: Text('退出'),
onPressed: () {
SystemNavigator.pop(); // 退出应用
},
),
],
),
);
}
} catch (e) {
print('检查ICP认证状态时发生错误: $e');
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('ICP认证检查'),
),
body: Center(
child: CircularProgressIndicator(), // 显示加载指示器
),
),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('主页'),
),
body: Center(
child: Text('欢迎来到应用主页!'),
),
);
}
}
注意事项
- ICP许可证号和网站域名:确保你提供的ICP许可证号和网站域名是准确的,否则认证可能会失败。
- 错误处理:在实际应用中,你应该添加更多的错误处理逻辑,以处理各种可能的异常情况。
- 用户隐私:确保在处理ICP认证时遵守相关的用户隐私政策和法律法规。
以上是如何在Flutter项目中集成和使用flutter_icp_auth
插件的基本步骤和代码示例。根据你的具体需求,你可能需要调整这些代码。