You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter/Dart原生移动应用中部署智能合约(不使用WebView)

使用web3dart在Flutter中部署智能合约的实操方案

为什么不推荐WebView混合方案

web3dart本身是Dart原生实现的以太坊交互库,完全不需要依赖WebView。混合WebView的方式容易出现环境隔离、权限不足、实例找不到等隐性问题,而且很难排查报错,直接用web3dart原生调用是更可靠的方案。

完整部署步骤与代码示例

1. 配置依赖

在pubspec.yaml中添加所需依赖:

dependencies:
  flutter:
    sdk: flutter
  web3dart: ^2.7.0
  http: ^1.1.0
  convert: ^3.1.1

执行flutter pub get安装依赖。

2. 准备合约资源

从Solidity编译器(比如Remix、Hardhat)中导出两个关键内容:

  • 合约ABI:JSON格式的接口描述字符串
  • 合约字节码:编译后的十六进制字符串(开头带0x)

3. 编写部署代码

以下是可直接复用的部署函数,以Ganache本地测试节点为例:

import 'package:web3dart/web3dart.dart';
import 'package:http/http.dart';

Future<String> deployTestContract() async {
  // 连接以太坊节点:模拟器用10.0.2.2映射本地localhost,真机用电脑局域网IP
  final client = Web3Client('http://10.0.2.2:7545', Client());

  // 部署者私钥:替换成你Ganache测试账户的私钥
  final deployerPrivateKey = EthPrivateKey.fromHex('你的测试私钥');
  final deployerAddress = await deployerPrivateKey.extractAddress();

  // 替换成你自己的合约ABI和字节码
  final contractABI = '''[
    {
      "inputs": [],
      "stateMutability": "nonpayable",
      "type": "constructor"
    },
    {
      "name": "getValue",
      "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "name": "setValue",
      "inputs": [{"internalType": "uint256", "name": "_value", "type": "uint256"}],
      "stateMutability": "nonpayable",
      "type": "function"
    }
  ]''';
  final contractBytecode = '0x608060405234801561001057600080fd5b50610150806100206000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806320965255146037578063812651e1146062575b600080fd5b60606004803603810190605f9190602001906094565b60405160799060f4565b60405180910390f35b60005481565b604051919060f4565b6000819050919050565b609e816089565b82525050565b600060208201905060b760008301846097565b9291505056fea2646970667358221220f9a7f7b4a3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f90a1b2c3d4e5f6a7b8c9d0e64736f6c63430008130033';

  // 加载合约工厂
  final deployedContract = DeployedContract(
    ContractAbi.fromJson(contractABI, 'TestContract'),
    EthereumAddress.fromHex(''), // 部署阶段留空
  );
  final deployFunction = deployedContract.function(''); // 无参数构造函数留空

  // 构建部署交易
  final transaction = Transaction.callContract(
    contract: deployedContract,
    function: deployFunction,
    parameters: [], // 构造函数参数,无则传空数组
    from: deployerAddress,
    gasLimit: EtherAmount.inWei(BigInt.from(2000000)), // 手动指定gas上限,避免不足
  );

  // 发送交易并获取哈希
  final txHash = await client.sendTransaction(
    deployerPrivateKey,
    transaction,
    chainId: 1337, // Ganache默认链ID,根据你的节点调整
    fetchChainIdFromNetworkId: false,
  );

  // 等待交易确认,获取合约地址
  final receipt = await client.getTransactionReceipt(txHash);
  final contractAddress = receipt?.contractAddress;

  client.dispose();
  return contractAddress?.hex ?? '部署失败';
}

4. 常见问题排查

  • 节点连接失败:确保Ganache绑定0.0.0.0(允许外部访问),模拟器用10.0.2.2访问本地节点,真机替换为电脑的局域网IP。
  • 无报错但部署失败:检查私钥是否正确、节点是否正常运行、gasLimit是否足够(可以适当调高)。
  • 交易超时:如果是连接主网/测试网,需要等待区块确认,可增加等待时长或使用节点的WebSocket连接(web3dart支持WebSocket客户端)。

部署后调用合约示例

部署完成后,可通过以下方式调用合约方法:

Future<BigInt> getContractValue(String contractAddr) async {
  final client = Web3Client('http://10.0.2.2:7545', Client());
  final contract = DeployedContract(
    ContractAbi.fromJson(contractABI, 'TestContract'),
    EthereumAddress.fromHex(contractAddr),
  );
  final getValueFunc = contract.function('getValue');
  final result = await client.call(
    contract: contract,
    function: getValueFunc,
    params: [],
  );
  client.dispose();
  return result[0] as BigInt;
}

内容的提问来源于stack exchange,提问作者Stan Gregg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 07:32:03