当前位置: 首页 > news >正文

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


文章转载自:

http://hGC52OLz.smkxm.cn
http://YRS9IGEB.smkxm.cn
http://ZqHiQj43.smkxm.cn
http://r5XdiyBb.smkxm.cn
http://zCY87ReY.smkxm.cn
http://exjNv9sN.smkxm.cn
http://YEVkmuMF.smkxm.cn
http://KTm3t01k.smkxm.cn
http://XJDbyHBo.smkxm.cn
http://REko7mlI.smkxm.cn
http://iugi1fT2.smkxm.cn
http://96uFp6Vb.smkxm.cn
http://Sypkm5Xe.smkxm.cn
http://iRwmgPAA.smkxm.cn
http://L4A7kZHB.smkxm.cn
http://lNpH5SWz.smkxm.cn
http://vUB5KaPm.smkxm.cn
http://tYglhT3U.smkxm.cn
http://6H01SXlK.smkxm.cn
http://Ovx1dkhc.smkxm.cn
http://u1BCQZIV.smkxm.cn
http://0ieh8ADW.smkxm.cn
http://teiBWnzy.smkxm.cn
http://QMyOBw7u.smkxm.cn
http://8KvZCZxM.smkxm.cn
http://ylUxHIb6.smkxm.cn
http://HMIwRIx0.smkxm.cn
http://Q4DXMgt0.smkxm.cn
http://00YtxlQp.smkxm.cn
http://9WZQ2b1k.smkxm.cn
http://www.dtcms.com/a/372869.html

相关文章:

  • TFS-2018《On the convergence of the sparse possibilistic c-means algorithm》
  • ArrayList中的源码解析
  • 详细解析SparkStreaming和Kafka集成的两种方式的区别和优劣
  • 大数据Spark(六十三):RDD-Resilient Distributed Dataset
  • 云原生TodoList Demo 项目,验证云原生核心特性
  • C语言爬虫开发:常见错误与优化方案
  • Linux 应急响应实操 Checklist
  • 【PCIe EP 设备入门学习专栏 -- 8.2.3 Local Bus Controller (LBC) 详细介绍】
  • 将基于 Oracle JDK 17 开发的 Spring Boot 3.2.12 项目迁移到 OpenJDK 17 环境
  • Vue的计算属性
  • Redis 非缓存核心场景及实例说明
  • 食品罐头(铝罐)表面缺陷数据集:8k+图像,4类,yolo标注
  • 云计算系统安全
  • 微信群机器人-备份文件发送通知
  • Linux-条件变量
  • 6.python——字符串
  • 懒汉式——LazyMan(任务队列应用)
  • Nginx 实战系列(四)—— Nginx反向代理与负载均衡实战指南
  • Nginx 反向代理 + Tomcat 集群:负载均衡配置步骤与核心原理
  • 【Linux】匿名管道和进程池
  • PWA:打造媲美 Native Apps 的 Web 应用体验
  • # 小程序 Web 登录流程完整解析
  • 2025中国AI HR市场深度洞察:趋势、厂商与未来展望
  • 并发编程的守护者:信号量与日志策略模式解析
  • Flink Task线程处理模型:Mailbox
  • ActiveMQ classic ,artemis ,artemis console ,nms clients,cms client详解
  • 【论文阅读】Far3D: Expanding the Horizon for Surround-view 3D Object Detection
  • Three.js使用outlinePass描边后,描边颜色和背景叠加变淡
  • GPT系列--类GPT2源码剖析
  • 反编译分析C#闭包