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

React TS连接Metamask钱包移动端无响应问题求助

移动端Metamask钱包连接无响应的适配方案

现有一套React TS编写的钱包连接代码,在PC端安装Metamask浏览器扩展时可正常运行,但在安装Metamask App的移动端点击连接按钮无任何反应,以下是适配全设备的解决方案。

核心问题分析

  1. 初始化阶段过早触发网络检查:原代码在getContract函数开头直接实例化Web3Provider并调用getNetwork,移动端未连接钱包时会抛出错误,导致整个函数执行失败,connectWallet方法无法正常返回,点击按钮自然无响应。
  2. listAccounts方法兼容性不足:该方法在移动端Metamask环境下无法正确获取账户列表,需替换为标准EIP-1193请求方法。
  3. 本地接口无法在移动端访问:代码中请求http://localhost:5000的接口,移动端无法访问本地服务,需替换为公网可访问的地址。

适配解决方案

1. 延迟Provider与合约初始化

将Provider和合约的初始化逻辑移至钱包连接成功后,避免未授权时的初始化错误。

2. 替换账户获取方式

用eth_accounts请求替代listAccounts,保证跨设备兼容性。

3. 调整网络检查时机

在连接钱包后再检查网络,避免初始化阶段阻断流程。

4. 替换本地接口地址

将localhost接口改为公网可访问的服务地址。

修改后的完整代码

import { Contract, ethers } from "ethers";
import MarketContract from "./Market.json";
import blockies from "blockies";

declare global {
    interface Window {
      ethereum?: any;
    }
}

const contractAddress = "0x";
const desiredNetworkID = 11155111;
// 替换为公网可访问的后端地址
const backendApiUrl = "https://your-public-api-domain.com/cryptoserver/api/users/login/";

export default function getContract() {
  // 初始状态下不创建Provider和合约,避免未授权错误
  let provider: ethers.providers.Web3Provider | null = null;
  let contract: Contract | null = null;
  let userAddress: string | null = null;

  const connectWallet = async (): Promise<{ 
    address: string | null; 
    identicon: string | null; 
    balance: string | null;
    contract?: Contract;
  }> => {
    try {
      if (!window.ethereum) {
        alert('请安装MetaMask钱包');
        throw new Error('MetaMask not found');
      }

      // 请求授权账户
      await window.ethereum.request({ method: 'eth_requestAccounts' });
      
      // 实例化Provider
      provider = new ethers.providers.Web3Provider(window.ethereum);
      const network = await provider.getNetwork();

      // 检查网络
      if (network.chainId !== desiredNetworkID) {
        alert('请切换至Sepolia测试网');
        throw new Error('Wrong network');
      }

      // 使用标准方法获取账户
      const accounts = await provider.send('eth_accounts', []);
      if (!accounts || accounts.length === 0) {
        throw new Error('No accounts found');
      }

      userAddress = accounts[0];
      const signer = provider.getSigner();
      // 实例化合约
      contract = new ethers.Contract(contractAddress, MarketContract.abi, signer);

      // 生成头像
      const identicon = blockies({ seed: userAddress.toLowerCase(), size: 8, scale: 16 }).toDataURL();

      // 获取余额
      const balanceBigNumber = await provider.getBalance(userAddress);
      const balance = ethers.utils.formatEther(balanceBigNumber);

      // 请求后端接口(使用公网地址)
      if (userAddress) {
        const response = await fetch(`${backendApiUrl}${userAddress}`);
        const data = await response.json();
        const token = data.token;
        localStorage.setItem('token', token);
      }

      return { address: userAddress, identicon, balance, contract };

    } catch (error) {
      console.error("连接钱包出错: ", error);
      return { address: null, identicon: null, balance: null };
    }
  };

  // 新增:获取已连接状态的方法
  const getCurrentState = async () => {
    if (!window.ethereum) return { userAddress: null, contract: null };
    
    try {
      provider = new ethers.providers.Web3Provider(window.ethereum);
      const accounts = await provider.send('eth_accounts', []);
      if (accounts.length > 0) {
        userAddress = accounts[0];
        const network = await provider.getNetwork();
        if (network.chainId === desiredNetworkID) {
          const signer = provider.getSigner();
          contract = new ethers.Contract(contractAddress, MarketContract.abi, signer);
        }
      }
      return { userAddress, contract };
    } catch (error) {
      console.error("获取当前状态出错: ", error);
      return { userAddress: null, contract: null };
    }
  };

  return {
    connectWallet,
    getCurrentState,
    get contract() { return contract; },
    get userAddress() { return userAddress; }
  };
}

额外技术建议

  • 监听钱包状态变化:添加eth_accountsChanged和chainChanged事件监听,实时更新账户和网络状态:
    if (window.ethereum) {
      window.ethereum.on('accountsChanged', (accounts: string[]) => {
        userAddress = accounts[0] || null;
        // 此处可触发前端状态更新,比如React的setState
      });
    
      window.ethereum.on('chainChanged', (chainId: string) => {
        // 网络切换后重新检查合约有效性
        if (parseInt(chainId) === desiredNetworkID && userAddress && provider) {
          const signer = provider.getSigner();
          contract = new ethers.Contract(contractAddress, MarketContract.abi, signer);
        } else {
          contract = null;
        }
      });
    }
    
  • 移动端交互优化:移动端点击连接按钮后,若未唤醒Metamask App,可提示用户手动打开App授权。
  • 错误提示本地化:将英文提示改为中文,提升移动端用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 07:24:59