Flutter智能卡交互插件tangem_sdk的使用
Flutter智能卡交互插件tangem_sdk的使用
Tangem卡是一款支持NFC的自托管硬件钱包,其主要功能是安全地创建和存储私钥并签署数据。Tangem SDK用于在第三方应用程序中支持Tangem卡。
支持的平台包括:
- iOS
- Android
- JVM
- Flutter
- React Native
- Cordova
- Capacitor
文档
如需详尽的文档,请访问Tangem开发者门户。
要开始开发过程,可以从Tangem开发者入门指南页面开始。
许可证
Tangem SDK 在MIT许可证下可用。有关更多信息,请参阅LICENSE文件。
示例代码
以下是一个完整的示例,展示了如何使用flutter_tangem_sdk
插件来与Tangem卡进行交互。
示例代码
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:tangem_sdk/tangem_sdk.dart';
import 'package:tangem_sdk_example/app_widgets.dart';
import 'package:tangem_sdk_example/source.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Tangem SDK 插件示例')),
body: CommandListWidget(),
),
);
}
}
class CommandListWidget extends StatefulWidget {
[@override](/user/override)
_CommandListWidgetState createState() => _CommandListWidgetState();
}
class _CommandListWidgetState extends State<CommandListWidget> {
final _jsonEncoder = JsonEncoder.withIndent(' ');
static const int ID_UNDEFINED = -1;
static const int ID_SCAN = 1;
static const int ID_CREATE_WALLET = 2;
static const int ID_PURGE_WALLET = 3;
late TangemSdk _sdk;
int _methodId = 10;
String? _cardId;
String? _walletPublicKey;
String? _scanImage;
String _response = "";
final _controller = TextEditingController();
[@override](/user/override)
void initState() {
super.initState();
_sdk = TangemSdk();
_controller.addListener(() {
setState(() {});
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(height: 25),
RowActions(
[
ActionButton("扫描卡片", _handleScanCard),
ActionButton("签名哈希", _handleSign),
],
),
ActionType("设置扫描图像"),
RowActions(
[
ActionButton("设置", _handleSetScanImage),
ActionButton("移除", _handleRemoveScanImage),
],
),
ActionType("钱包"),
RowActions(
[
ActionButton("创建", _handleCreateWallet),
ActionButton("清除", _handlePurgeWallet),
],
),
ActionType("PIN码"),
RowActions(
[
ActionButton("设置访问码", _handleSetAccessCode),
ActionButton("设置密码", _handleSetPasscode),
],
),
SizedBox(height: 5),
Divider(),
ActionType("JSON-RPC"),
Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(height: 5),
TextField(
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 0, 0, 5),
labelText: "粘贴配置",
isDense: true,
),
minLines: 1,
maxLines: 25,
controller: _controller,
),
SizedBox(height: 15),
Row(
children: [
OutlinedButton(
onPressed: () async {
final data = await Clipboard.getData(Clipboard.kTextPlain);
final textData = data?.text ?? "";
if (textData.isEmpty) return;
_controller.value = TextEditingValue(text: textData);
},
child: Icon(Icons.paste)),
SizedBox(width: 8),
Expanded(
child: OutlinedButton(
child: Text("启动"),
onPressed: _controller.text.isEmpty ? null : () => _handleJsonRpc(_controller.text),
),
)
],
),
],
),
),
Divider(),
ActionType("结果"),
Text(_response),
],
),
);
}
void _handleScanCard() {
_execJsonRPCRequest(_makeJsonRpc(SdkMethod.scan));
}
void _handleSign() {
if (_cardId == null || _walletPublicKey == null) {
_notify("扫描卡片或创建钱包");
return;
}
final request = _makeJsonRpc(SdkMethod.sign_hash, {
"walletPublicKey": _walletPublicKey,
"hash": "f1642bb080e1f320924dde7238c1c5f8f1642bb080e1f320924dde7238c1c5f8ff",
});
_execJsonRPCRequest(request, _cardId);
}
void _handleSetScanImage() {
_sdk.setScanImage(ScanTagImage(base64Image, 0)).then((value) {
_parseResponse(value);
_printResponse(value);
}).onError((error, stackTrace) {
_printResponse(error);
});
}
void _handleRemoveScanImage() {
_sdk.setScanImage(null).then((value) {
_parseResponse(value);
_printResponse(value);
}).onError((error, stackTrace) {
_printResponse(error);
});
}
void _handleCreateWallet() {
if (_cardId == null) {
_notify("扫描卡片");
return;
}
final request = _makeJsonRpc(SdkMethod.create_wallet, {
"curve": "Secp256k1",
});
_execJsonRPCRequest(request, _cardId);
}
void _handlePurgeWallet() {
if (_cardId == null || _walletPublicKey == null) {
_notify("扫描卡片或创建钱包");
return;
}
final request = _makeJsonRpc(SdkMethod.purge_wallet, {
"walletPublicKey": _walletPublicKey,
});
_execJsonRPCRequest(request, _cardId);
}
void _handleSetAccessCode() {
if (_cardId == null) {
_notify("扫描卡片");
return;
}
final request = _makeJsonRpc(SdkMethod.set_accesscode, {
"accessCode": "ABCDEFGH",
});
_execJsonRPCRequest(request, _cardId);
}
void _handleSetPasscode() {
if (_cardId == null) {
_notify("扫描卡片");
return;
}
final request = _makeJsonRpc(SdkMethod.set_passcode, {
"passcode": "ABCDEFGH",
});
_execJsonRPCRequest(request, _cardId);
}
void _handleJsonRpc(String text) {
try {
final jsonMap = jsonDecode(text.trim());
final request = JSONRPCRequest.fromJson(jsonMap);
_execJsonRPCRequest(request, _cardId);
} catch (ex) {
_notify(ex.toString());
}
}
void _execJsonRPCRequest(JSONRPCRequest request, [String? cardId, Message? message, String? accessCode]) {
final completeRequest = {
"JSONRPCRequest": jsonEncode(request),
"cardId": cardId,
"initialMessage": message?.toJson(),
"accessCode": accessCode,
};
_sdk.runJSONRPCRequest(completeRequest).then((value) {
_parseResponse(value);
_printResponse(value);
}).onError((error, stackTrace) {
_printResponse(error);
});
}
void _printResponse(Object? decodedResponse) {
if (decodedResponse == null) return;
setState(() {
_response = _reEncode(decodedResponse);
});
}
void _parseResponse(String response) {
JSONRPCResponse jsonRpcResponse;
try {
jsonRpcResponse = JSONRPCResponse.fromJson(jsonDecode(response));
} catch (ex) {
print(ex.toString());
return;
}
if (jsonRpcResponse.result != null) {
switch (jsonRpcResponse.id) {
case ID_SCAN:
{
_cardId = jsonRpcResponse.result["cardId"];
final wallets = jsonRpcResponse.result["wallets"];
if (wallets is List && wallets.isNotEmpty) {
_walletPublicKey = wallets[0]["publicKey"];
}
break;
}
case ID_CREATE_WALLET:
{
_walletPublicKey = jsonRpcResponse.result["wallet"]["publicKey"];
break;
}
case ID_PURGE_WALLET:
{
_walletPublicKey = null;
break;
}
}
}
}
JSONRPCRequest _makeJsonRpc(SdkMethod method, [Map<String, dynamic> params = const {}]) {
return JSONRPCRequest(describeEnum(method), params, _getMethodId(method));
}
int _getMethodId(SdkMethod method) {
switch (method) {
case SdkMethod.scan:
return ID_SCAN;
case SdkMethod.create_wallet:
return ID_CREATE_WALLET;
case SdkMethod.purge_wallet:
return ID_PURGE_WALLET;
default:
return _methodId++;
}
}
void _notify(String message) {
setState(() {
_response = message;
});
}
String _reEncode(Object value) {
if (value is String) {
return _jsonEncoder.convert(jsonDecode(value));
} else {
return _jsonEncoder.convert(value);
}
}
}
更多关于Flutter智能卡交互插件tangem_sdk的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
tangem_sdk
是一个用于在 Flutter 应用中与 Tangem 智能卡进行交互的插件。Tangem 智能卡是一种硬件钱包,用于安全地存储和管理加密货币。通过 tangem_sdk
插件,开发者可以在 Flutter 应用中实现与 Tangem 智能卡的通信,执行诸如读取卡片信息、签名交易等操作。
以下是如何在 Flutter 项目中使用 tangem_sdk
插件的基本步骤:
1. 添加依赖
首先,在 pubspec.yaml
文件中添加 tangem_sdk
插件的依赖:
dependencies:
flutter:
sdk: flutter
tangem_sdk: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get
来获取依赖。
2. 初始化 SDK
在使用 tangem_sdk
之前,需要先初始化 SDK。通常可以在应用的 main
函数中进行初始化:
import 'package:tangem_sdk/tangem_sdk.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await TangemSdk.initialize();
runApp(MyApp());
}
3. 扫描卡片
要开始与 Tangem 智能卡进行交互,首先需要扫描卡片。可以使用 TangemSdk.scanCard()
方法来扫描卡片并获取卡片信息:
import 'package:tangem_sdk/tangem_sdk.dart';
Future<void> scanCard() async {
try {
final response = await TangemSdk.scanCard();
print('Card ID: ${response.cardId}');
print('Public Key: ${response.walletPublicKey}');
print('Balance: ${response.balance}');
} catch (e) {
print('Error scanning card: $e');
}
}
4. 签名交易
要使用 Tangem 智能卡签名交易,可以使用 TangemSdk.sign()
方法。首先需要准备交易数据,然后调用 sign
方法进行签名:
import 'package:tangem_sdk/tangem_sdk.dart';
Future<void> signTransaction() async {
final transactionData = 'Your transaction data here';
try {
final signature = await TangemSdk.sign(transactionData);
print('Transaction signature: $signature');
} catch (e) {
print('Error signing transaction: $e');
}
}
5. 处理错误
在使用 tangem_sdk
时,可能会遇到各种错误,例如卡片未连接、操作被取消等。建议在使用 SDK 时捕获并处理这些错误:
try {
final response = await TangemSdk.scanCard();
// 处理响应
} on TangemSdkError catch (e) {
print('Tangem SDK error: ${e.message}');
} catch (e) {
print('Unexpected error: $e');
}
6. 其他功能
tangem_sdk
还提供了其他功能,例如创建钱包、导入钱包、设置访问码等。你可以根据需求调用相应的方法。
7. 示例代码
以下是一个简单的 Flutter 应用示例,展示了如何使用 tangem_sdk
扫描卡片并显示卡片信息:
import 'package:flutter/material.dart';
import 'package:tangem_sdk/tangem_sdk.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await TangemSdk.initialize();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Tangem SDK Example'),
),
body: Center(
child: TangemCardScanner(),
),
),
);
}
}
class TangemCardScanner extends StatefulWidget {
[@override](/user/override)
_TangemCardScannerState createState() => _TangemCardScannerState();
}
class _TangemCardScannerState extends State<TangemCardScanner> {
String _cardInfo = 'Scan a Tangem card to see its information.';
Future<void> _scanCard() async {
try {
final response = await TangemSdk.scanCard();
setState(() {
_cardInfo = 'Card ID: ${response.cardId}\nPublic Key: ${response.walletPublicKey}\nBalance: ${response.balance}';
});
} catch (e) {
setState(() {
_cardInfo = 'Error scanning card: $e';
});
}
}
[@override](/user/override)
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(_cardInfo),
SizedBox(height: 20),
ElevatedButton(
onPressed: _scanCard,
child: Text('Scan Card'),
),
],
);
}
}