前言
需求背景:一個web下載頁面,需要檢測pc是否安裝了客戶端軟件(windows軟件)。網頁上有一個打開客戶端按鈕。若安裝了客戶端軟件,則直接打開,否則下載軟件。支持web下載頁面在iframe下
打開客戶端的方法
通過客戶端軟件在注冊表注冊的自定義協議打開。例如:js代碼location.href = 'baseonline://';
查看注冊表方法: 在鍵盤上按“win+R”,打開運行窗口,在里面輸入regedit,回車即可進入注冊表編輯器
實現
- 方案1: 首先github上找到這個方案
https://github.com/ismailhabib/custom-protocol-detection
。對多個瀏覽器都實現了,基本都是hack方法。不足點是,若檢測頁面在iframe里面,谷歌瀏覽器的檢測方法不起作用。如果檢測頁面不在iframe下,方案1就能滿足使用。 - 方案2: 針對所在檢測頁面是iframe下的頁面。找到另外一個方法去實現。在谷歌瀏覽器測試通過。其他的沒測。
由於方案2只在谷歌測試過,可以把方案1和方案2結合使用。覆蓋更多瀏覽器類型
方案2的具體實現
/**
* uri 打開客戶端的uri
* failCb 打開客戶端失敗回調
* successCb 打開客戶端成功回調
*/
function openUriWithInputTimeoutHack(uri, failCb, successCb) {
let target = document.createElement('input')
target.style.width = '0'
target.style.height = '0'
target.style.position = 'fixed'
target.style.top = '0'
target.style.left = '0'
document.body.appendChild(target)
target.focus();
var handler = _registerEvent(target, "blur", onBlur);
console.log('focus')
function onBlur() {
console.log('blur')
successCb && successCb()
handler.remove()
clearTimeout(timeout)
document.body.removeChild(target)
};
//will trigger onblur
location.href = uri
// Note: timeout could vary as per the browser version, have a higher value
var timeout = setTimeout(function () {
console.log('setTimeout')
failCb && failCb()
handler.remove()
document.body.removeChild(target)
}, 1000);
}
function _registerEvent(target, eventType, cb) {
if (target.addEventListener) {
target.addEventListener(eventType, cb);
return {
remove: function () {
target.removeEventListener(eventType, cb);
}
};
} else {
target.attachEvent(eventType, cb);
return {
remove: function () {
target.detachEvent(eventType, cb);
}
};
}
}
// 測試
let protocalUrl = `baseonline://`
openUriWithInputTimeoutHack(protocalUrl, () => {
console.log('檢測到,未安裝客戶端')
}, () => {
// 瀏覽器彈窗提示
console.log('檢測到:已安裝了客戶端')
})
原理:同樣是hack方法,利用input聚焦失焦去判斷。點擊打開客戶端按鈕,input聚焦。1. 如果瀏覽器檢測到本地系統有對應的注冊碼,則會彈窗提示是否打開客戶端軟件,input失去焦點,判斷安裝了客戶端。2. 否則1s后還沒彈窗,判斷沒有安裝客戶端。