import deviceInfo from './deviceInfo'
import { setRefreshToken } from './token'
// === 設備判斷 ===
const u = navigator.userAgent
export const isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1
export const isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
export const isNativeMobile = (isAndroid || isIOS) && new URLSearchParams(window.location.search).get('native')
// === 調試信息 ===
console.log('=== 設備檢測 ===', {
userAgent: u,
isAndroid,
isIOS,
isNativeMobile,
urlParams: window.location.search
})
// === nativeTokenReady: 外部可 await 等待 token 注入 ===
let nativeTokenReadyResolve: (_token: string) => void
export const nativeTokenReady: Promise<string> = new Promise((resolve) => {
nativeTokenReadyResolve = resolve
})
// === 橋接狀態管理 ===
let bridgeInitialized = false
let tokenReceived = false
/**
* 安卓橋函數:需要 bridge.init()
*/
const androidFunction = (callback: any) => {
console.log('=== 安卓橋函數調用 ===', new Date().toISOString())
if (window.WebViewJavascriptBridge) {
console.log('=== 安卓橋已存在,直接回調 ===')
callback(window.WebViewJavascriptBridge)
} else {
console.log('=== 安卓橋不存在,等待WebViewJavascriptBridgeReady事件 ===')
document.addEventListener('WebViewJavascriptBridgeReady', () => {
console.log('=== 收到WebViewJavascriptBridgeReady事件 ===')
callback(window.WebViewJavascriptBridge)
}, false)
}
}
/**
* iOS 橋函數:用 iframe 觸發注入
*/
const iosFunction = (callback: any) => {
console.log('=== iOS橋函數調用 ===', new Date().toISOString())
if (window.WebViewJavascriptBridge) {
console.log('=== iOS橋已存在,直接回調 ===')
return callback(window.WebViewJavascriptBridge)
}
if (window.WVJBCallbacks) {
console.log('=== iOS橋回調已存在,添加到隊列 ===')
return window.WVJBCallbacks.push(callback)
}
? console.log('=== 創建iOS橋回調隊列和iframe ===')
window.WVJBCallbacks = [callback]
const WVJBIframe = document.createElement('iframe')
WVJBIframe.style.display = 'none'
WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__'
document.documentElement.appendChild(WVJBIframe)
setTimeout(() => {
document.documentElement.removeChild(WVJBIframe)
console.log('=== 移除iOS橋iframe ===')
}, 0)
}
/**
* 處理token注入
*/
const handleTokenInjection = (data: any) => {
console.log('=== 處理token注入 ===', new Date().toISOString())
console.log('原始數據:', data)
console.log('數據類型:', typeof data)
try {
let res = data
if (isAndroid && typeof data === 'string') {
try {
res = JSON.parse(data)
console.log('安卓JSON解析成功:', res)
} catch (e) {
console.error('安卓JSON解析失敗:', e, data)
return
}
}
console.log('處理后的數據:', res)
console.log('數據字段:', Object.keys(res || {}))
// 嘗試多種可能的token字段
const validToken = res['token']
if (validToken) {
console.log('=== 設置token成功 ===', validToken)
setRefreshToken(validToken)
tokenReceived = true
nativeTokenReadyResolve(validToken)
} else {
console.warn('=== 沒有找到有效的token ===')
// 即使沒有token也要resolve,避免無限等待
if (!tokenReceived) {
tokenReceived = true
nativeTokenReadyResolve('')
}
}
// 設置設備版本(如果有的話)
if (res?.['Device-Version']) {
console.log('=== 設置設備版本 ===', res['Device-Version'])
deviceInfo.setdeviceVersion(res['Device-Version'])
}
} catch (error) {
console.error('=== 處理token注入失敗 ===', error, data)
if (!tokenReceived) {
tokenReceived = true
nativeTokenReadyResolve('')
}
}
}
// === 導出的統一橋接初始化函數 ===
export function setupBridge(): any {
if (bridgeInitialized) {
console.log('=== 橋接已初始化,跳過重復初始化 ===')
return
}
console.log('=== 開始初始化橋接 ===', new Date().toISOString())
bridgeInitialized = true
window.setupWebViewJavascriptBridge = isAndroid ? androidFunction : iosFunction
? window.setupWebViewJavascriptBridge((bridge) => {
console.log('=== 橋接回調執行 ===', new Date().toISOString())
console.log('橋接對象:', bridge)
// 注冊原生注入 refreshToken 的方法
bridge.registerHandler('injectRefreshToken', handleTokenInjection)
console.log('=== 已注冊injectRefreshToken處理器 ===')
? ? // 安卓需要調用 bridge.init()
if (isAndroid) {
console.log('=== 調用安卓bridge.init ===')
bridge.init((_msg: any, responseCallback: any) => {
console.log('=== 安卓bridge.init回調 ===', _msg)
responseCallback('H5 已收到')
})
}
})
}
// === 封裝 callHandler 調用 ===
export const bridge = {
callHandler: (methodName: string, params?: any, callback?: any): any => {
console.log('=== 調用橋接方法 ===', methodName, params)
if (window?.setupWebViewJavascriptBridge) {
window.setupWebViewJavascriptBridge((bridge) => {
bridge.callHandler(methodName, params || null, (data: any, fn: any) => {
console.log('=== 橋接方法回調 ===', methodName, data)
callback?.(data, fn)
})
})
} else {
console.warn('=== 橋接未初始化,無法調用方法 ===', methodName)
}
}
}
// === 初始化橋接 ===
if (isNativeMobile) {
console.log('=== 檢測到原生環境,開始初始化 ===', new Date().toISOString())
// 立即初始化
setupBridge()
// 監聽全局事件(兜底方案)
const messageHandler = (event: any) => {
console.log('=== 收到message事件 ===', new Date().toISOString(), event.data)
// 檢查是否是token相關的事件
if (event.data && (event.data.token || event.data.refreshToken || event.data.type === 'injectRefreshToken')) {
console.log('=== 通過message事件收到token ===', event.data)
handleTokenInjection(event.data)
}
}
window.addEventListener('message', messageHandler)
// 延遲初始化(兜底)
setTimeout(() => {
if (!tokenReceived) {
console.log('=== 延遲初始化橋接 ===', new Date().toISOString())
setupBridge()
}
}, 1000)
// 超時處理
setTimeout(() => {
if (!tokenReceived) {
console.warn('=== 10秒內未收到token,可能存在問題 ===')
nativeTokenReadyResolve('')
}
}, 10000)
}
/**
* app攜帶地址欄參數?
* ? native=true
* ? theme=light | dark
*?
* bridge方法名
*/