Flutter账本管理插件ledger_flutter_plus的使用

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

Flutter账本管理插件ledger_flutter_plus的使用

概述

Ledger Nano设备是管理您加密货币和NFT的理想硬件钱包。这个Flutter插件使您可以轻松找到附近的Ledger设备,连接它们并通过USB和/或BLE签署交易。

支持的设备

BLE USB
Android ✔️ ✔️
iOS ✔️
WEB ✔️ ✔️

开始使用

安装

通过pub.dev安装此软件包的最新版本:

ledger_flutter_plus: ^latest-version

您可能需要安装其他Ledger App插件以支持不同的区块链。请参阅下面的“自定义Ledger App插件”部分。

例如,添加Algorand支持:

ledger_cardano: ^latest-version
设置

创建一个新的LedgerOptions实例并将其传递给Ledger构造函数。

final options = LedgerOptions(
  maxScanDuration: const Duration(milliseconds: 5000),
);

final ledgerUsb = Ledger.usb();
final ledgerBle = Ledger.ble(
  onPermissionRequest: (state) {},
);

AndroidAndroidManifest.xml中添加以下权限:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

<!--bibo01 : hardware option-->
<uses-feature android:name="android.hardware.bluetooth" android:required="false"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false"/>

<!-- required for API 18 - 30 -->
<uses-permission
    android:name="android.permission.BLUETOOTH"
    android:maxSdkVersion="30" />
<uses-permission
    android:name="android.permission.BLUETOOTH_ADMIN"
    android:maxSdkVersion="30" />

<!-- API 31+ -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission
    android:name="android.permission.BLUETOOTH_SCAN"
    android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

iOS 在您的应用程序的Info.plist文件中添加以下条目:

iOS13及以上

<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app uses bluetooth to find, connect and sign transactions with your Ledger Nano X</string>

iOS12及以下

<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app uses bluetooth to find, connect and sign transactions with your Ledger Nano X</string>

使用

扫描附近设备

您可以使用scan()方法扫描附近的Ledger设备。这将返回一个Stream,当发现新设备时可以监听。

final subscription = ledger.scan().listen((device) => print(device));

扫描会在maxScanDuration过去后停止或调用stop()方法。

await ledger.stop();

权限 Ledger Flutter插件使用蓝牙低能耗(Bluetooth Low Energy),这需要处理iOS和Android上的某些权限。插件每次需要权限时都会发送回调。只需覆盖onPermissionRequest并让permission_handler包处理其余的工作即可。

final ledger = Ledger(
  options: options,
  onPermissionRequest: (status) async {
    Map<Permission, PermissionStatus> statuses = await [
      Permission.location,
      Permission.bluetoothScan,
      Permission.bluetoothConnect,
      Permission.bluetoothAdvertise,
    ].request();

    if (status != BleStatus.ready) {
      return false;
    }

    return statuses.values.where((status) => status.isDenied).isEmpty;
  },
);
断开连接

使用disconnect()方法关闭与Ledger设备建立的连接。

await ledger.disconnect(device);
处置

始终使用dispose()方法关闭所有连接并处置任何潜在的监听器以避免资源泄漏。

await ledger.dispose();
LedgerException

每个方法都可能抛出一个LedgerException,其中包含消息、原因和潜在的错误代码。

try {
  await channel.ledger.connect(device);
} on LedgerException catch (ex) {
  await channel.ledger.disconnect(device);
}

自定义Ledger App插件

1. 创建新的LedgerApp

创建一个新的类(例如EthereumLedgerApp)并扩展自LedgerApp

class EthereumLedgerApp extends LedgerApp {
  EthereumLedgerApp(super.ledger);

  [@override](/user/override)
  Future<List<String>> getAccounts(LedgerDevice device) async {
    throw UnimplementedError();
  }

  [@override](/user/override)
  Future<Uint8List> signTransaction(
    LedgerDevice device,
    Uint8List transaction,
  ) {
    throw UnimplementedError();
  }

  [@override](/user/override)
  Future<List<Uint8List>> signTransactions(
    LedgerDevice device,
    List<Uint8List> transactions,
  ) async {
    throw UnimplementedError();
  }
}
2. 定义Ledger操作

为每个APDU命令创建一个新的操作类(例如EthereumPublicKeyOperation)并扩展自LedgerOperation

class AlgorandPublicKeyOperation extends LedgerOperation<List<String>> {
  final int accountIndex;

  AlgorandPublicKeyOperation({
    this.accountIndex = 0,
  });

  [@override](/user/override)
  Future<Uint8List> write(ByteDataWriter writer, int index, int mtu) async {
    writer.writeUint8(0x80); // ALGORAND_CLA
    writer.writeUint8(0x03); // PUBLIC_KEY_INS
    writer.writeUint8(0x00); // P1_FIRST
    writer.writeUint8(0x00); // P2_LAST
    writer.writeUint8(0x04); // ACCOUNT_INDEX_DATA_SIZE

    writer.writeUint32(accountIndex); // Account index as bytearray

    return writer.toBytes();
  }

