feat(app连接文件): 整理代码结构

This commit is contained in:
hzj 2026-01-19 12:16:32 +08:00
parent 133e950dec
commit 37c154a587

View File

@ -5,6 +5,8 @@
import { COMMON_HEADERS } from '@/utils/http.js' import { COMMON_HEADERS } from '@/utils/http.js'
// ==================== 工具函数 ====================
/** /**
* 检测是否为iOS系统 * 检测是否为iOS系统
* @returns {boolean} * @returns {boolean}
@ -29,156 +31,28 @@ export function isInApp() {
return !!(window.app || window.webkit || window.FlutterPageControl) 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()
}
}
/** /**
* 前往私聊 * 安全的日志函数避免 iOS WebView 中的 "JavaScript execution returned a result of an unsupported type" 错误
* @param {string} level - 日志级别 ('log', 'debug', 'warn', 'error')
* @param {...any} args - 日志参数
*/ */
export function gotoPrivateChat(userId) { function createSafeLogger() {
if (!userId) return return function safeConsoleLog(level, ...args) {
try {
console.log(`userId:${userId}`)
if (window.app && window.app.gotoPrivateChat) {
console.log('使用gotoPrivateChat')
// 使用注入的方法
window.app.gotoPrivateChat(userId)
} else if (window.FlutterPageControl) {
// 直接使用Flutter通道
window.FlutterPageControl.postMessage(`private_chat:${userId}`)
}
} catch (error) {
console.error('前往私聊失败:', error)
}
}
/**
* 查看个人页面
*/
export function viewUserInfo(userId) {
if (!userId) return
try {
console.log(`userId:${userId}`)
if (window.app && window.app.viewUserInfo) {
console.log('使用viewUserInfo')
// 使用注入的方法
window.app.viewUserInfo(userId)
} else if (window.FlutterPageControl) {
// 直接使用Flutter通道
window.FlutterPageControl.postMessage(`view_user_info:${userId}`)
}
} catch (error) {
console.error('查看个人页面失败:', error)
}
}
/**
* 前往房间
*/
export function gotoRoom(roomId) {
if (!roomId) return
try {
console.log(`roomId:${roomId}`)
if (window.app && window.app.gotoRoom) {
console.log('使用gotoRoom')
// 使用注入的方法
window.app.gotoRoom(roomId)
} else if (window.FlutterPageControl) {
// 直接使用Flutter通道
window.FlutterPageControl.postMessage(`go_to_room:${roomId}`)
}
} catch (error) {
console.error('前往房间失败:', error)
}
}
/**
* 前往app页面
*/
export function gotoAppPage(pageName) {
if (!pageName) return
try {
console.log(`pageName:${pageName}`)
// 直接使用Flutter通道
window.FlutterPageControl.postMessage(pageName)
} catch (error) {
console.error('前往APP页面失败:', error)
}
}
/**
* 退出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
// 安全日志函数
const safeConsoleLog = (level, ...args) => {
if (process.env.NODE_ENV === 'production') return if (process.env.NODE_ENV === 'production') return
try { try {
if (ios()) { if (ios()) {
// 对 iOS 设备进行特殊处理
const processedArgs = args.map((arg) => { const processedArgs = args.map((arg) => {
if (typeof arg === 'object' && arg !== null) { if (typeof arg === 'object' && arg !== null) {
try { try {
// 序列化对象,避免循环引用
return JSON.stringify( return JSON.stringify(
arg, arg,
(key, value) => { (key, value) => {
// 处理特殊对象类型
if (value instanceof HTMLElement) return '[HTMLElement]' if (value instanceof HTMLElement) return '[HTMLElement]'
if (typeof value === 'function') return '[Function]' if (typeof value === 'function') return '[Function]'
if (value instanceof Date) return value.toISOString() if (value instanceof Date) return value.toISOString()
@ -203,6 +77,7 @@ export function connectApplication(renderFun) {
}) })
console[level](...processedArgs) console[level](...processedArgs)
} else { } else {
// 非 iOS 设备正常使用
console[level](...args) console[level](...args)
} }
} catch (e) { } catch (e) {
@ -211,13 +86,22 @@ export function connectApplication(renderFun) {
} }
} }
} }
}
// 创建日志函数实例
const safeConsoleLog = createSafeLogger()
const debugLog = (...args) => safeConsoleLog('debug', ...args) const debugLog = (...args) => safeConsoleLog('debug', ...args)
const errorLog = (...args) => safeConsoleLog('error', ...args) const errorLog = (...args) => safeConsoleLog('error', ...args)
const warnLog = (...args) => safeConsoleLog('warn', ...args)
const infoLog = (...args) => safeConsoleLog('log', ...args)
try { // ==================== 平台特定处理函数 ====================
// 安卓设备环境
if (android()) { /**
* Android 平台处理逻辑
* @param {Function} renderFun - 回调函数
*/
function handleAndroidPlatform(renderFun) {
debugLog('Flutter Android WebView 检测') debugLog('Flutter Android WebView 检测')
debugLog('window.app 对象:', window.app) debugLog('window.app 对象:', window.app)
@ -246,17 +130,19 @@ export function connectApplication(renderFun) {
typeof window.app.getAccessOrigin === 'function' typeof window.app.getAccessOrigin === 'function'
) { ) {
debugLog('Flutter接口检测成功调用 getAccessOrigin') debugLog('Flutter接口检测成功调用 getAccessOrigin')
try { try {
const result = window.app.getAccessOrigin() const result = window.app.getAccessOrigin() // 直接同步调用获取数据
debugLog('getAccessOrigin 返回结果:', result) debugLog('getAccessOrigin 返回结果:', result)
renderFun(result) renderFun(result) // 传递给回调函数
} catch (error) { } catch (error) {
errorLog('调用 getAccessOrigin 出错:', error) errorLog('调用 getAccessOrigin 出错:', error)
} }
} else if (attempts < maxAttempts) { } else if (attempts < maxAttempts) {
// 继续等待 // 没找到,继续查询
setTimeout(checkInterface, 100) setTimeout(checkInterface, 100)
} else { } else {
// 查询次数用完
errorLog('Flutter接口注入超时使用默认数据') errorLog('Flutter接口注入超时使用默认数据')
// 使用默认的开发数据 // 使用默认的开发数据
const mockAccess = JSON.stringify({ const mockAccess = JSON.stringify({
@ -272,10 +158,11 @@ export function connectApplication(renderFun) {
checkInterface() checkInterface()
} }
// 如果window.app已存在直接检查,否则等待 // window.app已存在直接检查
if (window.app) { if (window.app) {
waitForFlutterInterface() waitForFlutterInterface()
} else { } else {
// window.app不存在等待注入
debugLog('等待Flutter注入window.app...') debugLog('等待Flutter注入window.app...')
// 监听window.app的创建 // 监听window.app的创建
let checkCount = 0 let checkCount = 0
@ -298,8 +185,11 @@ export function connectApplication(renderFun) {
} }
} }
// 苹果设备环境 /**
else if (ios()) { * iOS 平台处理逻辑
* @param {Function} renderFun - 回调函数
*/
function handleIOSPlatform(renderFun) {
debugLog('iOS access detected') debugLog('iOS access detected')
// iOS WebKit 消息处理器检测和等待 // iOS WebKit 消息处理器检测和等待
@ -317,6 +207,7 @@ export function connectApplication(renderFun) {
window.webkit.messageHandlers.getAccessOrigin window.webkit.messageHandlers.getAccessOrigin
) { ) {
debugLog('iOS接口检测成功调用 getAccessOrigin') debugLog('iOS接口检测成功调用 getAccessOrigin')
try { try {
// iOS的postMessage是异步的需要通过回调处理 // iOS的postMessage是异步的需要通过回调处理
window.webkit.messageHandlers.getAccessOrigin.postMessage({}) window.webkit.messageHandlers.getAccessOrigin.postMessage({})
@ -324,7 +215,7 @@ export function connectApplication(renderFun) {
// 设置全局回调函数来接收iOS返回的数据 // 设置全局回调函数来接收iOS返回的数据
window.receiveAccessOrigin = function (accessData) { window.receiveAccessOrigin = function (accessData) {
debugLog('收到iOS返回的access数据:', accessData) debugLog('收到iOS返回的access数据:', accessData)
renderFun(accessData) renderFun(accessData) // 接收数据后传递给回调函数
} }
} catch (error) { } catch (error) {
errorLog('调用 getAccessOrigin 出错:', error) errorLog('调用 getAccessOrigin 出错:', error)
@ -338,9 +229,10 @@ export function connectApplication(renderFun) {
renderFun(mockAccess) renderFun(mockAccess)
} }
} else if (attempts < maxAttempts) { } else if (attempts < maxAttempts) {
// 继续等待 // 没找到,继续查询
setTimeout(checkIOSInterface, 100) setTimeout(checkIOSInterface, 100)
} else { } else {
// 查询次数用完
errorLog('iOS接口注入超时使用默认数据') errorLog('iOS接口注入超时使用默认数据')
const mockAccess = JSON.stringify({ const mockAccess = JSON.stringify({
Authorization: 'Bearer IOS_MOCK_TOKEN', Authorization: 'Bearer IOS_MOCK_TOKEN',
@ -355,9 +247,8 @@ export function connectApplication(renderFun) {
checkIOSInterface() checkIOSInterface()
} }
// 检查 window.app 是否存在某些情况下iOS也可能注入window.app // window.app 存在某些情况下iOS也可能注入window.app
if (window.app && typeof window.app.getAccessOrigin === 'function') { if (window.app && typeof window.app.getAccessOrigin === 'function') {
debugLog('检测到window.app尝试调用getAccessOrigin')
try { try {
const result = window.app.getAccessOrigin() const result = window.app.getAccessOrigin()
debugLog('window.app.getAccessOrigin 返回结果:', result) debugLog('window.app.getAccessOrigin 返回结果:', result)
@ -367,13 +258,17 @@ export function connectApplication(renderFun) {
waitForIOSInterface() // 尝试WebKit方式 waitForIOSInterface() // 尝试WebKit方式
} }
} else { } else {
// window.app不存在等待注入
debugLog('等待iOS WebKit接口注入...') debugLog('等待iOS WebKit接口注入...')
waitForIOSInterface() waitForIOSInterface()
} }
} }
// 浏览器环境 /**
else { * Web 浏览器环境处理逻辑
* @param {Function} renderFun - 回调函数
*/
function handleWebPlatform(renderFun) {
debugLog('非移动设备环境') debugLog('非移动设备环境')
// 非APP环境可能是浏览器调试 // 非APP环境可能是浏览器调试
console.warn('Not in APP environment, using mock data for development') console.warn('Not in APP environment, using mock data for development')
@ -388,11 +283,164 @@ export function connectApplication(renderFun) {
setTimeout(() => renderFun(mockAccess), 100) setTimeout(() => renderFun(mockAccess), 100)
} }
} }
// ==================== 主要功能函数 ====================
/**
* 连接APP并获取访问参数
* @param {Function} renderFun 回调函数接收APP传递的access参数
*/
export function connectApplication(renderFun) {
window.renderData = renderFun
// 兼容历史版本
window.getIosAccessOriginParam = renderFun
try {
if (android()) {
handleAndroidPlatform(renderFun)
} else if (ios()) {
handleIOSPlatform(renderFun)
} else {
handleWebPlatform(renderFun)
}
} catch (error) { } catch (error) {
errorLog('Failed to connect to APP:', error) errorLog('Failed to connect to APP:', error)
} }
} }
// ==================== APP 通信函数 ====================
/**
* 关闭当前页面返回到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) {
errorLog('关闭页面失败:', error)
// 降级处理
window.history.back()
}
}
/**
* 前往私聊
*/
export function gotoPrivateChat(userId) {
if (!userId) return
try {
infoLog(`userId:${userId}`)
if (window.app && window.app.gotoPrivateChat) {
infoLog('使用gotoPrivateChat')
// 使用注入的方法
window.app.gotoPrivateChat(userId)
} else if (window.FlutterPageControl) {
// 直接使用Flutter通道
window.FlutterPageControl.postMessage(`private_chat:${userId}`)
}
} catch (error) {
errorLog('前往私聊失败:', error)
}
}
/**
* 查看个人页面
*/
export function viewUserInfo(userId) {
if (!userId) return
try {
infoLog(`userId:${userId}`)
if (window.app && window.app.viewUserInfo) {
infoLog('使用viewUserInfo')
// 使用注入的方法
window.app.viewUserInfo(userId)
} else if (window.FlutterPageControl) {
// 直接使用Flutter通道
window.FlutterPageControl.postMessage(`view_user_info:${userId}`)
}
} catch (error) {
errorLog('查看个人页面失败:', error)
}
}
/**
* 前往房间
*/
export function gotoRoom(roomId) {
if (!roomId) return
try {
infoLog(`roomId:${roomId}`)
if (window.app && window.app.gotoRoom) {
infoLog('使用gotoRoom')
// 使用注入的方法
window.app.gotoRoom(roomId)
} else if (window.FlutterPageControl) {
// 直接使用Flutter通道
window.FlutterPageControl.postMessage(`go_to_room:${roomId}`)
}
} catch (error) {
errorLog('前往房间失败:', error)
}
}
/**
* 前往app页面
*/
export function gotoAppPage(pageName) {
if (!pageName) return
try {
infoLog(`pageName:${pageName}`)
// 直接使用Flutter通道
window.FlutterPageControl.postMessage(pageName)
} catch (error) {
errorLog('前往APP页面失败:', error)
}
}
/**
* 退出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) {
errorLog('退出APP失败:', error)
}
}
/**
* 处理返回按钮逻辑
* @param {boolean} isHomePage 是否为首页
*/
export function handleBackButton(isHomePage = false) {
if (isHomePage) {
// 首页返回:关闭页面
closePage()
} else {
// 非首页:正常返回
window.history.back()
}
}
// ==================== 数据解析函数 ====================
/** /**
* 解析APP传递的访问参数 * 解析APP传递的访问参数
* @param {string} access JSON字符串格式的访问参数 * @param {string} access JSON字符串格式的访问参数
@ -406,7 +454,7 @@ export function parseAccessOrigin(access) {
data: accessParam, data: accessParam,
} }
} catch (error) { } catch (error) {
console.error('Failed to parse access origin:', error) errorLog('Failed to parse access origin:', error)
return { return {
success: false, success: false,
error: 'accessOrigin Error.', error: 'accessOrigin Error.',
@ -415,22 +463,12 @@ export function parseAccessOrigin(access) {
} }
} }
/**
* 解析请求头信息
* @param {Object} head 请求头对象
* @returns {Object} 解析后的头信息
*/
export function parseHeader(head) {
if (!head) {
return {}
}
/** /**
* 解析键值对字符串 (: "key1=value1;key2=value2") * 解析键值对字符串 (: "key1=value1;key2=value2")
* @param {string} values * @param {string} values
* @returns {Object} * @returns {Object}
*/ */
function getKeyValObj(values) { function parseKeyValString(values) {
const keyValBody = {} const keyValBody = {}
if (!values) return keyValBody if (!values) return keyValBody
@ -445,10 +483,20 @@ export function parseHeader(head) {
return keyValBody return keyValBody
} }
/**
* 解析请求头信息
* @param {Object} head 请求头对象
* @returns {Object} 解析后的头信息
*/
export function parseHeader(head) {
if (!head) {
return {}
}
const reqAppIntel = head['Req-App-Intel'] || '' const reqAppIntel = head['Req-App-Intel'] || ''
const reqSysOrigin = head['Req-Sys-Origin'] || '' const reqSysOrigin = head['Req-Sys-Origin'] || ''
const reqAppIntelObj = getKeyValObj(reqAppIntel) const reqAppIntelObj = parseKeyValString(reqAppIntel)
const reqSysOriginObj = getKeyValObj(reqSysOrigin) const reqSysOriginObj = parseKeyValString(reqSysOrigin)
return { return {
reqLang: head['Req-Lang'], reqLang: head['Req-Lang'],
@ -473,12 +521,12 @@ export async function setHttpHeaders(headerInfo) {
httpModule.setHeadersFromApp(headerInfo) httpModule.setHeadersFromApp(headerInfo)
} }
} catch (error) { } catch (error) {
console.error('Failed to update HTTP headers:', error) errorLog('Failed to update HTTP headers:', error)
} }
console.debug('🔑 Authorization token set:', headerInfo.authorization) debugLog('🔑 Authorization token set:', headerInfo.authorization)
console.debug('🌍 Language set:', headerInfo.reqLang) debugLog('🌍 Language set:', headerInfo.reqLang)
console.debug('📱 App info:', { debugLog('📱 App info:', {
version: headerInfo.appVersion, version: headerInfo.appVersion,
build: headerInfo.buildVersion, build: headerInfo.buildVersion,
channel: headerInfo.appChannel, channel: headerInfo.appChannel,