From 9ce0c65315853809c163074a8d1f97c6cf9b8afa Mon Sep 17 00:00:00 2001 From: hzj <1304805162@qq.com> Date: Mon, 12 Jan 2026 14:31:52 +0800 Subject: [PATCH] =?UTF-8?q?feat(app=E8=BF=9E=E6=8E=A5=E6=96=87=E4=BB=B6):?= =?UTF-8?q?=20=E6=96=B0=E5=A2=9Eios=E8=AE=BE=E5=A4=87=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/appBridge.js | 167 +++++++++++++++++++++++++++++++++++------ 1 file changed, 142 insertions(+), 25 deletions(-) diff --git a/src/utils/appBridge.js b/src/utils/appBridge.js index 7eb5683..20ea982 100644 --- a/src/utils/appBridge.js +++ b/src/utils/appBridge.js @@ -167,19 +167,68 @@ export function connectApplication(renderFun) { // 兼容历史版本 window.getIosAccessOriginParam = renderFun + // 安全日志函数 + const safeConsoleLog = (level, ...args) => { + if (process.env.NODE_ENV === 'production') return + + try { + if (ios()) { + const processedArgs = args.map((arg) => { + if (typeof arg === 'object' && arg !== null) { + try { + return JSON.stringify( + arg, + (key, value) => { + if (value instanceof HTMLElement) return '[HTMLElement]' + if (typeof value === 'function') return '[Function]' + if (value instanceof Date) return value.toISOString() + if (value instanceof RegExp) return value.toString() + if (value instanceof Error) return { message: value.message, stack: value.stack } + + if (this.__visited__) { + if (this.__visited__.has(value)) return '[Circular Reference]' + } else { + this.__visited__ = new Set() + } + this.__visited__.add(value) + return value + }, + 2, + ) + } catch (e) { + return '[Object with serialization error]' + } + } + return arg + }) + console[level](...processedArgs) + } else { + console[level](...args) + } + } catch (e) { + if (process.env.NODE_ENV === 'development') { + console.error('Console logging failed:', e) + } + } + } + + const debugLog = (...args) => safeConsoleLog('debug', ...args) + const errorLog = (...args) => safeConsoleLog('error', ...args) + try { + // 安卓设备环境 if (android()) { - console.debug('Flutter Android WebView 检测') - console.debug('window.app 对象:', window.app) + debugLog('Flutter Android WebView 检测') + debugLog('window.app 对象:', window.app) // 检查Flutter注入的接口 if (window.app) { - console.debug('window.app 的所有方法:') - console.debug(Object.keys(window.app)) + debugLog('window.app 的所有方法:') + debugLog(Object.keys(window.app)) // 检查具体的方法 - console.debug('getAccessOrigin 方法存在?', typeof window.app.getAccessOrigin) - console.debug('getAccessOrigin 是函数?', typeof window.app.getAccessOrigin === 'function') + debugLog('getAccessOrigin 方法存在?', typeof window.app.getAccessOrigin) + debugLog('getAccessOrigin 是函数?', typeof window.app.getAccessOrigin === 'function') } // 等待Flutter注入完成 @@ -189,26 +238,26 @@ export function connectApplication(renderFun) { const checkInterface = () => { attempts++ - console.debug(`尝试第 ${attempts} 次检查Flutter接口...`) + debugLog(`尝试第 ${attempts} 次检查Flutter接口...`) if ( window.app && window.app.getAccessOrigin && typeof window.app.getAccessOrigin === 'function' ) { - console.debug('Flutter接口检测成功,调用 getAccessOrigin') + debugLog('Flutter接口检测成功,调用 getAccessOrigin') try { const result = window.app.getAccessOrigin() - console.debug('getAccessOrigin 返回结果:', result) + debugLog('getAccessOrigin 返回结果:', result) renderFun(result) } catch (error) { - console.error('调用 getAccessOrigin 出错:', error) + errorLog('调用 getAccessOrigin 出错:', error) } } else if (attempts < maxAttempts) { // 继续等待 setTimeout(checkInterface, 100) } else { - console.error('Flutter接口注入超时,使用默认数据') + errorLog('Flutter接口注入超时,使用默认数据') // 使用默认的开发数据 const mockAccess = JSON.stringify({ Authorization: 'Bearer FLUTTER_MOCK_TOKEN', @@ -227,18 +276,18 @@ export function connectApplication(renderFun) { if (window.app) { waitForFlutterInterface() } else { - console.debug('等待Flutter注入window.app...') + debugLog('等待Flutter注入window.app...') // 监听window.app的创建 let checkCount = 0 const checkApp = () => { checkCount++ if (window.app) { - console.debug('检测到window.app,开始连接') + debugLog('检测到window.app,开始连接') waitForFlutterInterface() } else if (checkCount < 50) { setTimeout(checkApp, 100) } else { - console.error('等待window.app超时') + errorLog('等待window.app超时') // 手动通知Flutter注入接口 if (window.FlutterApp && window.FlutterApp.postMessage) { window.FlutterApp.postMessage('requestAccessOrigin') @@ -247,17 +296,85 @@ export function connectApplication(renderFun) { } checkApp() } - } else { - /*else if (ios()) { - console.debug('ios access detected') - // iOS可能需要特殊处理,这里先使用通用方法 - if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.getAccessOrigin) { - window.webkit.messageHandlers.getAccessOrigin.postMessage({}) - } else if (window.app && window.app.getAccessOrigin) { - renderFun(window.app.getAccessOrigin()) + } + + // 苹果设备环境 + else if (ios()) { + debugLog('iOS access detected') + + // iOS WebKit 消息处理器检测和等待 + const waitForIOSInterface = () => { + let attempts = 0 + const maxAttempts = 50 // 最多等待5秒 + + const checkIOSInterface = () => { + attempts++ + debugLog(`尝试第 ${attempts} 次检查iOS接口...`) + + if ( + window.webkit && + window.webkit.messageHandlers && + window.webkit.messageHandlers.getAccessOrigin + ) { + debugLog('iOS接口检测成功,调用 getAccessOrigin') + try { + // iOS的postMessage是异步的,需要通过回调处理 + window.webkit.messageHandlers.getAccessOrigin.postMessage({}) + + // 设置全局回调函数来接收iOS返回的数据 + window.receiveAccessOrigin = function (accessData) { + debugLog('收到iOS返回的access数据:', accessData) + renderFun(accessData) + } + } catch (error) { + errorLog('调用 getAccessOrigin 出错:', error) + // 使用模拟数据作为降级处理 + const mockAccess = JSON.stringify({ + Authorization: 'Bearer IOS_MOCK_TOKEN', + 'Req-Lang': 'en', + 'Req-App-Intel': 'build=1.0;version=2.1;channel=ios;Req-Imei=ios-device', + 'Req-Sys-Origin': 'origin=LIKEI;originChild=IOS', + }) + renderFun(mockAccess) + } + } else if (attempts < maxAttempts) { + // 继续等待 + setTimeout(checkIOSInterface, 100) + } else { + errorLog('iOS接口注入超时,使用默认数据') + const mockAccess = JSON.stringify({ + Authorization: 'Bearer IOS_MOCK_TOKEN', + 'Req-Lang': 'en', + 'Req-App-Intel': 'build=1.0;version=2.1;channel=ios;Req-Imei=ios-device', + 'Req-Sys-Origin': 'origin=LIKEI;originChild=IOS', + }) + renderFun(mockAccess) + } + } + + checkIOSInterface() } - }*/ - console.debug('非移动设备环境') + + // 检查 window.app 是否存在(某些情况下iOS也可能注入window.app) + if (window.app && typeof window.app.getAccessOrigin === 'function') { + debugLog('检测到window.app,尝试调用getAccessOrigin') + try { + const result = window.app.getAccessOrigin() + debugLog('window.app.getAccessOrigin 返回结果:', result) + renderFun(result) + } catch (error) { + errorLog('调用window.app.getAccessOrigin出错:', error) + waitForIOSInterface() // 尝试WebKit方式 + } + } else { + debugLog('等待iOS WebKit接口注入...') + waitForIOSInterface() + } + } + + // 浏览器环境 + else { + debugLog('非移动设备环境') // 非APP环境,可能是浏览器调试 console.warn('Not in APP environment, using mock data for development') // 开发环境可以提供模拟数据 @@ -272,7 +389,7 @@ export function connectApplication(renderFun) { } } } catch (error) { - console.error('Failed to connect to APP:', error) + errorLog('Failed to connect to APP:', error) } }