  [@override](/user/override)
  Future<List<String>> read(ByteDataReader reader, int index, int mtu) async {
    return [
      Address(publicKey: reader.read(reader.remainingLength)).encodedAddress,
    ];
  }
}
3. 实现LedgerApp

最后一步是使用Ledger客户端在连接的Ledger上执行所需的操作。实现LedgerApp所需的各个方法。

[@override](/user/override)
Future<List<String>> getAccounts(LedgerDevice device) async {
    return ledger.sendOperation<List<String>>(
      device,
      AlgorandPublicKeyOperation(accountIndex: accountIndex),
    );
}

示例完整Demo

import 'package:flutter/material.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Ledger Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  [@override](/user/override)
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final options = LedgerOptions(
    maxScanDuration: const Duration(milliseconds: 5000),
  );

  final ledger = Ledger.ble(
    onPermissionRequest: (state) async {
      Map<Permission, PermissionStatus> statuses = await [
        Permission.location,
        Permission.bluetoothScan,
        Permission.bluetoothConnect,
        Permission.bluetoothAdvertise,
      ].request();

      if (state != BleStatus.ready) {
        return false;
      }

      return statuses.values.where((status) => status.isDenied).isEmpty;
    },
  );

  void _startScanning() {
    final subscription = ledger.scan().listen((device) {
      print('Found device: $device');
    });
  }

  void _stopScanning() async {
    await ledger.stop();
  }

  void _disconnect() async {
    await ledger.disconnect(null);
  }

  void _dispose() async {
    await ledger.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Ledger Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
              onPressed: _startScanning,
              child: Text('Start Scanning'),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _stopScanning,
              child: Text('Stop Scanning'),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _disconnect,
              child: Text('Disconnect'),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _dispose,
              child: Text('Dispose'),
            ),
          ],
        ),
      ),
    );
  }
}

更多关于Flutter账本管理插件ledger_flutter_plus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter账本管理插件ledger_flutter_plus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何使用 ledger_flutter_plus 插件的示例代码,该插件可以用于账本管理。假设你已经将 ledger_flutter_plus 添加到你的 Flutter 项目中,并且已经完成了相关的配置。

首先,确保在你的 pubspec.yaml 文件中添加了依赖:

dependencies:
  flutter:
    sdk: flutter
  ledger_flutter_plus: ^最新版本号  # 请替换为实际的最新版本号

然后运行 flutter pub get 来获取依赖。

接下来,我们将编写一个简单的 Flutter 应用来演示如何使用 ledger_flutter_plus 插件。

示例代码

main.dart

import 'package:flutter/material.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Ledger Flutter Plus Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: LedgerDemoPage(),
    );
  }
}

class LedgerDemoPage extends StatefulWidget {
  @override
  _LedgerDemoPageState createState() => _LedgerDemoPageState();
}

class _LedgerDemoPageState extends State<LedgerDemoPage> {
  late Ledger ledger;

  @override
  void initState() {
    super.initState();
    // 初始化 Ledger 实例
    ledger = Ledger();
    // 这里可以添加其他初始化代码,比如连接硬件设备等
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Ledger Flutter Plus Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
              onPressed: () async {
                try {
                  // 执行一些 Ledger 操作,例如获取版本信息
                  String version = await ledger.getVersion();
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(
                      content: Text('Ledger Version: $version'),
                    ),
                  );
                } catch (e) {
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(
                      content: Text('Error: ${e.message}'),
                      backgroundColor: Colors.red,
                    ),
                  );
                }
              },
              child: Text('Get Ledger Version'),
            ),
            // 可以添加更多按钮来演示其他 Ledger 功能
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    // 清理资源,比如关闭 Ledger 连接等
    ledger.dispose();
    super.dispose();
  }
}

注意事项

  1. 硬件连接:确保你的 Ledger 设备已经通过 USB 连接到你的开发机器,并且已经解锁和选择了相应的应用。
  2. 权限处理:在真实应用中,你可能需要处理更多的权限请求和错误处理,比如请求用户允许 USB 设备访问。
  3. 插件方法ledger_flutter_plus 插件提供了许多方法来与 Ledger 设备交互,比如签名交易、获取公钥等。上述示例中只演示了获取版本信息的方法,你可以查阅插件的官方文档来了解更多方法。

官方文档

为了获取更详细的信息和使用案例,请参考 ledger_flutter_plus 插件的官方文档或 GitHub 仓库。

这个示例代码提供了一个基本的框架,你可以在此基础上扩展以满足你的具体需求。

回到顶部