Flutter区块链钱包管理插件polkawallet_sdk的使用
Flutter区块链钱包管理插件polkawallet_sdk的使用
SDK
polkawallet SDK用于将基于substrate的区块链作为插件集成。
构建一个polkawallet_plugin dart包
1. 创建你的插件仓库
创建一个dart包:
flutter create --template=package polkwalllet_plugin_acala
cd polkwalllet_plugin_acala/
在pubspec.yaml
中添加依赖项:
dependencies:
polkawallet_sdk: ^0.1.2
然后安装依赖项:
flutter pub get
2. 构建你的polkadot-js包装器
应用使用一个隐藏的webView运行polkadot-js/api
实例以连接到远程节点。
示例:
- kusama/polkadot: https://github.com/polkawallet-io/js_api
- acala: https://github.com/polkawallet-io/polkawallet_plugin_acala/tree/master/lib/js_service_acala
- laminar: https://github.com/polkawallet-io/polkawallet_plugin_laminar/tree/master/lib/polkawallet_plugin_laminar
3. 实现你的插件类
修改插件入口文件(例如polkwalllet_plugin_acala.dart
),创建一个继承自PolkawalletPlugin
的PluginFoo
类:
class PluginAcala extends PolkawalletPlugin {
/// 定义你自己的插件
}
3.1 覆盖PolkawalletPlugin.basic
[@override](/user/override)
final basic = PluginBasicData(
name: 'acala',
ss58: 42,
primaryColor: Colors.deepPurple,
gradientColor: Colors.blue,
// `bg.png` 将作为背景纹理显示在主题色块上,所以它应该具有透明或暗色背景。
backgroundImage: AssetImage('packages/polkawallet_plugin_acala/assets/images/bg.png'),
icon:
Image.asset('packages/polkawallet_plugin_acala/assets/images/logo.png'),
// `logo_gray.png` 应该是灰色颜色 `#9e9e9e`。
iconDisabled: Image.asset(
'packages/polkawallet_plugin_acala/assets/images/logo_gray.png'),
isTestNet: false,
);
3.2 覆盖PolkawalletPlugin.tokenIcons
定义图标小部件,以便Polkawallet应用可以显示你的平行链上的代币图标。
[@override](/user/override)
final Map<String, Widget> tokenIcons = {
'KSM': Image.asset(
'packages/polkawallet_plugin_kusama/assets/images/tokens/KSM.png'),
'DOT': Image.asset(
'packages/polkawallet_plugin_kusama/assets/images/tokens/DOT.png'),
};
3.3 覆盖PolkawalletPlugin.nodeList
const node_list = [
{
'name': 'Mandala TC5 Node 1 (Hosted by OnFinality)',
'ss58': 42,
'endpoint': 'wss://node-6714447553777491968.jm.onfinality.io/ws',
},
];
[@override](/user/override)
List<NetworkParams> get nodeList {
return node_list.map((e) => NetworkParams.fromJson(e)).toList();
}
3.4 覆盖PolkawalletPlugin.getNavItems(BuildContext, Keyring)
定义在Polkawallet应用底部导航栏中的自定义导航项。HomeNavItem.content
是当你的导航项被选中时显示的页面内容小部件。
[@override](/user/override)
List<HomeNavItem> getNavItems(BuildContext context, Keyring keyring) {
return [
HomeNavItem(
text: 'Acala',
icon: SvgPicture.asset(
'packages/polkawallet_plugin_acala/assets/images/logo.svg',
color: Theme.of(context).disabledColor,
),
iconActive: SvgPicture.asset(
'packages/polkawallet_plugin_acala/assets/images/logo.svg'),
content: AcalaEntry(this, keyring),
)
];
}
3.5 覆盖PolkawalletPlugin.getRoutes(Keyring)
定义导航路由以供插件页面使用。
[@override](/user/override)
Map<String, WidgetBuilder> getRoutes(Keyring keyring) {
return {
TxConfirmPage.route: (_) =>
TxConfirmPage(this, keyring, _service.getPassword),
CurrencySelectPage.route: (_) => CurrencySelectPage(this),
AccountQrCodePage.route: (_) => AccountQrCodePage(this, keyring),
TokenDetailPage.route: (_) => TokenDetailPage(this, keyring),
TransferPage.route: (_) => TransferPage(this, keyring),
// 其他页面
// ...
};
}
3.6 覆盖PolkawalletPlugin.loadJSCode()
方法
加载你在步骤2中构建的polkadot-js/api
包装器。
[@override](/user/override)
Future<String> loadJSCode() => rootBundle.loadString(
'packages/polkawallet_plugin_acala/lib/js_service_acala/dist/main.js');
3.7 覆盖插件生命周期方法
onWillStart()
: 你可能希望在此处准备插件状态数据。onStarted()
: 远程节点已连接,你可以从网络获取数据。onAccountChanged()
: 用户刚刚更改了账户,你可能需要清除前一个账户的缓存并为新账户查询数据。
示例:
获取数据并构建页面
我们使用https://pub.dev/packages/mobx作为应用程序状态管理工具。因此,插件目录看起来像这样:
lib
|__ pages (UI页面)
|__ store (MobX存储)
|__ service (由UI触发的动作以改变存储)
|__ ...
通过PolkawalletPlugin.sdk.api
查询数据:
Future<List> queryReferendums() async {
final data = await api.gov.queryReferendums(keyring.current.address);
store.gov.setReferendums(data);
return data;
}
通过直接调用JS查询数据:
Future<void> updateBestNumber() async {
final int bestNumber = await api.service.webView
.evalJavascript('api.derive.chain.bestNumber()');
store.gov.setBestNumber(bestNumber);
}
当我们向MobX存储设置数据时,MobX Observer Flutter小部件会根据新数据重新构建。
在example/
应用中运行你的页面
你可能希望在开发过程中运行一个示例应用。
查看kusama/polkadot
或acala
或laminar
示例:
示例代码
example/lib/main.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:polkawallet_sdk/api/types/networkParams.dart';
import 'package:polkawallet_sdk/polkawallet_sdk.dart';
import 'package:polkawallet_sdk/storage/keyring.dart';
import 'package:polkawallet_sdk/storage/keyringEVM.dart';
import 'package:polkawallet_sdk_example/pages/account.dart';
import 'package:polkawallet_sdk_example/pages/dAppPage.dart';
import 'package:polkawallet_sdk_example/pages/ethWithJS.dart';
import 'package:polkawallet_sdk_example/pages/evm.dart';
import 'package:polkawallet_sdk_example/pages/keyring.dart';
import 'package:polkawallet_sdk_example/pages/setting.dart';
import 'package:polkawallet_sdk_example/pages/tx.dart';
import 'pages/staking.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
[@override](/user/override)
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final WalletSDK sdk = WalletSDK();
final Keyring keyring = Keyring();
final KeyringEVM keyringEVM = KeyringEVM();
bool _sdkReady = false;
Future<void> _initApi() async {
await keyring.init([0, 2]);
await keyringEVM.init();
await sdk.init(keyring, keyringEVM: keyringEVM);
setState(() {
_sdkReady = true;
});
}
void _showResult(BuildContext context, String title, res) {
showCupertinoDialog(
context: context,
builder: (BuildContext context) {
return CupertinoAlertDialog(
title: Text(title),
content: SelectableText(res, textAlign: TextAlign.left),
actions: [
CupertinoButton(
child: Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
},
);
}
[@override](/user/override)
void initState() {
super.initState();
_initApi();
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Polkawallet SDK Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(sdk, keyring, _sdkReady),
routes: {
DAppPage.route: (_) => DAppPage(sdk, keyring),
KeyringPage.route: (_) => KeyringPage(sdk, keyring, _showResult),
SettingPage.route: (_) => SettingPage(sdk, _showResult),
AccountPage.route: (_) => AccountPage(sdk, _showResult),
TxPage.route: (_) => TxPage(sdk, keyring, _showResult),
StakingPage.route: (_) => StakingPage(sdk, keyring, _showResult),
EVMPage.route: (_) => EVMPage(sdk, keyringEVM, _showResult),
EthWithJSPage.route: (_) => EthWithJSPage(sdk, keyringEVM, _showResult),
},
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage(this.sdk, this.keyring, this.sdkReady);
final WalletSDK sdk;
final Keyring keyring;
final bool sdkReady;
[@override](/user/override)
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _connecting = false;
bool _apiConnected = false;
Future<void> _connectNode() async {
setState(() {
_connecting = true;
});
final node = NetworkParams();
node.name = 'Kusama';
node.endpoint = 'wss://kusama.api.onfinality.io/public-ws/';
node.ss58 = 2;
final res = await widget.sdk.api.connectNode(widget.keyring, [node]);
if (res != null) {
setState(() {
_apiConnected = true;
});
}
setState(() {
_connecting = false;
});
}
[@override](/user/override)
Widget build(BuildContext context) {
final Widget trailing = widget.sdkReady
? IconButton(
icon: Icon(Icons.arrow_forward_ios, size: 18),
onPressed: null,
)
: CupertinoActivityIndicator();
return Scaffold(
appBar: AppBar(
title: Text('Polkawallet SDK Demo'),
),
body: SafeArea(
child: ListView(
children: [
Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('js-api loaded: ${widget.sdkReady}'),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('js-api connected: $_apiConnected'),
OutlinedButton(
child: _connecting
? CupertinoActivityIndicator()
: Text(_apiConnected
? 'connected ${widget.sdk.api.connectedNode?.name}'
: 'connect'),
onPressed: _apiConnected || _connecting
? null
: () => _connectNode(),
)
],
),
],
),
),
Divider(),
ListTile(
title: Text('WebViewWithExtension'),
subtitle: Text('open polkassembly.io (DApp)'),
trailing: trailing,
onTap: () {
if (!widget.sdkReady) return;
Navigator.of(context).pushNamed(DAppPage.route,
arguments: "https://apps.acala.network/#/loan");
},
),
Divider(),
ListTile(
title: Text('sdk.keyring'),
subtitle: Text('keyPairs management'),
trailing: trailing,
onTap: () {
if (!widget.sdkReady) return;
Navigator.of(context).pushNamed(KeyringPage.route);
},
),
Divider(),
ListTile(
title: Text('sdk.setting'),
subtitle: Text('network settings'),
trailing: trailing,
onTap: () {
if (!widget.sdkReady) return;
Navigator.of(context).pushNamed(SettingPage.route);
},
),
Divider(),
ListTile(
title: Text('sdk.account'),
subtitle: Text('account management'),
trailing: trailing,
onTap: () {
if (!widget.sdkReady) return;
Navigator.of(context).pushNamed(AccountPage.route);
},
),
Divider(),
ListTile(
title: Text('sdk.tx'),
subtitle: Text('extrinsic actions'),
trailing: trailing,
onTap: () {
if (!widget.sdkReady) return;
Navigator.of(context).pushNamed(TxPage.route);
},
),
Divider(),
ListTile(
title: Text('sdk.staking'),
subtitle: Text('staking management'),
trailing: trailing,
onTap: () {
if (!widget.sdkReady) return;
Navigator.of(context).pushNamed(StakingPage.route);
},
),
Divider(),
ListTile(
title: Text('ethers'),
subtitle: Text('ethers keyring'),
onTap: () {
Navigator.of(context).pushNamed(EVMPage.route);
},
),
Divider(),
ListTile(
title: Text('sdk.eth'),
subtitle: Text('eth js keyring'),
onTap: () {
Navigator.of(context).pushNamed(EthWithJSPage.route);
},
),
Divider(),
],
),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
更多关于Flutter区块链钱包管理插件polkawallet_sdk的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter区块链钱包管理插件polkawallet_sdk的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用polkawallet_sdk
进行区块链钱包管理的代码示例。polkawallet_sdk
是一个用于与Polkadot和Substrate链交互的Flutter插件。
首先,确保你已经在pubspec.yaml
文件中添加了polkawallet_sdk
依赖:
dependencies:
flutter:
sdk: flutter
polkawallet_sdk: ^最新版本号 # 请替换为实际的最新版本号
然后,运行flutter pub get
来获取依赖。
接下来,在你的Flutter项目中,你可以按照以下步骤使用polkawallet_sdk
进行钱包管理。
1. 导入必要的包
在你的Dart文件中导入polkawallet_sdk
:
import 'package:polkawallet_sdk/polkawallet_sdk.dart';
2. 初始化SDK
在你的应用启动时,初始化SDK。这通常在你的主文件(如main.dart
)中进行:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 初始化SDK
await PolkaWalletSDK.init();
runApp(MyApp());
}
3. 创建和管理钱包
以下是一个简单的示例,展示如何使用polkawallet_sdk
创建钱包、生成地址,并进行签名交易。
import 'package:flutter/material.dart';
import 'package:polkawallet_sdk/polkawallet_sdk.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await PolkaWalletSDK.init();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('PolkaWallet SDK Demo'),
),
body: Center(
child: WalletManagement(),
),
),
);
}
}
class WalletManagement extends StatefulWidget {
@override
_WalletManagementState createState() => _WalletManagementState();
}
class _WalletManagementState extends State<WalletManagement> {
late String walletAddress;
@override
void initState() {
super.initState();
_createWallet();
}
Future<void> _createWallet() async {
// 创建钱包
final Keypair keypair = Keypair.generate();
setState(() {
walletAddress = keypair.publicKey;
});
// 打印钱包地址
print('Generated Wallet Address: $walletAddress');
// 示例:签名消息
final String message = 'Hello, Polkadot!';
final Signature signature = keypair.sign(message.codeUnits);
// 打印签名
print('Signature: $signature');
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Wallet Address: $walletAddress'),
// 这里可以添加更多功能,如发送交易、查询余额等
],
);
}
}
注意事项
- 安全性:在实际应用中,请确保妥善管理私钥。上面的示例仅用于演示目的,不建议在生产环境中直接存储或传输私钥。
- 错误处理:在生产代码中,请添加适当的错误处理逻辑,以处理可能发生的异常。
- 依赖版本:确保使用
polkawallet_sdk
的最新稳定版本,并查阅其官方文档以获取最新的API和功能。
以上代码展示了如何在Flutter项目中使用polkawallet_sdk
进行基本的钱包管理操作。根据你的具体需求,你可以进一步扩展和自定义这些功能。