H5喚起APP進(jìn)行分享
最近很久沒有寫blog和note,倒是過家家的開發(fā)日志簡單草草寫了一點(diǎn)。這次記錄下這個(gè)學(xué)習(xí)過程
由來
我們的 "通達(dá)有你",web h5頁面的分享功能體驗(yàn)太差了,我一直想改變提高體驗(yàn)度。
通常點(diǎn)分享然后跳轉(zhuǎn)到另一個(gè)頁面,比如QQ、空間、微博,還有微信。微信通常要掃二維碼分享,(我們只有一個(gè)手機(jī)啊,還要再屏幕上掃二維碼,通常要是我是嘗試分享者,微信這么麻煩的分享我肯定是不會繼續(xù)分享了)
所以剛有空我就想試試更好的方法
疑問?
然后我平時(shí)留意幾大互聯(lián)網(wǎng)的巨頭的h5頁面,他也是可以進(jìn)行APP喚起的,這到底是怎么做到的?
不過這種情況分為兩種:
喚起自己產(chǎn)品的APP
-
喚起第三方APP
image

而我的目的是第二種,我們是要喚起第三方APP進(jìn)行分享
分析實(shí)現(xiàn)方式
經(jīng)過我 面向搜索引擎 的一頓操作,了解到一些資料和方式,其中要實(shí)現(xiàn)在h5喚起APP的主要采用
- URL Scheme | Intent | Universal Link(也稱:深度鏈接)
- 通過瀏覽器的內(nèi)置native分享接口
URLScheme
URL Scheme 是什么
我們來看一下 URL 的組成:
[scheme:][//authority][path][?query][#fragment]
我們拿 https://www.baidu.com 來舉例,scheme 自然就是 https 了。
就像給服務(wù)器資源分配一個(gè) URL,以便我們?nèi)ピL問它一樣,我們同樣也可以給手機(jī)APP分配一個(gè)特殊格式的 URL,用來訪問這個(gè)APP或者這個(gè)APP中的某個(gè)功能(來實(shí)現(xiàn)通信)。APP得有一個(gè)標(biāo)識,好讓我們可以定位到它,它就是 URL 的 Scheme 部分。
常用APP的 URL Scheme
| APP | 微信 | 支付寶 | 淘寶 | 微博 | 知乎 | 短信 | |
|---|---|---|---|---|---|---|---|
| URL Scheme | weixin:// | alipay:// | taobao:// | sinaweibo:// | mqq:// | zhihu:// | sms:// |
URL Scheme 語法
上面表格中都是最簡單的用于打開 APP 的 URL Scheme,下面才是我們常用的 URL Scheme 格式:
行為(應(yīng)用的某個(gè)功能)
|
scheme://[path][?query]
| |
應(yīng)用標(biāo)識 功能需要的參數(shù)
搜集到的常用Scheme
| 應(yīng)用名稱 | URL Scheme |
|---|---|
| 微博 | weibo:// |
| mqq:// | |
| QQ群組 | mqqapi://card/show_pslcard?src_type=internal&version=1&card_type=group&uin={QQ群號} |
| QQ聯(lián)系人 | mqqapi://card/show_pslcard?src_type=internal&version=1&uin={QQ號碼} |
| 支付寶 | alipay:// |
| 微信 | weixin:// |
| 微信 | wechat:// |
| 微信-掃一掃 | weixin://dl/scan |
| 微信-反饋 | weixin://dl/feedback |
| 微信-朋友圈 | weixin://dl/moments |
| 微信-設(shè)置 | weixin://dl/settings |
| 微信-消息通知設(shè)置 | weixin://dl/notifications |
| 微信-聊天設(shè)置 | weixin://dl/chat |
| 微信-通用設(shè)置 | weixin://dl/general |
| 微信-公眾號 | weixin://dl/officialaccounts |
| 微信-游戲 | weixin://dl/games |
| 微信-幫助 | weixin://dl/help |
| 微信-反饋 | weixin://dl/feedback |
| 微信-個(gè)人信息 | weixin://dl/profile |
| 微信-功能插件 | weixin://dl/features |
| 蝦米音樂 | xiami:// |
| chrome | googlechrome:// |
| 微博國際版 | weibointernational:// |
| 摩拜單車 | mobike:// |
| ofo | ofoapp:// |
| 有道云筆記 | youdaonote:// |
| 印象筆記 | evernote:// |
| 今日頭條 | snssdk141:// |
| 網(wǎng)易新聞 | newsapp:// |
| 網(wǎng)易云音樂 | orpheuswidget:// |
| QQ音樂 | qqmusic:// |
| QQ音樂最近播放 | qqmusic://today?mid=31&k1=2&k4=0 |
| 美團(tuán)外賣 | meituanwaimai:// |
| 美團(tuán) | imeituan:// |
| Gmail | googlegmail:// |
| 網(wǎng)易郵箱 | neteasemail:// |
| QQ郵箱 | qqmail:// |
| 騰訊視頻 | tenvideo:// |
| 愛奇藝 | iqiyi:// |
| 12306 | cn.12306:// |
| 有道詞典 | yddict:// |
| 釘釘 | dingtalk:// |
我進(jìn)入深坑
看到上面這些資料的我,思考了很久如何去找具體的path和query部分。如果能找到這兩塊的詳細(xì)參數(shù),那么我們就可以在APP間相互調(diào)用和傳參了,就和普通URL一樣了
但是,我尋找了好久,或許是我不懂這里面的方式吧,或許是我也不太懂Android方面的知識,就是沒人在網(wǎng)上提及到具體的path和query,
后來想想,也是挺正常的,大多網(wǎng)站和企業(yè)只是想喚起自己的APP,那如何使用這些URL Scheme呢
大坑
先預(yù)告一下還有比較大的坑就是,scheme的觸發(fā)方式會被瀏覽器攔截,如果是QQ和微信自帶的內(nèi)置瀏覽器,使用Scheme是無效的,除非是自家人或者在它的白名單內(nèi)(比如幾大巨頭),這就導(dǎo)致了如果你在QQ和微信內(nèi)點(diǎn)擊網(wǎng)頁內(nèi)的分享,不好意思,啥用沒有。。。不過可以做個(gè)遮罩層用他們內(nèi)置瀏覽器的右上角分享功能。
-
微信、微博、手百、QQ瀏覽器等。
這些應(yīng)用能阻止喚端是因?yàn)樗鼈冎苯悠帘蔚袅?URL Scheme 。接下來可能就有看官疑惑了,微信中是可以打開大眾點(diǎn)評的呀,微博里面可以打開優(yōu)酷呀,那是如何實(shí)現(xiàn)的呢?
它們都各自維護(hù)著一個(gè)白名單,如果你的域名在白名單內(nèi),那這個(gè)域名下所有的頁面發(fā)起的 URL Scheme 就都會被允許。就像微信,如果你是騰訊的“家屬”,你就可以加入白名單了,微信的白名單一般只包含著“家屬”,除此外很難申請到白名單資質(zhì)。但是微博之類的都是可以聯(lián)系他們的渠道童鞋進(jìn)行申請的,只是條件各不相同,比如微博的就是在你的 APP 中添加打開微博的入口,三個(gè)月內(nèi)喚起超過 100w 次,就可以加入白名單了。
-
騰訊應(yīng)用寶直接打開 APP 的某個(gè)功能
剛剛我們說到,如果你不是微信的家屬,那你是很難進(jìn)入白名單的,所以在安卓中我們一般都是直接打開騰訊應(yīng)用寶,ios 中 直接打開 App Store。點(diǎn)擊騰訊應(yīng)用寶中的“打開”按鈕,可以直接喚起我們的 APP,但是無法打開 APP 中的某個(gè)功能(就是無法打開指定頁面)。
騰訊應(yīng)用寶對外開放了一個(gè)叫做 APP Link 的申請,只要你申請了 APP Link,就可以通過在打開應(yīng)用寶的時(shí)候在應(yīng)用寶地址后面添加上
&android_schema={your_scheme},來打開指定的頁面了。
感覺騰訊應(yīng)用寶是個(gè)做文章的很地方,沒準(zhǔn)之后會嘗試下
瀏覽器的內(nèi)置分享原生分享
瀏覽器自帶有分享到微信和QQ的功能,但不是每個(gè)都提供接口來供網(wǎng)頁調(diào)用。即使有提供,瀏覽器暴露的api不一樣,各家有各家的規(guī)則和方式。
但好在網(wǎng)上找到了兩個(gè)前輩造的輪子NativeShare和uc-qq-share-to-wechat ,也都是調(diào)用各個(gè)瀏覽器的原生分享功能,但前者里面我還看到了部分Scheme的方式。
主要的瀏覽器有:
- QQ瀏覽器
- UC瀏覽器
- 微信自帶瀏覽器
- QQ自帶瀏覽器
- QQ空間APP
- 百度瀏覽器
- 百度APP自帶瀏覽器
- ios 搜狗瀏覽器
- Safari瀏覽器
- 其他
觸發(fā)方式
現(xiàn)在來說說觸發(fā)方式,大致上有三種:
iframe方案
<iframe src="sinaweibo://qrcode">
在未安裝 app 的情況下,不會去跳轉(zhuǎn)錯(cuò)誤頁面。但是 iframe 在各個(gè)系統(tǒng)以及各個(gè)應(yīng)用中的兼容問題還是挺多的,我自己并沒有使用這種。
var last = Date.now(),
doc = window.document,
ifr = doc.createElement('iframe');
//創(chuàng)建一個(gè)隱藏的iframe
ifr.src = nativeUrl;
ifr.style.cssText = 'display:none;border:0;width:0;height:0;';
doc.body.appendChild(ifr);
setTimeout(function() {
doc.body.removeChild(ifr);
//setTimeout回小于2000一般為喚起失敗
if (Date.now() - last < 2000) {
if (typeof onFail == 'function') {
onFail();
} else {
//彈窗提示或下載處理等
}
} else {
if (typeof onSuccess == 'function') {
onSuccess();
}
}
}, 1000);
iframe方案的喚起原理是: 程序切換到后臺時(shí),計(jì)時(shí)器會被推遲(計(jì)時(shí)器不準(zhǔn)的又一種情況)。如果app被喚醒那么網(wǎng)頁必然就進(jìn)入了后臺,如果用戶從app切回來,那么時(shí)間一般會超過2s;若app沒有被喚起,那么網(wǎng)頁不會進(jìn)入后臺,setTimeout基本準(zhǔn)時(shí)觸發(fā),那么時(shí)間不會超過2s。
a標(biāo)簽喚起
<a href="mqqapi://card/show_pslcard?src_type=internal&version=1&uin=123456">QQ臨時(shí)交流</a>
上面這個(gè)a標(biāo)簽?zāi)憧梢宰约簢L試一下,是可以直接喚起的,a標(biāo)簽如果目標(biāo)scheme錯(cuò)誤,即應(yīng)用不存在也不會報(bào)錯(cuò)。
location.href跳轉(zhuǎn)
window.location.href = 'sinaweibo://qrcode';
我自己大多使用click的方式配合location來進(jìn)行跳轉(zhuǎn),自己沒有在各大平臺和各個(gè)瀏覽器版本上做太多實(shí)驗(yàn),在一個(gè)博文中看到
URL Scheme 在 ios 9+ 上諸如 safari、UC、QQ瀏覽器中, iframe 均無法成功喚起 APP,只能通過 window.location 才能成功喚端。
某篇博文中對三種喚起方式進(jìn)行了測試
。X表示喚起失敗,√表示喚起成功
。紅色標(biāo)記表示進(jìn)入頁面直接喚起,綠色表示人工事件操作后喚起
。ios測試機(jī):iphone 6p;android測試機(jī):小米1s
iframe喚起app測試結(jié)果

