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://www.pswp.cn/news/921783.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/921783.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++】19. 封装红⿊树实现set和map

文章目录一、源码及框架分析二、模拟实现map和set1、insert的实现2、iterator的实现3、map⽀持[ ]4、模拟实现的完整源代码1&#xff09;RBTree.h2&#xff09;Myset.h3&#xff09;Mymap.h4&#xff09;Test.cpp一、源码及框架分析 SGI-STL30版本源代码&#xff0c;map和set的…

面试不会问题

1. 什么是表锁&#xff1f;什么是行锁&#xff1f;什么情况下会使用表锁&#xff1f;InnoDB引擎通过“索引”实现行锁&#xff08;锁定满足条件的行&#xff09;&#xff0c;但如果操作无法通过索引定位行&#xff0c;会导致行锁失效&#xff0c;进而升级为表锁。常见的表现为&…

达梦数据库-用户,权限,角色

达梦数据库-用户,权限,角色 在达梦数据库(DM8)中,用户(User)、权限(Privilege)和角色(Role) 是数据库安全体系的核心组成部分,用于控制谁可以访问数据库、能访问哪些对象以及能执行哪些操作。 下面为你提供一份全面、详细、结构化的说明,帮助你深入理解达梦数据…

uniapp原生插件 TCP Socket 使用文档

uniapp原生插件 TCP Socket 使用文档 试了插件市场几个TCP Socket插件都不能实现监听服务器主动断开&#xff0c;于是闲来无事就开发了一款&#xff0c;本插件是一个基于 Netty 实现的 TCP 通信模块&#xff0c;用于在 UniApp 插件中提供 TCP 连接、数据发送和连接管理功能。以…

VM中CentOS 7密码重置

重启虚拟机点击e进入内核处理向下划找到UTF-8在后面输入rd.breakctrl X进入单用户模式mount -o remount,rw/sysroot进行挂盘 chroot /sysroot访问系统&#xff0c;并使用passwd修改root密码 出现乱码 输入LANGen touch /.autorelabel 保存配置 exit exit退出等待系统重新打开&…

车规级MOS管AEC-Q101认证的关键参数解读与失效模式-深圳阿赛姆

摘要本文拆解AEC-Q101认证的7大关键测试项&#xff08;UIS/温度循环/THB等&#xff09;&#xff0c;结合M120N06JC等型号实测数据&#xff0c;解析雪崩失效/栅氧击穿/绑定线脱落等故障机理&#xff0c;附选型核查表一、AEC-Q101认证核心测试项与参数解读1.1 非钳位电感开关测试…

嵌入式铁头山羊stm32-ADC实现软件触发的常规序列的单通道转换-Day25

目录 一、实验目的 二、电路连接 三、实验执行&#xff08;五步&#xff09; 1.初始化ADC的IO引脚 2.配置ADC的时钟&#xff0c;注意要小于14MHz 3.根据ADC的编程接口 实现初始化ADC的基本参数 4.配置常规序列并闭合触发输入开关 5.闭合总开关、启动并读取转换结果 四…

多模态模型出现“幻觉”,描述了表格中不存在的内容,如何修正?

在日常工作中&#xff0c;多模态模型的 “幻觉” 问题已成为影响效率的关键痛点 —— 当我们需要模型基于文档生成建议性内容&#xff08;如行业报告分析、论文数据解读等&#xff09;时&#xff0c;模型常因无法准确理解文档信息&#xff0c;输出包含 “虚构内容” 的结果&…

Java AI 智能问数:Function调用版如何重塑企业数据决策

Java AI 智能问数&#xff1a;Function调用版如何重塑企业数据决策 在数字化转型浪潮中&#xff0c;企业一把手常面临数据查询的痛点&#xff1a;分析师需编写复杂SQL&#xff0c;业务人员依赖IT支持&#xff0c;决策链条冗长。传统方法效率低下&#xff0c;而自然语言处理&…

AI-调查研究-74-具身智能 机器人学习新突破:元学习与仿真到现实迁移的挑战与机遇

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; AI炼丹日志-31- 千呼万唤始出来 GPT-5 发布&#xff01;“快的…

