Flutter集成Tagion服务插件tagion_dart_api的使用
Flutter集成Tagion服务插件tagion_dart_api的使用
关键概念
本指南提供了如何在Tagion Dart API中使用关键组件的概述。当前项目是在Tagion API之上的Dart包装器。
API分为5个模块:
- 基本模块(Basic):管理API的运行时。在与其他模块交互之前必须初始化并启动。
- 加密模块(Crypto):使用
SecureNet
指针管理加密操作,如密钥对生成和设备PIN解密。 - Hibon模块(Hibon):表示可以被操作和转换为文档缓冲区的分层数据结构。
- 文档模块(Document):由
Hibon
缓冲区创建的结构化数据格式,允许进行数据检索和操作。 - HiRPC模块(HiRPC):允许创建签名请求,确保与外部系统安全交互。
开始使用
下载二进制文件
该项目使用预编译的二进制文件。要获取这些二进制文件,请在您的Flutter项目的根目录下运行以下命令:
dart run tagion_dart_api:libtagion_fetch
支持的平台包括:
- iOS
- Android
使用说明
本文档提供了如何使用Tagion Dart API中的关键类和方法的示例。每个示例都展示了基本的工作流程和对象实例化过程,以及方法和使用模式的详细描述。
示例1:创建和管理基本对象
Basic
对象对于管理API的运行时至关重要。在与其他任何模块交互之前,必须实例化Basic
对象,并显式地启动其运行时。运行时管理涉及两个关键方法:startDRuntime()
和stopDRuntime()
。必须确保在使用其他API功能时运行时正在运行,并且在操作完成后停止运行时以释放资源。
IBasic basic = Basic.init();
// 启动D运行时以启用其他模块。
basic.startDRuntime();
// 完成后,停止运行时以释放资源。
basic.stopDRuntime();
示例2:使用Crypto对象生成密钥对和解密设备PIN
Crypto
对象提供了加密操作,允许生成新的密钥对并解密现有的设备PIN。在此示例中,首先实例化一个Crypto
对象(假设Basic
对象已经启动了运行时),然后创建一个SecureNet
指针来存储加密信息。该指针可用于生成新的密钥对或解密现有的加密PIN。
在整个应用程序生命周期中,必须保留SecureNet
指针,因为它包含了用于签名和其他加密操作的重要加密信息。
ICrypto crypto = Crypto.init();
Pointer<SecureNet> secureNetPtr = malloc<SecureNet>();
// 使用口令、PIN码、盐和SecureNet指针生成一个新的密钥对。
// 结果是加密后的设备PIN数据。
Uint8List devicePinData = crypto.generateKeypair('differ portion age fame', '123456', 'salt', secureNetPtr);
// 使用SecureNet指针对数据进行签名,并传递给加密函数。
Uint8List signedData = crypto.sign(dataToSign, secureNetPtr);
// 解密设备PIN数据,使用PIN码和SecureNet指针。
crypto.decryptDevicePin('123456', devicePinData, secureNetPtr);
示例3:创建和管理Hibon对象
Hibon
对象用于表示和管理分层数据结构。在向Hibon
对象添加任何数据之前,必须先调用create()
方法。数据可以作为键值对或嵌套的Hibon
对象添加(支持其他类型)。Hibon
的分层结构允许用户创建复杂的嵌套数据对象。
一旦数据被结构化,你可以获得一个表示Hibon
的文档缓冲区,该缓冲区稍后可以用于创建文档。
IHibon hibon = Hibon.init();
// 在添加数据之前创建一个新的Hibon结构。
hibon.create();
// 向Hibon对象添加键值对。
hibon.addString('key', 'value');
// 创建另一个嵌套的Hibon对象并将其添加到主Hibon中。
IHibon innerHibon = Hibon.init();
innerHibon.create();
innerHibon.addString('innerKey', 'innerValue');
// 使用键将嵌套的Hibon对象添加到主Hibon中。
hibon.addHibonByKey('inner', innerHibon);
// 获取Hibon对象作为文档缓冲区。
// 该缓冲区可用于创建文档或其他操作。
hibon.getAsDocumentBuffer();
示例4:从Hibon缓冲区创建文档
一旦你有了一个Hibon
对象,就可以用它来创建一个Document
对象。文档本质上是对数据的结构化表示,通过这种方法可以进一步通过按键检索特定元素。检索到的元素可以返回字符串值或嵌套子文档。
// 从Hibon缓冲区创建一个Document对象。
// 缓冲区是通过调用Hibon对象的getAsDocumentBuffer方法获得的。
IDocument document = Document.init(hibon.getAsDocumentBuffer());
// 按键检索文档中的元素。
IDocumentElement element = document.getElementByKey('key');
// 获取文档元素的字符串值。
element.getString();
// 如果元素表示嵌套结构,则检索子文档。
element.getSubDocument();
示例5:使用HiRPC创建签名请求
HiRPC
对象允许你创建签名请求,以便与系统进行安全通信。此示例展示了如何使用方法名、SecureNet
指针、可选的文档缓冲区和可选的衍生器生成签名的HiRPC请求。文档缓冲区可以从Hibon
对象使用getAsDocumentBuffer()
方法获得。
IHiRPC hiRPC = TagionHiRPC.init();
// 使用方法名、SecureNet指针、可选的文档缓冲区/衍生器创建一个签名的HiRPC请求。
// 此方法返回一个已签名的请求,准备传输。
Uint8List signedRequest = hiRPC.createSignedRequest("method", secureNetPtr, docBuffer, deriver);
许可证合规性(使用)
- 保留许可证:如果你在项目中使用了此包,你必须在项目文档中包含DECARD Group AG许可证。
- 组合软件:如果你将此包与其他软件组合使用,你必须将相同的DECARD Group AG许可证应用于组合软件。
- 更多详情:有关完整的条款、阈值和商业用途,请参阅LICENSE.md中的完整DECARD Group AG许可证。
贡献于包
克隆并运行为独立项目
- 克隆项目
- 导航到带有测试应用的示例文件夹:
cd example
- 启动模拟器
emulator -avd my_emulator
- 将模拟器连接到Flutter
- 运行
flutter devices
确保Flutter识别运行中的模拟器。
2 connected devices: my_emulator • emulator • android-x86 • Android 11 (API 30) (emulator) Chrome (web) • chrome • web-javascript • Google Chrome 128.0.6613.85
- 运行
- 使用
flutter run
命令启动测试应用。
运行集成测试
/// 需要运行模拟器。
cd example
flutter test integration_test/entry_point_integration_test.dart
运行单元测试
/// 从项目根目录运行。
flutter test
许可证合规性(贡献)
如果你修改了代码:
- 必须注明所做的更改和改进。
- 发布修改版本(源代码)并附上更改描述。
以下是示例代码,位于example/lib/main.dart
:
import 'dart:ffi';
import 'package:crypto/crypto.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:tagion_dart_api/enums/tagion_error_code.dart';
import 'package:tagion_dart_api/enums/text_format.dart';
import 'package:tagion_dart_api/exception/crypto_exception.dart';
import 'package:tagion_dart_api/exception/document_exception.dart';
import 'package:tagion_dart_api/exception/hibon_exception.dart';
import 'package:tagion_dart_api/module/basic/basic.dart';
import 'package:tagion_dart_api/module/crypto/crypto.dart';
import 'package:tagion_dart_api/module/crypto/crypto_interface.dart';
import 'package:tagion_dart_api/module/crypto/ffi/crypto_ffi.dart';
import 'package:tagion_dart_api/module/document/document.dart';
import 'package:tagion_dart_api/module/hibon/hibon.dart';
import 'package:tagion_dart_api/pointer_manager/pointer_manager.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> {
late final TGNBasic _basic;
late final ICrypto _crypto;
final TextEditingController _passPhraseCtrl = TextEditingController(text: 'pass phrase example');
final TextEditingController _pinCodeCtrl = TextEditingController(text: '123456');
final TextEditingController _keyPairCtrl = TextEditingController();
final TextEditingController _hibonCtrl = TextEditingController();
final TextEditingController _signatureCtrl = TextEditingController();
final FocusNode _passPhraseFN = FocusNode();
final FocusNode _pinCodeFN = FocusNode();
final FocusNode _keyPairFN = FocusNode();
final FocusNode _hibonFN = FocusNode();
final FocusNode _signatureFN = FocusNode();
late final Pointer<SecureNet> _secureNetPtr;
Uint8List? _hibon;
String? _hibonStatus;
String? _signatureStatus;
String? _dartIndex;
final Map<String, bool> _collapsedState = {
'keyPair': false,
'hibon': false,
'signature': false,
};
[@override](/user/override)
void initState() {
super.initState();
_secureNetPtr = const PointerManager().allocate<SecureNet>();
_basic = TGNBasic.init();
_basic.startDRuntime();
_crypto = TGNCrypto.init();
}
void _generateKeypair() {
_crypto.generateKeypair(
_passPhraseCtrl.text,
_pinCodeCtrl.text,
'',
_secureNetPtr,
);
_keyPairCtrl.text = _toBase64Url(_crypto.getPublicKey(_secureNetPtr));
_unfocus();
}
void _signData() {
setState(() {
try {
if (_hibon == null) {
_signatureStatus = 'Create hibon first';
return;
}
List<int> dataHash = sha256.convert(_hibon!).bytes;
_signatureCtrl.text = _toBase64Url(_crypto.sign(Uint8List.fromList(dataHash), _secureNetPtr));
_signatureStatus = 'Signed';
} on CryptoApiException catch (e) {
_signatureStatus = 'Failed: ${e.runtimeType}: ${e.errorCode.toString()} - ${e.message}';
}
});
}
String _toBase64Url(Uint8List? data) {
if (data == null) return 'No data';
return _basic.encodeBase64Url(data);
}
void _createHibon() {
TGNHibon hibonExample = TGNHibon.init();
hibonExample.create();
hibonExample.addString("\$@", "TGN");
TGNHibon value = TGNHibon.init();
value.create();
value.addInt<Uint64>("\$", 1000);
hibonExample.addHibonByKey("\$V", value);
hibonExample.addArrayByKey("\$Y", Uint8List.fromList([1, 2, 3, 4, 5]));
hibonExample.addTime("\$t", DateTime.now().millisecondsSinceEpoch);
_hibon = hibonExample.getAsDocumentBuffer();
_representHibon(_hibon, TextFormat.prettyJson);
_showDartIndex(_hibon);
_validateHibon(_hibon);
}
void _createHibonFromJson(String json) {
try {
TGNHibon hibonFromJson = TGNHibon.init();
hibonFromJson.create();
hibonFromJson.createFromJson(json);
_hibon = hibonFromJson.getAsDocumentBuffer();
_showDartIndex(_hibon);
_validateHibon(_hibon);
} on HibonApiException catch (e) {
setState(() {
_hibonStatus = 'HibonApiException: ${e.errorCode} ${e.message}';
});
} on TGNDocumentApiException catch (e) {
setState(() {
_hibonStatus = 'TGNDocumentApiException: ${e.errorCode} ${e.message}';
});
}
}
void _representHibon(Uint8List? hibon, TextFormat textFormat) {
if (hibon == null) return;
TGNDocument doc = TGNDocument.init(hibon);
_hibonCtrl.text = doc.getAsString(textFormat);
}
void _validateHibon(Uint8List? hibon) {
if (hibon == null) {
return;
}
TGNDocument doc = TGNDocument.init(hibon);
TGNErrorCode code = doc.validate();
setState(() {
if (code == TGNErrorCode.none) {
_hibonStatus = 'Valid';
} else {
_hibonStatus = code.toString();
}
});
}
void _showDartIndex(Uint8List? data) {
if(data == null) return;
Uint8List dartIndex = _basic.createDartIndex(data);
setState(() {
_dartIndex = _toBase64Url(dartIndex);
});
}
void _clearKeyPair() {
_passPhraseCtrl.clear();
_pinCodeCtrl.clear();
_keyPairCtrl.clear();
const PointerManager().zeroOutAndFree(_secureNetPtr, 1);
}
void _clearHibon() {
_hibonCtrl.clear();
setState(() {
_hibon = null;
_dartIndex = null;
_hibonStatus = null;
});
}
void _unfocus() {
_passPhraseFN.unfocus();
_pinCodeFN.unfocus();
_keyPairFN.unfocus();
}
Widget _buildCollapsableContainer({
required String key,
required String title,
required Widget child,
}) {
return GestureDetector(
onTap: () {
setState(() {
_collapsedState[key] = !_collapsedState[key]!;
});
},
child: Container(
key: Key(key),
padding: const EdgeInsets.all(10),
width: double.infinity,
margin: const EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title, style: const TextStyle(fontSize: 16)),
Icon(_collapsedState[key]! ? Icons.arrow_drop_down : Icons.arrow_drop_up),
],
),
Visibility(
visible: _collapsedState[key]!,
child: child,
),
],
),
));
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.white70,
appBar: AppBar(
title: const Text('Example'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: _unfocus,
child: SingleChildScrollView(
child: Center(
child: Column(
children: [
_buildCollapsableContainer(
key: 'keyPair',
title: 'Key pair',
child: Column(
children: [
TextField(
decoration: const InputDecoration(labelText: 'Pass phrase'),
controller: _passPhraseCtrl,
focusNode: _passPhraseFN,
minLines: 1,
maxLines: 3,
onChanged: (value) {
_passPhraseCtrl.text = value;
},
),
TextField(
decoration: const InputDecoration(labelText: 'Pin code'),
controller: _pinCodeCtrl,
focusNode: _pinCodeFN,
onChanged: (value) {
_pinCodeCtrl.text = value;
},
),
TextField(
decoration: const InputDecoration(labelText: 'Public key'),
controller: _keyPairCtrl,
focusNode: _keyPairFN,
readOnly: true,
minLines: 1,
maxLines: 8,
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
OutlinedButton(
onPressed: _generateKeypair,
child: const Text('Generate'),
),
const SizedBox(width: 10),
OutlinedButton(
onPressed: _clearKeyPair,
child: const Text('Clear'),
),
],
),
],
),
),
_buildCollapsableContainer(
key: 'hibon',
title: 'Hibon',
child: Column(
children: [
Text('Hash: ${_dartIndex ?? 'N/A'}'),
const SizedBox(height: 10),
TextField(
decoration: const InputDecoration(labelText: 'Hibon'),
controller: _hibonCtrl,
focusNode: _hibonFN,
minLines: 1,
maxLines: 100,
onChanged: (value) {
_createHibonFromJson(value);
},
),
const SizedBox(height: 10),
Text(_hibonStatus ?? 'N/A'),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
OutlinedButton(
onPressed: _createHibon,
child: const Text('Generate'),
),
const SizedBox(width: 10),
OutlinedButton(
onPressed: _clearHibon,
child: const Text('Clear'),
),
],
),
],
),
),
_buildCollapsableContainer(
key: 'signature',
title: 'Sign a hibon',
child: Column(
children: [
TextField(
decoration: const InputDecoration(labelText: 'Result'),
controller: _signatureCtrl,
focusNode: _signatureFN,
readOnly: true,
minLines: 1,
maxLines: 10,
),
const SizedBox(height: 10),
Text(_signatureStatus ?? ''),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
OutlinedButton(
onPressed: _signData,
child: const Text('Sign'),
),
const SizedBox(width: 10),
OutlinedButton(
onPressed: _clearHibon,
child: const Text('Clear'),
),
],
),
],
),
),
],
),
),
),
),
),
),
);
}
}
更多关于Flutter集成Tagion服务插件tagion_dart_api的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter集成Tagion服务插件tagion_dart_api的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter项目中集成Tagion服务插件tagion_dart_api
,你可以按照以下步骤进行。这里将展示一个基本的集成示例,包括如何在Flutter应用中引入该插件并使用其API。
步骤1:添加依赖
首先,在你的pubspec.yaml
文件中添加tagion_dart_api
依赖:
dependencies:
flutter:
sdk: flutter
tagion_dart_api: ^最新版本号 # 替换为实际的最新版本号
然后运行flutter pub get
来安装依赖。
步骤2:配置权限(如果需要)
根据Tagion服务的要求,你可能需要在AndroidManifest.xml
和Info.plist
中添加相应的权限配置。具体权限需求请参考Tagion服务的官方文档。
步骤3:初始化Tagion服务
在你的Flutter应用的入口文件(通常是main.dart
)中,初始化Tagion服务。以下是一个基本的示例:
import 'package:flutter/material.dart';
import 'package:tagion_dart_api/tagion_dart_api.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
TagionClient? _tagionClient;
@override
void initState() {
super.initState();
// 初始化TagionClient,替换为你的API密钥和端点
_tagionClient = TagionClient(
apiKey: 'your_api_key', // 替换为你的API密钥
endpoint: 'https://your_tagion_endpoint', // 替换为你的Tagion服务端点
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Tagion Integration Demo'),
),
body: Center(
child: ElevatedButton(
onPressed: () async {
// 调用Tagion服务的示例方法
try {
var response = await _tagionClient?.someTagionApiMethod(); // 替换为实际的API方法
print('Tagion API Response: $response');
} catch (e) {
print('Error calling Tagion API: $e');
}
},
child: Text('Call Tagion API'),
),
),
),
);
}
}
注意:上面的代码中的_tagionClient?.someTagionApiMethod();
是一个占位符,你需要根据Tagion服务的实际API文档替换为具体的API方法调用。
步骤4:处理API响应
在上面的代码中,我们使用了try-catch
块来处理API调用可能抛出的异常。在实际应用中,你可能需要根据API响应的结果更新UI或执行其他逻辑。
注意事项
- API密钥:确保你的API密钥是安全的,不要硬编码在客户端代码中,可以考虑使用环境变量或安全存储服务。
- 错误处理:对于生产环境的应用,你需要更全面地处理各种可能的错误情况,包括网络错误、认证错误等。
- 文档参考:详细的API使用方法、参数说明和响应格式请参考Tagion服务的官方文档。
通过上述步骤,你应该能够在Flutter项目中成功集成并使用Tagion服务插件tagion_dart_api
。