移动端window.ethereum.request失效,如何实现PolyMarket式MetaMask登录?
实现移动端MetaMask唤起与登录同步的解决方案
核心问题分析
你测试iOS时直接跳转App Store链接是错误的——PolyMarket的逻辑是优先用MetaMask深层链接唤起App,只有唤起失败(用户未安装MetaMask)时才会跳转应用商店。直接跳App Store会跳过DApp授权流程,自然无法检测到登录状态。
实现步骤与代码示例
以下是React项目中完整的实现逻辑,和PolyMarket的核心流程一致:
1. 平台检测工具函数
先判断当前设备是iOS/Android还是桌面端:
const isIOS = () => /iPhone|iPad|iPod/.test(navigator.userAgent) && !window.MSStream; const isAndroid = () => /Android/.test(navigator.userAgent);
2. 登录按钮点击事件处理
优先用MetaMask深层链接唤起App,唤起失败则跳转应用商店:
const handleMetaMaskLogin = async () => { const dappDomain = window.location.origin.replace(/^https?:\/\//, ''); // 提取你的DApp域名(不带http/https) let deepLink = `https://metamask.app.link/dapp/${dappDomain}`; // 桌面端沿用原有扩展逻辑 if (!isIOS() && !isAndroid()) { if (!window.ethereum) { alert('请安装MetaMask浏览器扩展'); return; } try { await window.ethereum.request({ method: 'eth_requestAccounts' }); handleLoginSuccess(); // 自定义登录成功后的逻辑 } catch (err) { console.error('登录失败:', err); } return; } // 移动端尝试唤起MetaMask App const startTime = Date.now(); window.location.href = deepLink; // 检测唤起是否失败:2秒后页面仍可见则说明唤起失败,跳转应用商店 setTimeout(() => { if (Date.now() - startTime < 3000 && document.visibilityState === 'visible') { const storeUrl = isIOS() ? 'https://apps.apple.com/us/app/metamask-blockchain-wallet/id1438144202' : 'https://play.google.com/store/apps/details?id=io.metamask'; window.location.href = storeUrl; } }, 2000); };
3. 页面返回后的状态检测
用户从MetaMask授权后回到浏览器,需要主动检测登录状态:
import { useEffect } from 'react'; useEffect(() => { // 页面加载时检测已有账户 const checkExistingAccounts = async () => { if (window.ethereum) { try { const accounts = await window.ethereum.request({ method: 'eth_accounts' }); if (accounts.length > 0) { handleLoginSuccess(); // 处理已登录逻辑 } } catch (err) { console.error('检测账户失败:', err); } } }; checkExistingAccounts(); // 监听账户变化事件 const handleAccountsChanged = (accounts) => { if (accounts.length > 0) { handleLoginSuccess(); } else { handleLogout(); // 处理登出逻辑 } }; window.ethereum?.on('accountsChanged', handleAccountsChanged); // 组件卸载时移除监听 return () => { window.ethereum?.removeListener('accountsChanged', handleAccountsChanged); }; }, []);
关键注意事项
- 深层链接的正确性:
metamask.app.link/dapp/xxx会自动重定向到MetaMask的原生唤起链接(metamask://dapp/xxx),必须传入你的DApp真实域名,MetaMask会关联该域名的授权状态。 - 唤起失败的判断:通过页面可见性+定时器判断,避免误判(比如用户切换应用慢的情况)。
- 状态同步:用户从MetaMask返回后,
window.ethereum会被注入到浏览器环境,此时可以通过eth_accounts请求或accountsChanged事件获取登录状态。
内容的提问来源于stack exchange,提问作者Morton
相关产品推荐
相关产品推荐

