如何在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
相关产品推荐
相关产品推荐