window.location.href喚起app測試結(jié)果

a標(biāo)簽喚起app測試結(jié)果

iframe和window.location.href喚起對比

iframe、window.location.href和a標(biāo)簽喚起三者對比

對比iframe喚起和location.href,我們可以發(fā)現(xiàn):
- 對于ios來說,location.href跳轉(zhuǎn)更合適,因?yàn)檫@種方式可以在Safari中成功喚起app。Safari作為iphone默認(rèn)瀏覽器其重要性就不用多說了,而對于微信和qq客戶端,ios中這兩種方式都沒有什么卵用==
- 對于Android來說,在進(jìn)入頁面直接喚起的情況下,iframe和location.href是一樣的,但是如果是事件驅(qū)動(dòng)的喚起,iframe喚起的表現(xiàn)比location.href要更好一點(diǎn)。
- 通過測試可以發(fā)現(xiàn),進(jìn)入頁面直接喚起和事件驅(qū)動(dòng)的喚起,對于很多瀏覽器,兩者的表現(xiàn)是不同的,簡單來說,直接喚起的失敗更多。
以上測試可能隨時(shí)間已經(jīng)有出入和變化,僅供參考
選擇
看了這些資料后,開始動(dòng)手對網(wǎng)站的分享功能再次二開,目前都是采用a標(biāo)簽進(jìn)行一個(gè)簡單的跳轉(zhuǎn),去對應(yīng)社交平臺的分享url的api接口提交各個(gè)參數(shù)。

