jsBridge接入流程

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方法名

*/

相关推荐
老毛肚5 分钟前
jeecgboot TS + Vue 模板化 03
前端·javascript·vue.js
小林ixn5 分钟前
揭秘JavaScript面向对象:从栈模拟队列到原型链的深度剖析
javascript
下北沢美食家8 分钟前
SSE 入门
前端
云计算磊哥@8 分钟前
运维开发宝典023-WEB网站服务
运维·前端·运维开发
FlyWIHTSKY11 分钟前
React 19 + Next.js 16(App Router)项目中集成 MSW
开发语言·javascript·vue.js
冰暮流星31 分钟前
javascript之对象的建立-使用Object
开发语言·javascript·ecmascript
加点油。。。。32 分钟前
【1.Obsidian渲染html文件】
前端·html·obsidian
ZFSS33 分钟前
BYOK(自带密钥)使用指南
运维·服务器·前端·人工智能·midjourney
AI_零食33 分钟前
呼吸灯 - 通过鸿蒙PC Electron框架技术完成-在焦虑时代守护每一次呼吸的数字禅修
前端·javascript·华为·electron·前端框架·鸿蒙
佛山个人技术开发40 分钟前
高端旅游风景区酒店民宿网站模板 自适应宽屏文旅酒店源码
前端·html5·旅游