diff --git a/public/app-bridge-test.html b/public/app-bridge-test.html new file mode 100644 index 0000000..2cab7ca --- /dev/null +++ b/public/app-bridge-test.html @@ -0,0 +1,271 @@ + + + + + + APP Bridge Test + + + +
+

APP Bridge 通信测试

+ +
+

环境检测

+
+ 检测中... + +
+
+
+ +
+

APP对象检测

+ +
+
+ +
+

模拟APP调用

+ + + +
+
+ +
+

连接APP测试

+ +
+
+
+ + + + diff --git a/src/router/index.js b/src/router/index.js index 2ddc611..f25d044 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -95,6 +95,11 @@ const router = createRouter({ name: 'agency-center', component: () => import('../views/AgencyCenterView.vue'), }, + { + path: '/not_app', + name: 'not-app', + component: () => import('../views/NotAppView.vue'), + }, ], }) diff --git a/src/utils/appBridge.js b/src/utils/appBridge.js new file mode 100644 index 0000000..32f0704 --- /dev/null +++ b/src/utils/appBridge.js @@ -0,0 +1,162 @@ +/** + * APP桥接工具函数 + * 用于H5页面与原生APP之间的通信 + */ + +/** + * 检测是否为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) +} + +/** + * 连接APP并获取访问参数 + * @param {Function} renderFun 回调函数,接收APP传递的access参数 + */ +export function connectApplication(renderFun) { + window.renderData = renderFun + // 兼容历史版本 + window.getIosAccessOriginParam = renderFun + + try { + if (ios()) { + // 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 if (android()) { + // Android处理 + if (window.app && window.app.getAccessOrigin) { + renderFun(window.app.getAccessOrigin()) + } + } else { + // 非APP环境,可能是浏览器调试 + console.warn('Not in APP environment, using mock data for development') + // 开发环境可以提供模拟数据 + if (process.env.NODE_ENV === 'development') { + const mockAccess = JSON.stringify({ + 'Authorization': 'Bearer mock-token-for-development', + 'Req-Lang': 'en', + 'Req-App-Intel': 'build=1.0;version=2.1;channel=official;Req-Imei=mock-imei', + 'Req-Sys-Origin': 'origin=web;child=browser' + }) + 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 function setHttpHeaders(headerInfo) { + // 动态导入http.js中的函数来避免循环依赖 + import('../utils/http.js').then(httpModule => { + if (httpModule.setHeadersFromApp) { + httpModule.setHeadersFromApp(headerInfo) + } + }).catch(error => { + console.error('Failed to update HTTP headers:', error) + }) + + console.log('🔑 Authorization token set:', headerInfo.authorization) + console.log('🌍 Language set:', headerInfo.reqLang) + console.log('📱 App info:', { + version: headerInfo.appVersion, + build: headerInfo.buildVersion, + channel: headerInfo.appChannel, + system: headerInfo.sysOrigin + }) +} diff --git a/src/utils/http.js b/src/utils/http.js index 2749b3f..27a7b44 100644 --- a/src/utils/http.js +++ b/src/utils/http.js @@ -1,8 +1,8 @@ // HTTP请求配置 const API_BASE_URL = 'https://api.likeichat.com' -// 公共请求头配置 -const COMMON_HEADERS = { +// 默认公共请求头配置 +let COMMON_HEADERS = { 'authorization': 'Bearer F77126B08E13987C3AD88B6015C5B777.djIlM0ExOTU0MDU5NzkzOTYzMzkzMDI1JTNBTElLRUklM0ExNzU3NzYzODU5NzE1JTNBMTc1NTE3MTg1OTcxNQ==', 'req-app-intel': 'version=1.0.0;build=1;model=SM-G9550;sysVersion=9;channel=Google', 'req-client': 'Android', @@ -13,6 +13,64 @@ const COMMON_HEADERS = { 'req-zone': 'Asia/Shanghai', } +/** + * 更新公共请求头 + * @param {object} headers - 要更新的请求头 + */ +export function updateCommonHeaders(headers) { + COMMON_HEADERS = { + ...COMMON_HEADERS, + ...headers + } + console.log('🔄 Updated common headers:', COMMON_HEADERS) +} + +/** + * 从APP头部信息设置HTTP请求头 + * @param {object} headerInfo - APP传递的头部信息 + */ +export function setHeadersFromApp(headerInfo) { + const updatedHeaders = {} + + // 设置Authorization + if (headerInfo.authorization) { + updatedHeaders.authorization = headerInfo.authorization + } + + // 设置语言 + if (headerInfo.reqLang) { + updatedHeaders['req-lang'] = headerInfo.reqLang + } + + // 设置APP信息 + if (headerInfo.appVersion || headerInfo.buildVersion || headerInfo.appChannel) { + const appIntelParts = [] + if (headerInfo.appVersion) appIntelParts.push(`version=${headerInfo.appVersion}`) + if (headerInfo.buildVersion) appIntelParts.push(`build=${headerInfo.buildVersion}`) + if (headerInfo.appChannel) appIntelParts.push(`channel=${headerInfo.appChannel}`) + + if (appIntelParts.length > 0) { + updatedHeaders['req-app-intel'] = appIntelParts.join(';') + } + } + + // 设置设备信息 + if (headerInfo.reqImei) { + updatedHeaders['req-imei'] = headerInfo.reqImei + } + + // 设置系统来源 + if (headerInfo.sysOrigin) { + const sysOriginParts = [`origin=${headerInfo.sysOrigin}`] + if (headerInfo.sysOriginChild) { + sysOriginParts.push(`child=${headerInfo.sysOriginChild}`) + } + updatedHeaders['req-sys-origin'] = sysOriginParts.join(';') + } + + updateCommonHeaders(updatedHeaders) +} + /** * 通用HTTP请求函数 * @param {string} url - 请求URL diff --git a/src/views/HostCenterView.vue b/src/views/HostCenterView.vue index 05c7c61..e94e183 100644 --- a/src/views/HostCenterView.vue +++ b/src/views/HostCenterView.vue @@ -7,6 +7,16 @@
+ +
+
+ 正在连接APP... +
+
+
+ 已连接 +
+ -
-
-

Team ID:

-
- {{ teamId }} - -
-
- -
@@ -88,7 +60,7 @@ const shareToWeChat = () => { // 分享链接 const shareLink = () => { const shareText = `Join my team! Team ID: ${teamId.value}\nDownload Likei APP: https://likei.app` - + if (navigator.share) { navigator.share({ title: 'Join my team on Likei', diff --git a/src/views/MessageView.vue b/src/views/MessageView.vue index 75b2078..c168c88 100644 --- a/src/views/MessageView.vue +++ b/src/views/MessageView.vue @@ -17,7 +17,7 @@
- {{ message.name.charAt(0) }} + {{ message.name }}

{{ message.name }}

@@ -55,18 +55,6 @@ const messages = ref([]) // 模拟消息数据 const mockMessages = [ - { - id: '1234567890', - name: 'User1', - avatar: '', - type: 'team_join_request' - }, - { - id: '1234567890', - name: 'User1', - avatar: '', - type: 'team_join_request' - }, { id: '1234567890', name: 'User1', @@ -80,8 +68,7 @@ const fetchMessages = async () => { loading.value = true try { const response = await getApplyRecord('1954059793963393025', 'WAIT') // 调用真实接口 - // 假设接口返回的数据结构为 { data: [...] } 或直接是数组 - messages.value = response.data || response // 根据实际返回结构调整 + loading.value = false } catch (error) { } finally { diff --git a/src/views/NotAppView.vue b/src/views/NotAppView.vue new file mode 100644 index 0000000..df953df --- /dev/null +++ b/src/views/NotAppView.vue @@ -0,0 +1,99 @@ + + + + +