鸿蒙5、6用户h5页面使用schemeURL跳转小程序失败

0 阅读3分钟

线上鸿蒙5、6用户h5页面使用schemeURL跳转小程序失败

情况描述

  • ios用户自动跳转成功
  • 安卓用户自动跳转成功
  • 测试机鸿蒙5、6跳转成功

客户经理提供用户手机截图:

线上用户自动跳转到网址为:weixin://dl/business/?t=xxx的网址了,没有拉起微信小程序

image.png

线上用户手机鸿蒙5、6跳转失败

测试机鸿蒙5、6跳转成功获取到的useragent能够自动、点击按钮跳转

访问同事发现,称手机非纯血鸿蒙

userAgent: Mozilla/5.0(Phone;OpenHarmony 6.0; Android 10)AppleWebKit/537.36(KHTML,like Gecko) Chrome/132.0.0.0Safari/537.36 ArkWeb/6.0.0.120MobileHuaweiBrowser/5.1.11.312data"不
支持

问题原因

  1. 无法确认是纯血鸿蒙还是非纯血鸿蒙原因?
  2. 是浏览器问题?兼容性或者隐私设置问题?
  3. 如何区分纯血鸿蒙、非纯血鸿蒙?

以上问题,想和客户求证,还在等负责人推进...

关键代码

// schemeURL密文地址
let url = 'weixin://dl/business/?t=xxx'  

