aslan-h5/src/utils/appBridge.js
2025-08-22 14:41:35 +08:00

297 lines
8.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* APP桥接工具函数
* 用于H5页面与原生APP之间的通信
*/
import {COMMON_HEADERS} from "@/utils/http.js";
/**
* 检测是否为iOS系统
* @returns {boolean}
*/
export function ios() {
return /iPad|iPhone|iPod/.test(navigator.userAgent)
}
/**
* 检测是否为Android系统
* @returns {boolean}
*/
export function android() {
return /Android/.test(navigator.userAgent)
}
/**
* 检测是否在APP环境中
* @returns {boolean}
*/
export function isInApp() {
return !!(window.app || window.webkit || window.FlutterPageControl)
}
/**
* 关闭当前页面返回到Flutter上一页
*/
export function closePage() {
try {
if (window.app && window.app.closePage) {
// 使用注入的方法
window.app.closePage()
} else if (window.FlutterPageControl) {
// 直接使用Flutter通道
window.FlutterPageControl.postMessage('close_page')
} else {
// 降级处理:浏览器环境
// if (window.history.length > 1) {
// window.history.back()
// } else {
// window.close()
// }
}
} catch (error) {
console.error('关闭页面失败:', error)
// 降级处理
window.history.back()
}
}
/**
* 退出APP
*/
export function exitApp() {
try {
if (window.app && window.app.exitApp) {
window.app.exitApp()
} else if (window.FlutterPageControl) {
window.FlutterPageControl.postMessage('exit_app')
}
} catch (error) {
console.error('退出APP失败:', error)
}
}
/**
* 处理返回按钮逻辑
* @param {boolean} isHomePage 是否为首页
*/
export function handleBackButton(isHomePage = false) {
if (isHomePage) {
// 首页返回:关闭页面
closePage()
} else {
// 非首页:正常返回
window.history.back()
}
}
/**
* 连接APP并获取访问参数
* @param {Function} renderFun 回调函数接收APP传递的access参数
*/
export function connectApplication(renderFun) {
window.renderData = renderFun
// 兼容历史版本
window.getIosAccessOriginParam = renderFun
try {
if (android()) {
console.debug('Flutter Android WebView 检测')
console.debug('window.app 对象:', window.app)
// 检查Flutter注入的接口
if (window.app) {
console.debug('window.app 的所有方法:')
console.debug(Object.keys(window.app))
// 检查具体的方法
console.debug('getAccessOrigin 方法存在?', typeof window.app.getAccessOrigin)
console.debug('getAccessOrigin 是函数?', typeof window.app.getAccessOrigin === 'function')
}
// 等待Flutter注入完成
const waitForFlutterInterface = () => {
let attempts = 0;
const maxAttempts = 50; // 最多等待5秒
const checkInterface = () => {
attempts++;
console.debug(`尝试第 ${attempts} 次检查Flutter接口...`)
if (window.app && window.app.getAccessOrigin && typeof window.app.getAccessOrigin === 'function') {
console.debug('Flutter接口检测成功调用 getAccessOrigin')
try {
const result = window.app.getAccessOrigin()
console.debug('getAccessOrigin 返回结果:', result)
renderFun(result)
} catch (error) {
console.error('调用 getAccessOrigin 出错:', error)
}
} else if (attempts < maxAttempts) {
// 继续等待
setTimeout(checkInterface, 100)
} else {
console.error('Flutter接口注入超时使用默认数据')
// 使用默认的开发数据
const mockAccess = JSON.stringify({
'Authorization': 'Bearer FLUTTER_MOCK_TOKEN',
'Req-Lang': 'en',
'Req-App-Intel': 'build=1.0;version=2.1;channel=flutter;Req-Imei=flutter-device',
'Req-Sys-Origin': 'origin=LIKEI;originChild=LIKEI'
})
renderFun(mockAccess)
}
}
checkInterface()
}
// 如果window.app已存在直接检查否则等待
if (window.app) {
waitForFlutterInterface()
} else {
console.debug('等待Flutter注入window.app...')
// 监听window.app的创建
let checkCount = 0
const checkApp = () => {
checkCount++
if (window.app) {
console.debug('检测到window.app开始连接')
waitForFlutterInterface()
} else if (checkCount < 50) {
setTimeout(checkApp, 100)
} else {
console.error('等待window.app超时')
// 手动通知Flutter注入接口
if (window.FlutterApp && window.FlutterApp.postMessage) {
window.FlutterApp.postMessage('requestAccessOrigin')
}
}
}
checkApp()
}
}
/*else if (ios()) {
console.debug('ios access detected')
// iOS可能需要特殊处理这里先使用通用方法
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.getAccessOrigin) {
window.webkit.messageHandlers.getAccessOrigin.postMessage({})
} else if (window.app && window.app.getAccessOrigin) {
renderFun(window.app.getAccessOrigin())
}
}*/
else {
console.debug('非移动设备环境')
// 非APP环境可能是浏览器调试
console.warn('Not in APP environment, using mock data for development')
// 开发环境可以提供模拟数据
if (process.env.NODE_ENV === 'development') {
const mockAccess = JSON.stringify({
'Authorization': COMMON_HEADERS.authorization,
'Req-Lang': COMMON_HEADERS['req-lang'],
'Req-App-Intel': COMMON_HEADERS['req-app-intel'],
'Req-Sys-Origin': COMMON_HEADERS['req-sys-origin']
})
setTimeout(() => renderFun(mockAccess), 100)
}
}
} catch (error) {
console.error('Failed to connect to APP:', error)
}
}
/**
* 解析APP传递的访问参数
* @param {string} access JSON字符串格式的访问参数
* @returns {Object} 解析后的参数对象
*/
export function parseAccessOrigin(access) {
try {
const accessParam = JSON.parse(access)
return {
success: true,
data: accessParam
}
} catch (error) {
console.error('Failed to parse access origin:', error)
return {
success: false,
error: 'accessOrigin Error.',
data: null
}
}
}
/**
* 解析请求头信息
* @param {Object} head 请求头对象
* @returns {Object} 解析后的头信息
*/
export function parseHeader(head) {
if (!head) {
return {}
}
/**
* 解析键值对字符串 (如: "key1=value1;key2=value2")
* @param {string} values
* @returns {Object}
*/
function getKeyValObj(values) {
const keyValBody = {}
if (!values) return keyValBody
const valueArray = values.split(';')
for (let index = 0; index < valueArray.length; index++) {
const keyVal = valueArray[index]
if (keyVal && keyVal.includes('=')) {
const keyValArray = keyVal.split('=')
keyValBody[keyValArray[0]] = keyValArray[1]
}
}
return keyValBody
}
const reqAppIntel = head['Req-App-Intel'] || ''
const reqSysOrigin = head['Req-Sys-Origin'] || ''
const reqAppIntelObj = getKeyValObj(reqAppIntel)
const reqSysOriginObj = getKeyValObj(reqSysOrigin)
return {
reqLang: head['Req-Lang'],
authorization: head['Authorization'],
buildVersion: reqAppIntelObj['build'],
appVersion: reqAppIntelObj['version'],
appChannel: reqAppIntelObj['channel'],
reqImei: reqAppIntelObj['Req-Imei'],
sysOrigin: reqSysOriginObj['origin'],
sysOriginChild: reqSysOriginObj['child']
}
}
/**
* 设置HTTP请求的默认头部信息
* @param {Object} headerInfo 解析后的头部信息
*/
export async function setHttpHeaders(headerInfo) {
try {
const httpModule = await import('../utils/http.js')
if (httpModule.setHeadersFromApp) {
httpModule.setHeadersFromApp(headerInfo)
}
} catch(error) {
console.error('Failed to update HTTP headers:', error)
}
console.debug('🔑 Authorization token set:', headerInfo.authorization)
console.debug('🌍 Language set:', headerInfo.reqLang)
console.debug('📱 App info:', {
version: headerInfo.appVersion,
build: headerInfo.buildVersion,
channel: headerInfo.appChannel,
system: headerInfo.sysOrigin
})
}