Flutter集成Tagion服务插件tagion_dart_api的使用

发布于 1周前 作者 vueper 来自 Flutter

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);

许可证合规性(使用)

  1. 保留许可证:如果你在项目中使用了此包,你必须在项目文档中包含DECARD Group AG许可证。
  2. 组合软件:如果你将此包与其他软件组合使用,你必须将相同的DECARD Group AG许可证应用于组合软件。
  3. 更多详情:有关完整的条款、阈值和商业用途,请参阅LICENSE.md中的完整DECARD Group AG许可证。

贡献于包

克隆并运行为独立项目

  1. 克隆项目
  2. 导航到带有测试应用的示例文件夹:
    cd example
    
  3. 启动模拟器
    emulator -avd my_emulator
    
  4. 将模拟器连接到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
    
  5. 使用 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

1 回复

更多关于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.xmlInfo.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或执行其他逻辑。

注意事项

  1. API密钥:确保你的API密钥是安全的,不要硬编码在客户端代码中,可以考虑使用环境变量或安全存储服务。
  2. 错误处理:对于生产环境的应用,你需要更全面地处理各种可能的错误情况,包括网络错误、认证错误等。
  3. 文档参考:详细的API使用方法、参数说明和响应格式请参考Tagion服务的官方文档。

通过上述步骤,你应该能够在Flutter项目中成功集成并使用Tagion服务插件tagion_dart_api

回到顶部