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

*/

相关推荐
Mr Xu_3 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js
未来龙皇小蓝3 小时前
RBAC前端架构-01:项目初始化
前端·架构
程序员agions4 小时前
2026年,微前端终于“死“了
前端·状态模式
万岳科技系统开发4 小时前
食堂采购系统源码库存扣减算法与并发控制实现详解
java·前端·数据库·算法
程序员猫哥_4 小时前
HTML 生成网页工具推荐:从手写代码到 AI 自动生成网页的进化路径
前端·人工智能·html
龙飞054 小时前
Systemd -systemctl - journalctl 速查表:服务管理 + 日志排障
linux·运维·前端·chrome·systemctl·journalctl
我爱加班、、4 小时前
Websocket能携带token过去后端吗
前端·后端·websocket
AAA阿giao4 小时前
从零拆解一个 React + TypeScript 的 TodoList:模块化、数据流与工程实践
前端·react.js·ui·typescript·前端框架
杨超越luckly4 小时前
HTML应用指南:利用GET请求获取中国500强企业名单,揭秘企业增长、分化与转型的新常态
前端·数据库·html·可视化·中国500强
一 乐4 小时前
校园二手交易|基于springboot + vue校园二手交易系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端