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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 18:44:55