Flutter账本管理插件ledger_flutter的使用
Flutter账本管理插件ledger_flutter的使用
ledger-flutter
一个Flutter插件,用于通过USB和BLE扫描、连接和签名Ledger Nano设备上的交易。
概述
Ledger Nano设备是管理您的加密货币和NFT的最佳硬件钱包。这个Flutter插件使您能够轻松找到附近的Ledger设备,与它们连接并通过USB和/或BLE签名交易。
Web3生态系统集成
我们正在扩展Flutter生态系统以发展Web3社区。请查看下面的其他Web3包:
- WalletConnect
- Algorand
支持的设备
BLE | USB | |
---|---|---|
Android | ✔️ | ✔️ |
iOS | ✔️ | ❌ |
开始使用
安装
通过pub.dev安装最新版本的此包:
ledger_flutter: ^latest-version
例如,添加Algorand支持:
ledger_algorand: ^latest-version
设置
创建一个新的LedgerOptions
实例并将其传递给Ledger
构造函数。
final options = LedgerOptions(
maxScanDuration: const Duration(milliseconds: 5000),
);
final ledger = Ledger(
options: options,
);
Android
该包使用以下权限:
- ACCESS_FINE_LOCATION:此权限是因为旧的Nexus设备需要位置服务才能提供可靠的扫描结果。
- BLUETOOTH:允许应用程序连接到配对的蓝牙设备。
- BLUETOOTH_ADMIN:允许应用程序发现和配对蓝牙设备。
在AndroidManifest.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
对于iOS,必须在应用的Info.plist
文件中添加以下条目。如果不这样做,则无法访问Core Bluetooth。
iOS13及以上
<key>NSBluetoothAlwaysUsageDescription</key>
<string>此应用程序使用蓝牙来查找、连接并与您的Ledger Nano X签署交易。</string>
iOS12及以下
<key>NSBluetoothPeripheralUsageDescription</key>
<string>此应用程序使用蓝牙来查找、连接并与您的Ledger Nano X签署交易。</string>
Ledger App插件
每个区块链都有自己的协议,需要实现后才能获取公钥和签名交易。我们引入了Ledger App插件的概念,任何开发人员都可以轻松创建和集成自己的Ledger App插件,并与社区共享。
我们为Algorand区块链添加了第一个支持:
ledger_algorand: ^latest-version
final algorandApp = AlgorandLedgerApp(ledger);
final publicKeys = await algorandApp.getAccounts(device);
现有插件:
- Algorand
- 创建我自己的插件
使用方法
扫描附近设备
您可以使用scan()
方法扫描附近的Ledger设备。这会返回一个可以监听的新设备被发现时发出的Stream
。
final subscription = ledger.scan().listen((device) => print(device));
扫描会在maxScanDuration
过去或调用stop()
方法时停止。maxScanDuration
是BLE发现运行以查找附近设备的最大时间。
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;
},
);
连接到Ledger设备
一旦找到LedgerDevice
,可以使用connect()
方法轻松连接到设备。
await ledger.connect(device);
如果无法连接到设备,则会抛出LedgerException
。
该包还包括一个devices
流,当连接状态更改时更新。
final subscription = ledger.devices.listen((state) => print(state));
获取公钥
根据所需的区块链和Ledger Application插件,可以使用getAccounts()
方法从Ledger Nano设备获取公钥。
final algorandApp = AlgorandLedgerApp(ledger);
final publicKeys = await algorandApp.getAccounts(device);
accounts.addAll(publicKeys.map((pk) => Address.fromAlgorandAddress(pk)).toList());
签名交易
您可以使用提供的LedgerApp
轻松签名交易。
这是一个使用algorand_dart
SDK的示例:
final algorandApp = AlgorandLedgerApp(channel.ledger);
final signature = await algorandApp.signTransaction(
device,
transaction.toBytes(),
);
final signedTx = SignedTransaction(
transaction: event.transaction,
signature: signature,
);
final txId = await algorand.sendTransaction(
signedTx,
waitForConfirmation: true,
);
断开连接
使用disconnect()
方法关闭与Ledger设备的已建立连接。
await ledger.disconnect(device);
处理
始终使用close()
方法关闭所有连接并释放潜在的监听器资源,以免泄漏任何资源。
await ledger.close();
LedgerException
每个方法都可能抛出LedgerException
,其中包含消息、原因和潜在错误代码。
try {
await channel.ledger.connect(device);
} on LedgerException catch (ex) {
await channel.ledger.disconnect(device);
}
自定义Ledger App插件
每个区块链都有自己的APDU协议,在能够获取公钥和签名交易之前需要实现。
如果您想支持另一个区块链(如Ethereum),请按照以下步骤操作。您可以在ledger_algorand
中检查实现细节。
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
。遵循并实现所需区块链的APDU协议。
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
上实现所需的方法。
注意,不同区块链的LedgerApp
接口可能会改变,因此请随时打开拉取请求。
[@override](/user/override)
Future<List<String>> getAccounts(LedgerDevice device) async {
return ledger.sendOperation<List<String>>(
device,
AlgorandPublicKeyOperation(accountIndex: accountIndex),
);
}
赞助商
我们的顶级赞助商如下所示!
Defly |
Blockshake |
贡献
贡献是开源社区如此令人惊叹的学习、启发和创造的地方的原因。您所做的任何贡献都非常感谢。
如果您有一个能使此项目更好的建议,请fork仓库并创建一个pull请求。您也可以简单地打开一个带有标签enhancement
的问题。
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/my-feature
) - Commit your Changes (
git commit -m 'feat: my new feature'
) - Push to the Branch (
git push origin feature/my-feature
) - Open a Pull Request
请阅读我们的贡献指南并尝试遵循Conventional Commits。
许可证
ledger_flutter SDK发布在MIT许可证下。详情请参见LICENSE。
示例Demo
以下是完整的示例demo,展示了如何使用ledger_flutter
插件进行设备扫描、连接和签名交易:
import 'package:flutter/material.dart';
import 'package:ledger_flutter/ledger_flutter.dart';
import 'package:ledger_algorand/ledger_algorand.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
[@override](/user/override)
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final options = LedgerOptions(
maxScanDuration: const Duration(seconds: 10),
);
final ledger = Ledger(options: options);
final algorandApp = AlgorandLedgerApp(ledger);
[@override](/user/override)
void initState() {
super.initState();
scanDevices();
}
void scanDevices() {
final subscription = ledger.scan().listen((device) {
print('Found device: $device');
connectToDevice(device);
});
}
void connectToDevice(LedgerDevice device) async {
try {
await ledger.connect(device);
print('Connected to device: $device');
getPublicKeys(device);
} catch (e) {
print('Failed to connect: $e');
}
}
void getPublicKeys(LedgerDevice device) async {
final publicKeys = await algorandApp.getAccounts(device);
print('Public Keys: $publicKeys');
// Disconnect after getting keys
await ledger.disconnect(device);
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Ledger Flutter Demo'),
),
body: Center(
child: Text('Check console for device information.'),
),
),
);
}
[@override](/user/override)
void dispose() {
ledger.close();
super.dispose();
}
}
更多关于Flutter账本管理插件ledger_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html