嘗試
準(zhǔn)備先引入大佬的NativeShare輪子,因?yàn)槲以谒脑诰€demo嘗試了,我手機(jī)自帶瀏覽器、模擬器的自帶瀏覽器、模擬器的QQ瀏覽器,都可以很好的分享出來,于是首先引入他的方式。
思路
$(document).ready(function () {
$(".social-share-icon ").on("click",function (e) {
e.preventDefault();
shareHref = $(this).attr("href");
if ($(this).hasClass("icon-qq")){
call('qqFriend',shareHref);
}
})
})
對目前的各個(gè)a標(biāo)簽,在dom加載完成時(shí)添加一個(gè)click事件,阻止a標(biāo)簽的觸發(fā),然后把href地址記錄下來。然后再去觸發(fā)相應(yīng)的NativeShare中的call方法。
但是我發(fā)現(xiàn)在原生的瀏覽器里面竟然沒觸發(fā)。。那就做個(gè)降級處理吧。
function call(command) {
try {
nativeShare.call(command)
} catch (err) {
// 在這里寫降級處理的內(nèi)容
alert(err.message)
}
}
在catch到拋出到異常后,自己在用原生的URL scheme 嘗試觸發(fā),如果還是不能觸發(fā),那就沒辦法咯~~
var url_scheme = '//share/to_fri?src_type=web&version=1&file_type=news&title=' + Base64.encode(shareData.title) + '&thirdAppDisplayName=5o6M5LiK55CG5bel5aSn&url=' + Base64.encode(shareData.link) + '&description=' + Base64.encode(shareData.desc);
location.assign('mqqapi:' + url_scheme)
setTimeout(function () {
location.assign('timapi:' + url_scheme)
}, 2000)
這個(gè)是我在網(wǎng)上找到的一個(gè)qq 分享的URL scheme,記得要base64處理下各個(gè)內(nèi)容,還有個(gè)缺陷就是沒有icon了,圖片顯示不了了。
細(xì)節(jié)處理
剛剛都是說手機(jī)移動(dòng)端訪問,如果要是電腦端訪問的話,還是觸發(fā)這個(gè)肯定不成功。所以在最開始要先判斷下ua。根據(jù)ua來做出下一步動(dòng)作。簡單的放下ua判斷代碼
var browser = {
versions: function() {
var u = navigator.userAgent, app = navigator.appVersion;
return { //移動(dòng)終端瀏覽器版本信息
trident: u.indexOf('Trident') > -1, //IE內(nèi)核
presto: u.indexOf('Presto') > -1, //opera內(nèi)核
webKit: u.indexOf('AppleWebKit') > -1, //蘋果、谷歌內(nèi)核
gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐內(nèi)核
mobile: !!u.match(/AppleWebKit.*Mobile.*/), //是否為移動(dòng)終端
ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios終端
android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android終端或uc瀏覽器
iPhone: u.indexOf('iPhone') > -1, //是否為iPhone或者QQHD瀏覽器
iPad: u.indexOf('iPad') > -1, //是否iPad
webApp: u.indexOf('Safari') == -1, //是否web應(yīng)該程序,沒有頭部與底部
qq: u.indexOf('MQQBrowser') > -1,//QQ瀏覽器
uc: u.indexOf('UCBrowser') > -1// UC瀏覽器
};
} (),
language: (navigator.browserLanguage || navigator.language).toLowerCase()
}
// 先判斷是否是PC,如果是PC端 就直接使用鏈接來分享
if (browser.versions.mobile || browser.versions.android || browser.versions.ios){
// if (browser.versions.qq && command==='qqFriend' || command==='qZone'){
// throw new Error;
// }
nativeShare.call(command)
}else{
// 使用原鏈接分享
location.assign(e)
}
效果
最后測試了幾個(gè)瀏覽器分享效果
| 瀏覽器 | 華為自帶 | X瀏覽器 | 模擬器自帶 | 模擬中QQ瀏覽器 | APK內(nèi)置 |
|---|---|---|---|---|---|
| QQ好友 | N | Y | Y | Y | Y |
| QQ空間 | N | Y | Y | Y | Y |
| 微信朋友圈 | Y | N | N | Y | N |


看來QQ瀏覽器果然通過原生的內(nèi)置分享api都能達(dá)到分享喚起,但是在其他瀏覽器就有部分不兼容了。后面有需要在繼續(xù)調(diào)整優(yōu)化吧,
Reference
H5喚起APP指南 https://suanmei.github.io/2018/08/23/h5_call_app/
h5喚起app http://echozq.github.io/echo-blog/2015/11/13/callapp.html
