Flutter Dapp遇_rootHandleError等错误,Android端MetaMask无授权弹窗
问题:Flutter Dapp集成MetaMask(Android端无法弹出授权弹窗+调试错误)
调试Flutter Dapp时出现_rootHandleError、<anonymous closure>、_microTaskLoop错误;编译后的APK可运行,但用户无法在MetaMask中看到连接授权弹窗。通过WalletConnect协议使用walletconnect_dart包集成,iOS模拟器运行正常,Android端异常。
用户代码如下:
import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:walletconnect_dart/walletconnect_dart.dart'; import 'package:url_launcher/url_launcher_string.dart'; class LoginPage extends StatefulWidget { const LoginPage({super.key}); @override State<LoginPage> createState() => _LoginPageState(); } class _LoginPageState extends State<LoginPage> { var connector = WalletConnect( bridge: 'https://bridge.walletconnect.org', clientMeta: const PeerMeta( name: 'My App', description: 'An app for converting pictures to NFT', url: 'https://walletconnect.org', icons: [ 'https://files.gitbook.com/v0/b/gitbook-legacy-files/o/spaces%2F-LJJeCjcLrr53DcT1Ml7%2Favatar.png?alt=media' ])); var _session, _uri, _signature; Future<void> loginUsingMetamask(BuildContext context) async { if (!connector.connected) { try { var session = await connector.createSession(onDisplayUri: (uri) async { _uri = uri; await launchUrl(Uri.parse(uri), mode: LaunchMode.externalApplication); }); print(session.accounts[0]); print(session.chainId); setState(() { _session = session; }); } catch (exp) { print(exp); } } } @override Widget build(BuildContext context) { connector.on( 'connect', (session) => setState( () { _session = _session; }, )); connector.on( 'session_update', (payload) => setState(() { _session = payload; print(_session.accounts[0]); print(_session.chainId); })); connector.on( 'disconnect', (payload) => setState(() { _session = null; })); return Scaffold( appBar: AppBar(title: Text("Login Page")), body: Column(children: [ ElevatedButton( onPressed: () async { loginUsingMetamask(context); }, child: Text("Connect to Metamask")) ]), ); } }
Android端差异与解决办法
一、Android端核心差异
- Android对App间跳转的URI Scheme验证更严格,MetaMask的回调URI需正确配置才能完成会话闭环
- Android后台任务调度机制与iOS不同,WalletConnect的会话回调易被系统优先级调度拦截
- 旧版
walletconnect_dart在Android上存在异步处理兼容性问题,直接导致_microTaskLoop类错误
二、具体修复步骤
1. 配置AndroidManifest.xml的Intent Filter
在<activity>标签内添加MetaMask回调URI过滤,确保App能接收授权结果:
<intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="wc" /> </intent-filter>
2. 修复代码逻辑错误
用户代码存在3个关键问题,逐一修正:
- 事件监听重复注册:将
connector.on系列监听从build方法移到initState,避免每次重建UI时重复注册 - Connect回调赋值错误:
connect事件中应将接收到的session赋值给_session,而非原地赋值 - 跳转异常未处理:添加
canLaunchUrl校验,避免因MetaMask未安装导致流程中断
修改后的核心代码:
@override void initState() { super.initState(); // 仅在初始化时注册一次事件监听 connector.on('connect', (session) => setState(() { _session = session; // 修复赋值错误 })); connector.on('session_update', (payload) => setState(() { _session = payload; print(_session.accounts[0]); print(_session.chainId); })); connector.on('disconnect', (payload) => setState(() { _session = null; })); } Future<void> loginUsingMetamask(BuildContext context) async { if (!connector.connected) { try { var session = await connector.createSession(onDisplayUri: (uri) async { _uri = uri; final url = Uri.parse(uri); if (await canLaunchUrl(url)) { await launchUrl(url, mode: LaunchMode.externalApplication); } else { throw '未检测到MetaMask,请先安装应用'; } }); print(session.accounts[0]); print(session.chainId); setState(() { _session = session; }); } catch (exp) { print('连接错误:$exp'); // 可添加用户提示,如SnackBar ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('连接失败:$exp')), ); } } }
3. 解决异步循环错误
- 更新
walletconnect_dart到最新稳定版,在pubspec.yaml中修改依赖:
dependencies: walletconnect_dart: ^0.5.5 # 替换为最新版本
- 避免在UI线程嵌套过深的异步操作,所有WalletConnect相关逻辑尽量保持扁平化
4. 测试注意事项
- 不要使用Android模拟器测试,建议用真实设备(部分模拟器对App间跳转支持不完善)
- 确保MetaMask为最新版本,旧版本可能不兼容WalletConnect v1/v2协议特性
内容的提问来源于stack exchange,提问作者Geek
相关产品推荐
相关产品推荐