劳务员的就业前景如何?

劳务员的就业前景整体较为乐观&#xff0c;受到行业需求、政策支持等因素的积极影响&#xff0c;同时也面临着一些挑战。以下是具体分析&#xff1a;1.就业优势行业需求稳定&#xff1a;建筑行业作为国民经济的支柱产业&#xff0c;持续发展使得对劳务员的需求较为稳定。无论是…

libvirt 新手指南:从零开始掌握虚拟化管理

引言 在云计算、大数据和边缘计算的时代&#xff0c;虚拟化技术已成为 IT 基础设施的核心支柱。它允许我们在单一物理服务器上运行多个虚拟机&#xff08;Virtual Machine&#xff0c;简称 VM&#xff09;&#xff0c;从而实现资源的高效利用、快速部署和灵活扩展。对于新手来说…

OpenLayers数据源集成 -- 章节三:矢量要素图层详解

前言在前面的文章中&#xff0c;我们学习了OpenLayers的瓦片图层&#xff08;TileLayer&#xff09;技术。本文将深入探讨OpenLayers中的矢量要素图层&#xff08;VectorFeatureLayer&#xff09;功能&#xff0c;这是WebGIS开发中处理矢量数据、实现交互式地图的核心技术。矢量…

从“能说话”到“会做事”:AI Agent如何重构日常工作流?

从“能说话”到“会做事”&#xff1a;AI Agent如何重构日常工作流&#xff1f;在人工智能飞速发展的当下&#xff0c;AI已从最初简单的语音交互、信息检索进化到了具备自主决策与行动能力的新阶段&#xff0c;其中AI Agent的出现堪称关键转折点。从只能机械“说话”回答问题&a…

随身wifi到底有没有用?

不用绕弯子&#xff0c;直接说清随身WiFi怎么回事&#xff0c;对比完家用WiFi和手机热点&#xff0c;再避坑&#xff5e;一、先明白&#xff1a;随身WiFi到底是啥&#xff1f; 1、简单讲就是「能揣兜里的WiFi发射器」——要么插张物联卡&#xff0c;要么内置流量&#xff0c;能…

MySQL问题8

MySQL深度分页优化思路 常见的3种优化思路如下&#xff1a; 1. 子查询优化方式 示例改写前&#xff1a; SELECT * FROM words WHERE name oee ORDER BY id LIMIT 99999990, 10;这个写法会导致 MySQL 扫描并丢弃前面 99999990 行&#xff0c;效率极低。 示例改写后&#xff…

洛谷 P1249 最大乘积-普及/提高-

P1249 最大乘积 题目描述 一个正整数一般可以分为几个互不相同的自然数的和&#xff0c;如 312312312&#xff0c;413413413&#xff0c;514235142351423&#xff0c;615246152461524。 现在你的任务是将指定的正整数 nnn 分解成若干个互不相同的自然数&#xff08;也可以不分解…

大学地理信息科学该如何学习才能好就业

一、明确专业特点与就业方向地理信息科学是一门交叉性强、实践性强的学科&#xff0c;融合了地理学、计算机科学、测绘、遥感等多个领域&#xff0c;广泛应用于自然资源管理、城市规划、交通、环境、农业、水利、智慧城市等行业。主要就业方向包括&#xff1a;政府部门/事业单位…

【git】Git 大文件推送失败问题及解决方案

Git 大文件推送失败问题及解决方案 在日常开发中&#xff0c;我们经常会遇到这样的问题&#xff1a; Remote: File [xxx.exe] size 188.156MB, exceeds quota 100MB Remote: Please remove the file[s] from history and try again这是因为 Gitee/GitHub 等平台对单个文件大小有…

国产银河麒麟三维数字沙盘大数据可视化研训推演模拟仿真地理信息系统

国产银河麒麟三维数字沙盘大数据可视化研训推演模拟仿真地理信息系统独立自主知识产权和原创源代码级地理信息系统平台&#xff0c;核心引擎与算法实现全栈国产化&#xff0c;提供从数据采集、处理到可视化分析的全链条自主可控解决方案&#xff0c; 1.2支持国产操作系统&…