vue
<template>
<div class="container">
<h2>银行APP跳转测试</h2>
<table>
<tr>
<th>银行</th>
<th>协议</th>
<th>是否支持</th>
</tr>
<tr>
<td>邮储银行</td>
<td>psbc://mainpage</td>
<td>
<el-button type="primary" @click="handleOpenApp(1)">打开</el-button>
</td>
</tr>
<tr>
<td>中国银行</td>
<td>boc://com.chinamworld.bocmbci/startWith</td>
<td>
<el-button type="primary" @click="handleOpenApp(2)">打开</el-button>
</td>
</tr>
<tr>
<td>建设银行</td>
<td>ccbapp://main.ccb.com</td>
<td>
<el-button type="primary" @click="handleOpenApp(3)">打开</el-button>
</td>
</tr>
<tr>
<td>工商银行</td>
<td>(ios)com.icbc.iphoneclient://(安卓/鸿蒙)<br/>com.icbc.androidclient://</td>
<td>
<el-button type="primary" @click="handleOpenApp(4)">打开</el-button>
</td>
</tr>
</table>
</div>
</template>
<script setup>
import { ref, onBeforeUnmount } from 'vue';
import { ElMessage } from 'element-plus'
// 检测平台类型
const isIOS = () => {
return /iPad|iPhone|iPod/.test(navigator.userAgent);
};
const isAndroid = () => {
return /Android/.test(navigator.userAgent);
};
const isHarmoney = () => {
return /HarmonyOS|Open/.test(navigator.userAgent);
};
// 检测页面是否失去焦点(表示App已打开)
const isAppLaunched = () => {
return new Promise((resolve) => {
let launched = false;
const handleVisibilityChange = () => {
if (document.visibilityState === 'hidden' || document.hidden) {
launched = true;
resolve({ method: 'unknown', success: true });
}
};
const handleBlur = () => {
launched = true;
resolve({ method: 'unknown', success: true });
};
// 添加事件监听器
document.addEventListener('visibilitychange', handleVisibilityChange);
window.addEventListener('blur', handleBlur);
// 2秒后如果没有跳转则认为失败
setTimeout(() => {
document.removeEventListener('visibilitychange', handleVisibilityChange);
window.removeEventListener('blur', handleBlur);
if (!launched) {
resolve({ method: 'none', success: false });
}
}, 2000);
});
};
const openWithIframe = (url) => {
return new Promise((resolve) => {
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.src = url;
console.log('1.使用iframe方式打开App...');
// 监听iframe加载事件(如果失败会有错误)
iframe.onload = () => {
console.log('iframe加载完成');
};
iframe.onerror = () => {
console.log('iframe加载失败');
};
document.body.appendChild(iframe);
// 1秒后移除iframe
setTimeout(() => {
if (document.body.contains(iframe)) {
document.body.removeChild(iframe);
}
// iframe方式一般不直接反映App打开状态,这里假设尝试过了
resolve({ method: 'iframe', tried: true });
}, 1000);
});
};
const openWithLocation = (url) => {
return new Promise((resolve) => {
console.log('2.尝试使用window.location.href打开App...');
try {
window.location.href = url;
// 如果执行到这里,说明location.href尝试过了
resolve({ method: 'location', tried: true });
} catch (error) {
console.error('window.location.href打开失败:', error);
resolve({ method: 'location', tried: false, error });
}
});
};
const handleOpenApp = async (num) => {
let url = '';
let fallbackUrl = ''; // 备用方案,如应用商店下载页
switch(num) {
case 1:
url = 'psbc://mainpage';
break;
case 2:
url = 'boc://com.chinamworld.bocmbci/startWith';
break;
case 3:
url = 'ccbapp://main.ccb.com';
break;
case 4:
// 工商银行区分平台
if (isIOS()) {
url = 'com.icbc.iphoneclient://';
ElMessage.info('检测到iOS系统,使用iPhone版工行App协议');
} else if (isAndroid()) {
url = 'com.icbc.androidclient://';
ElMessage.info('检测到Android系统,使用Android版工行App协议');
} else if (isHarmoney()) {
// 鸿蒙系统通常兼容Android应用,使用Android协议
url = 'com.icbc.androidclient://';
ElMessage.info('检测到鸿蒙系统,使用Android版工行App协议');
} else {
// 默认使用安卓协议
url = 'com.icbc.androidclient://';
ElMessage.info('未知系统类型,默认使用Android版工行App协议');
}
break;
}
// 验证URL是否有效
if (!url) {
ElMessage.error('未找到对应的App协议');
return;
}
// 显示用户反馈
const bankNames = ['', '邮储银行', '中国银行', '建设银行', '工商银行'];
ElMessage.info(`正在尝试打开${bankNames[num]}...`);
// 记录开始时间
const startTime = Date.now();
try {
// 并行执行两种方式
const [iframeResult, locationResult] = await Promise.all([
openWithIframe(url),
openWithLocation(url)
]);
console.log('iframe结果:', iframeResult);
console.log('location结果:', locationResult);
// 检测App是否成功启动
const appLaunchResult = await isAppLaunched();
console.log('App启动检测结果:', appLaunchResult);
if (appLaunchResult.success) {
ElMessage.success(`成功打开${bankNames[num]}!(方式:${appLaunchResult.method})`);
} else {
ElMessage.warning(`${bankNames[num]}可能未安装或不支持深层链接`);
}
console.log(`总耗时: ${Date.now() - startTime}ms`);
} catch (error) {
console.error('打开App失败:', error);
ElMessage.error('无法打开银行App,请检查是否已安装');
}
};
</script>
<style>
h2{
text-align: center;
margin: 20px 0;
}
.table-container {
overflow-x: auto;
width: 100%;
max-width: 100vw;
margin: 0 auto;
}
table {
border-collapse: collapse;
min-width: 300px;
width: 600px; /* 桌面端宽度 */
max-width: 100%;
border: 1px solid #ccc;
text-align: center;
margin: 0 auto;
}
th, td {
border: 1px solid #ccc;
padding: 12px 8px; /* 增加移动端内边距 */
vertical-align: middle;
}
/* 移动端适配 */
@media screen and (max-width: 768px) {
.container {
padding: 10px;
font-size: 14px;
}
h2 {
font-size: 18px;
margin: 15px 0;
}
table {
width: 100%;
font-size: 12px;
}
th, td {
padding: 8px 4px;
word-break: break-all; /* 长文本换行 */
}
.protocol {
min-width: 120px;
}
.protocol-mobile {
display: block;
margin-bottom: 4px;
}
.protocol-mobile:last-child {
margin-bottom: 0;
}
.el-button {
width: auto;
min-width: 60px;
height: 32px;
font-size: 12px;
}
}
@media screen and (max-width: 480px) {
.container {
padding: 5px;
}
h2 {
font-size: 16px;
margin: 10px 0;
}
th, td {
padding: 6px 3px;
font-size: 11px;
}
.protocol {
min-width: 80px;
}
.el-button {
height: 28px;
padding: 4px 8px;
min-width: 50px;
}
}
/* 大屏幕优化 */
@media screen and (min-width: 769px) {
.container {
max-width: 800px;
margin: 0 auto;
}
}
/* 针对移动设备的触摸友好设计 */
@media screen and (hover: none) and (pointer: coarse) {
.el-button {
min-height: 44px; /* 符合移动端最小触摸区域标准 */
min-width: 60px;
}
}
</style>