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实例以连接到远程节点。

示例:

3. 实现你的插件类

修改插件入口文件(例如polkwalllet_plugin_acala.dart),创建一个继承自PolkawalletPluginPluginFoo类:

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/polkadotacalalaminar示例:


示例代码

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

1 回复

更多关于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'),
        // 这里可以添加更多功能,如发送交易、查询余额等
      ],
    );
  }
}

注意事项

  1. 安全性:在实际应用中,请确保妥善管理私钥。上面的示例仅用于演示目的,不建议在生产环境中直接存储或传输私钥。
  2. 错误处理:在生产代码中,请添加适当的错误处理逻辑,以处理可能发生的异常。
  3. 依赖版本:确保使用polkawallet_sdk的最新稳定版本,并查阅其官方文档以获取最新的API和功能。

以上代码展示了如何在Flutter项目中使用polkawallet_sdk进行基本的钱包管理操作。根据你的具体需求,你可以进一步扩展和自定义这些功能。

回到顶部