window.onload = function () {  
setTimeout(() => {  
window.location.href = 'weixin://dl/business/?t=xxx';  
}, 500);

function jumpTo1(){  
window.location.href = url;  
}  
function jumpTo2(){  
const ifr = document.createElement('iframe');  
ifr.src = url;  
ifr.style.display = 'none';  
document.body.appendChild(ifr);  
// 可选:延时移除,避免影响  
setTimeout(() => {  
document.body.removeChild(ifr);  
}, 2000);  
}  
function jumpTo3(){  
const a = document.createElement('a');  
a.href = url;  
a.style.display = 'none';  
document.body.appendChild(a);  
a.click();  
// 可选:延时移除,避免影响  
setTimeout(() => {  
document.body.removeChild(a);  
}, 2000);  
}

源代码

jsp页面

<div class="container" id="arcode">  
<div class="note">  
<strong>温馨提示:</strong>此功能需要在微信外浏览器打开,如手机自带浏览器、Safari或Chrome等。  
</div>  
  
<%-- <button class="jump-btn" onclick="loadScheme('develop')">密文开发版本</button>--%>  
<%-- <button class="jump-btn" onclick="loadMWScheme()">明文跳转小程序</button>--%>  
<div>  
<button id="hmbtn" class="jump-btn" onclick="joinWhiteList()" style="display:none"> 进入小程序</button>  
<button id="fhmbtn2" class="jump-btn" onclick="loadScheme()" style="display:none"> 进入小程序</button>  
<button id="hmbtn2" class="jump-btn" onclick="joinWhiteList()" style="display:none"> 上报设备信息</button>  
</div>  
<p id="device3" style="color: red"></p>  
<p id="device"></p>  
<div class="steps">  
<p><strong>跳转说明:</strong></p>  
<ul>  
<li>确保您已安装最新版本的微信App</li>  
</ul>  
</div>  
  
<div class="qr-code">  
<div class="qr-placeholder" v-loading="loading">  
<view id="mini"></view>  
</div>  
<p>如有问题,请联系客服支持</p>  
</div>  
  
</div>  
  
<script>  
new Vue({  
el: '#arcode',  
data() {  
return {  
loading: false,  
};  
},  
});  
  
const baseURL = "<%=basePath%>"  
const service = axios.create({  
baseURL: baseURL,  
timeout: 15000,  
withCredentials: true,  
})  
  
service.interceptors.request.use(config => {  
if (config.method === 'get') {  
if (config.params) {  
config.params['date'] = new Date().getTime()  
} else {  
config.url = config.url + `?date=` + new Date().getTime()  
}  
}  
return config  
}, error => {  
ELEMENT.Message({  
message: '错误信息:' + error,  
type: 'warning'  
});  
return Promise.reject(error)  
})  
  
service.interceptors.response.use(resData => {  
if (resData.headers['content-disposition']) {  
resData.data.contentDisposition = resData.headers['content-disposition']  
}  
if (resData.status >= 200 && resData.status < 300) {  
const {code, result, msg} = resData.data  
if (code === 1) {  
return result  
} else if (code === 10012) {  
ELEMENT.Message({  
message: 'token已过期,请您重新登录!',  
type: 'warning'  
});  
setTimeout(() => location.reload(), 1500);  
return Promise.reject(code)  
} else {  
if (msg == undefined) {  
return resData  
}  
ELEMENT.Message({  
message: msg,  
type: 'warning'  
});  
return Promise.reject(code)  
}  
}  
}, error => {  
ELEMENT.Message({  
message: '错误信息:' + error,  
type: 'warning'  
});  
return Promise.reject(error)  
})  
  
function GetWxMiniScheme(code, ticket, version) {  
return service({  
method: 'GET',  
url: '/api/scheme/getWxMiniScheme/' + code + '/' + ticket + '/' + version,  
})  
}  
  
function AddWhitelist(ticket, model) {  
return service({  
method: 'GET',  
url: '/api/scheme/addWhitelist/' + ticket + '/' + model,  
})  
}  
  
var ticket = `${ticket}`;  
const paramscom = new URLSearchParams(window.location.search);  
ticket = paramscom.get('ticket');  
// 系统  
let ua = navigator.userAgent.toLowerCase();  
let isHo = false  
  
// 1. 识别鸿蒙系(优先级最高,避免被安卓识别覆盖)  
const isOpenHarmony = /openharmony\s?([0-9._]+)/i.test(ua) || /openharmony\/([0-9._]+)/i.test(ua);  
const openHarmonyVersion = (ua.match(/openharmony\s?([0-9._]+)/i) || ua.match(/openharmony\/([0-9._]+)/i) || [])[1] || '';  
  
const isHarmonyOS = /harmonyos\s?([0-9._]+)/i.test(ua) || /harmonyos\/([0-9._]+)/i.test(ua);  
const harmonyOSVersion = (ua.match(/harmonyos\s?([0-9._]+)/i) || ua.match(/harmonyos\/([0-9._]+)/i) || [])[1] || '';  
  
// 2. 识别iOS(包含iPhone/iPad/iPod)  
const isIOS = /iphone|ipad|ipod|ios/i.test(ua);  
const iosVersion = (ua.match(/os\s+(\d+[._]\d+)/i) || [])[1]?.replace('_', '.') || '';  
  
// 3. 识别安卓  
const isAndroid = /android|adr/i.test(ua) && !isOpenHarmony && !isHarmonyOS; // 排除鸿蒙(鸿蒙UA含android)  
const androidVersion = (ua.match(/android\s+(\d+[._]\d+)/i) || [])[1]?.replace('_', '.') || '';  
  
// 4. 识别Windows Phone  
const isWindowsPhone = /windows phone|wp/i.test(ua);  
const wpVersion = (ua.match(/windows phone\s+(\d+[._]\d+)/i) || [])[1]?.replace('_', '.') || '';  
  
// 5. 识别其他系统(Linux/MacOS/Windows)  
const isLinux = /linux/i.test(ua) && !isAndroid && !isOpenHarmony && !isHarmonyOS;  
const isMacOS = /mac os x/i.test(ua);  
const isWindows = /windows|win32/i.test(ua);  
  
// 6. 最终系统类型和版本赋值(无Unknown)  
let systemType = '';  
let systemVersion = '';  
  
if (isOpenHarmony) {  
systemType = 'OpenHarmony';  
systemVersion = openHarmonyVersion;  
isHo = true  
} else if (isHarmonyOS) {  
systemType = 'HarmonyOS';  
systemVersion = harmonyOSVersion;  
isHo = true  
} else if (isIOS) {  
systemType = 'iOS';  
systemVersion = iosVersion;  
} else if (isAndroid) {  
systemType = 'Android';  
systemVersion = androidVersion;  
} else if (isWindowsPhone) {  
systemType = 'Windows Phone';  
systemVersion = wpVersion;  
} else if (isLinux) {  
systemType = 'Linux';  
systemVersion = '';  
} else if (isMacOS) {  
systemType = 'MacOS';  
systemVersion = (ua.match(/mac os x\s+(\d+[._]\d+)/i) || [])[1]?.replace('_', '.') || '';  
} else if (isWindows) {  
systemType = 'Windows';  
systemVersion = (ua.match(/windows nt\s+(\d+[._]\d+)/i) || [])[1]?.replace('_', '.') || '';  
} else {  
// 兜底:仍识别不出则显示「Other」而非Unknown  
systemType = 'Other';  
systemVersion = '';  
}  
// 打印最终结果(无Unknown)  
console.log('系统类型:', systemType, '版本号:', systemVersion);  
const deviceInfo = {  
systemType,  
systemVersion,  
userAgent: navigator.userAgent,  
platform: navigator.platform,  
time: new Date().toISOString()  
};  
const p = document.querySelector('#device');  
const p3 = document.querySelector('#device3');  
p.style.whiteSpace = 'pre-wrap';  
p.innerText = '系统类型:' + deviceInfo.systemType + '\n' + '版本号:' + deviceInfo.systemVersion + '\n平台:' + deviceInfo.platform + '\n' + 'UserAgent: ' + deviceInfo.userAgent + 'data"' + (navigator.userAgentData ? JSON.stringify(navigator.userAgentData) : '不支持');  
  
  
// 页面加载后延迟执行跳转  
window.onload = function () {  
if (isHo) {  
document.getElementById('hmbtn').style.display = 'block';  
document.getElementById('hmtext').style.display = 'block';  
} else {  
// 非鸿蒙系统自动跳转-显示上报信息按钮(加白名单)  
setTimeout(() => {  
loadScheme()  
}, 500);  
}  
  
  
};  
  
// 【核心】全浏览器适配的清理逻辑(含夸克/华为)  
function clearH5PageAfterJump() {  
// 第一步:识别浏览器类型  
const ua = navigator.userAgent.toLowerCase();  
const browserType = {  
isHuawei: ua.includes('huaweibrowser') || ua.includes('harmony') || ua.includes('huawei'),  
isQuark: ua.includes('quark') || ua.includes('quarkmini'),  
isChrome: ua.includes('chrome') && !ua.includes('mobile safari'),  
isSafari: ua.includes('mobile safari') && !ua.includes('chrome'),  
isOther: true  
};  
// 修正other判断  
browserType.isOther = !browserType.isHuawei && !browserType.isQuark && !browserType.isChrome && !browserType.isSafari;  
  
try {  
// 1. 华为浏览器:优先调用专属API  
if (browserType.isHuawei && window.HuaweiBrowser) {  
window.HuaweiBrowser.closeCurrentTab();  
}  
// 2. 通用关闭尝试(仅部分浏览器生效)  
else if (window.close) {  
window.close();  
setTimeout(() => window.close(), 200);  
}  
} catch (e) {  
console.log('自动关闭失败,执行强制清空', e);  
  
// 第二步:分浏览器强制清空(核心适配夸克)  
if (browserType.isQuark) {  
// 夸克专属:深度清空+重写页面结构  
document.open(); // 打开文档流,清空缓存  
document.write('<html class="blank-page"><body class="blank-page"></body></html>');  
document.close(); // 关闭文档流,强制渲染  
// 替换历史记录+禁止返回  
window.location.replace('about:blank');  
// 禁用所有交互  
document.body.style.pointerEvents = 'none';  
// 终止所有异步任务  
for (let i = 0; i < 2000; i++) {  
clearInterval(i);  
clearTimeout(i);  
}  
// 夸克特殊:延迟再次清空  
setTimeout(() => {  
document.body.innerHTML = '';  
document.documentElement.className = 'blank-page';  
}, 100);  
}  
// 华为浏览器兜底  
else if (browserType.isHuawei) {  
document.documentElement.innerHTML = '';  
document.body.innerHTML = '';  
window.location.replace('about:blank');  
document.documentElement.style.display = 'none';  
document.body.style.display = 'none';  
for (let i = 0; i < 1000; i++) {  
clearInterval(i);  
clearTimeout(i);  
}  
}  
// 其他浏览器通用方案  
else {  
document.body.innerHTML = '';  
window.location.replace('about:blank');  
document.documentElement.className = 'blank-page';  
}  
}  
}  
  
// 监听页面隐藏(跳转成功),执行清理  
document.addEventListener('visibilitychange', function () {  
if (document.hidden) {  
console.log('页面隐藏 → 跳转成功,清理H5页面');  
// 不同浏览器延迟适配  
const ua = navigator.userAgent.toLowerCase();  
let delay = 500; // 默认  
if (ua.includes('huawei')) delay = 300; // 华为  
if (ua.includes('quark')) delay = 200; // 夸克(更快响应)  
  
setTimeout(() => {  
clearH5PageAfterJump();  
}, delay);  
}  
});  
  
// 所有系统统一走a标签跳转  
function jumpByATag(url) {  
const ua = navigator.userAgent.toLowerCase();  
const isAndroid = ua.indexOf('android') > -1 || ua.indexOf('adr') > -1;  
const isIOS = !!ua.match(/\(i[^;]+;( u;)? cpu.+mac os x/);  
const isXiaomi = ua.indexOf('mi ') > -1 || ua.indexOf('xiaomi') > -1 ||  
ua.indexOf('redmi') > -1;  
  
if (isIOS) {  
window.location.href = url;  
} else if (isAndroid || isXiaomi) {  
// 安卓(尤其是⼩⽶)⽤iframe中转  
const ifr = document.createElement('iframe');  
ifr.src = url;  
ifr.style.display = 'none';  
document.body.appendChild(ifr);  
// 可选:延时移除,避免影响  
setTimeout(() => {  
document.body.removeChild(ifr);  
}, 2000);  
} else {  
const a = document.createElement('a');  
a.href = url;  
a.style.display = 'none';  
document.body.appendChild(a);  
a.click();  
// 可选:延时移除,避免影响  
setTimeout(() => {  
document.body.removeChild(a);  
}, 2000);  
}  
}  
  
function loadMWScheme() {  
var appid = "wx5728ecf19f0d9405";  
var path = "pages/index/index";  
var env = "develop";  
let code1 = `${code}`;  
  
const params = new URLSearchParams(window.location.search);  
ticket = params.get('ticket');  
let queryObj = 'source=h5&ticket=' + ticket + '&code=' + code1;  
let query = encodeURIComponent(queryObj);  
let finalUrl = 'weixin://dl/business/?appid=' + appid + '&path=' + path + '&query=' + query + '&env_version=' + env;  
console.log(finalUrl + '明文跳转');  
jumpByATag(finalUrl);  
}  
  
function loadScheme(version = 'release') {  
try {  
let code1 = `${code}`;  
const params = new URLSearchParams(window.location.search);  
ticket = params.get('ticket');  
// 鸿蒙系统直接加入白名单  
  
// 否则-  
GetWxMiniScheme(code1, ticket, version).then(res => {  
const schemeUrl = res.urlScheme;  
let jumped = false;  
let hasReported = false;  
const start = Date.now();  
  
const handleVisibility = () => {  
if (document.hidden) {  
jumped = true;  
console.log('页面隐藏 → 推测跳转成功');  
document.removeEventListener('visibilitychange', handleVisibility);  
clearH5PageAfterJump();  
}  
};  
document.addEventListener('visibilitychange', handleVisibility);  
  
const interval = setInterval(() => {  
const elapsed = Date.now() - start;  
if (jumped || hasReported || elapsed > 8000) {  
clearInterval(interval);  
return;  
}  
if (elapsed >= 5000 && !jumped) {  
console.log('检测 5 秒未跳转,开始上报');  
hasReported = true;  
reportDeviceInfo(ticket);  
clearInterval(interval);  
}  
}, 1000);  
  
// 统一拼接跳转URL 0为明文跳转  
let finalJumpUrl = '';  
if (res.status == 0) {  
var appid = "wx5728ecf19f0d9405";  
var path = "pages/index/index";  
var env = version;  
let queryObj = 'source=h5&ticket=' + ticket + '&code=' + code1;  
let query = encodeURIComponent(queryObj);  
finalJumpUrl = 'weixin://dl/business/?appid=' + appid + '&path=' + path + '&query=' + query + '&env_version=' + env;  
console.log(finalJumpUrl + '明文跳转', res);  
} else {  
finalJumpUrl = schemeUrl;  
console.log(schemeUrl + ' 密文跳转', res);  
}  
  
// 所有系统统一走a标签跳转  
jumpByATag(finalJumpUrl);  
  
}).catch(err => {  
console.error('获取Scheme失败:', err);  
});  
} catch (err) {  
console.error('loadScheme异常:', err);  
}  
}  
  
function reportDeviceInfo(ticket1 = ticket) {  
console.log(navigator.userAgent, navigator, 'navigator', ticket1)  
if (!isHo) {  
p3.innerText = '非鸿蒙系统,请从App跳转小程序'  
p.innerText = '系统类型:' + deviceInfo.systemType + '\n' + '版本号:' + deviceInfo.systemVersion + '\n平台:' + deviceInfo.platform + '\n' + 'UserAgent: ' + deviceInfo.userAgent + 'data"' + navigator.userAgentData;  
console.log('检测设备信息:', deviceInfo, navigator.userAgentData, 'userAgentData', systemType);  
ELEMENT.Message({  
message: '请点击进入小程序,失败可选择上报设备信息,从小程序进入',  
type: 'warning'  
});  
document.getElementById('hmbtn2').style.display = 'block';  
document.getElementById('fhmbtn2').style.display = 'block';  
return  
}  
AddWhitelist(ticket1, systemType + systemVersion).then(res => {  
if (res == '')  
res = '已经加入白名单,请从访客小程序入口进入'  
ELEMENT.Message({  
message: res,  
type: 'error'  
});  
}).catch(err => {  
console.log(err, 'err')  
})  
}  
  
function joinWhiteList() {  
let ticket1 = ticket  
AddWhitelist(ticket1, systemType + systemVersion).then(res => {  
if (res == '')  
res = '已经加入白名单,请从访客小程序入口进入'  
ELEMENT.Message({  
message: res,  
type: 'error'  
});  
}).catch(err => {  
console.log(err, 'err')  
})  
}  
</script>