在iOS中,须要调起一个app可使用schema协议,这是iOS原生支持的,而且由于iOS系统中都不能使用本身的浏览器内核,因此全部的浏览器都支持,这跟android生态不同,android是能够本身搞内核的,可是iOS不行。php
在iOS中提供了两种在浏览器中打开APP的方法:Smart App Banner和schema协议。html
Smart App Bannernode
即经过一个meta 标签,在标签上带上app的信息,和打开后的行为,例如:app-id之类的,代码形如:android
<meta name="apple-itunes-app" content="app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL">
具体能够看下开发文档:https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/PromotingAppswithAppBanners/PromotingAppswithAppBanners.html
今天Smart APP Banner不是咱们的主角,咱们说的是schemaios
使用schema URL来打开iOS APPweb
schema相似自定义url协议,咱们能够经过自定义的协议来打开本身的应用,形如:chrome
myapplink:// # 例如 facebook的 fb:// # itunes的 itms-apps:// # 还有短信也是相似的 sms://
若是要打开一个app,最简单的方式是经过一个连接,如咱们在html中这样写:浏览器
<a href="myapplink://">打开个人app</a>
当用户点击连接的时候就能够打开对应的app。app
绑定click事件dom
可是实际中咱们更多的状况是绑定事件,好比作个弹层啥的,不能一味的用a标签啊,因此能够经过两种方式来解决:location.href和iframe。
iframe的方式是开发中经常使用的,可是他也有一些问题:
1.咱们没很好的方式来判断是否打开了app
2.会引发history变化
3.由于引发history变化,因此一些webview会有问题,好比:我查查,打开一个页面,若是有iframe,选择在safari中打开,实际打开的是iframe的页面
4.若是页面暴漏给了android系统,那么也会出现页面打不开,之类的问题
5.若是没有app,调起不成功,ios的safari会本身弹出一个对话框:打不开网址之类的提示
因此如今的问题是:如何知道iframe已经打开了某个app,即解决iframe打开app回调。
使用iframe在iOS系统中打开app
聪明的你可能想到了,iframe的onload事件啊,但是遗憾的说,无效!因此咱们找到了定时器(setTimeout),经过一个定时器,若是在一段时间内(好比500ms),当点击了按钮(记录time1),页面没有切走(调起app以后,页面进程会被中断),进程中断,那么计时器也会中断,这时候应该不会触发timer,若是调起失败,那么timer会就触发,咱们判断下在必定时间内若是页面没有被切走,就认为调起失败。
另外经过timer触发时候的timer2,作差,判断是否太离谱了(切走了以后的时间应该比timer实际定时的500ms要长):
function openIos(url, callback) { if (!url) { return; } var node = document.createElement('iframe'); node.style.display = 'none'; var body = document.body; var timer; var clear = function(evt, isTimeout) { (typeof callback==='function') && callback(isTimeout); if (!node) { return; } node.onload = null; body.removeChild(node); node = null; }; var hide = function(e){ clearTimeout(timer); clear(e, false); }; node.onload = clear; node.src = url; body.appendChild(node); var now = +new Date(); //若是事件失败,则1秒设置为空 timer = setTimeout(function(){ var newTime = +new Date(); if(now-newTime>600){ //由于切走了,在切回来须要消耗时间 //因此timer即便执行了,可是二者的时间差应该跟500ms有较大的出入 //可是实际并非这样的! clear(null, false); }else{ clear(null, true); } }, 500); }
看上去方法很靠谱,可是现实老是那么的残酷!
不一样的浏览器app(包括webview),都有本身在后台的常驻时间,即:假如一个浏览器他在被切走以后,后台常驻10s,那么咱们设置定时器5s过时就是徒劳的,并且5s的定时器,用户要空等5s!交互也不让你这样干啊!
最后咱们想到了pageshow和pagehide事件,即若是浏览器被切走到了要打开的app,应该会触发浏览器的pagehide事件,而从app从新返回到浏览器,就会触发pageshow方法。
可是通过代码测试发现,在uc、chrome中,不会触发pagehide和pageshow的方法,而在safari中能够的。
结论:
1.使用iframe调用schema URL
2.使用定时器判断在一段时间内是否调起成功
3.使用pageshow和pagehide来辅助定时器作更详细的判断
4.定时器中若是有alert可能不会被弹出,这一点很吃惊!后面的dom居然5.执行了,可是alert没弹出,可能跟alert的实现有关系吧
6.在实验中我使用了两个定时器,是由于切回浏览器以后,有时候timeout触发要在pagehide和pageshow以前
7.计算timer实际执行时间差,也是不靠谱的
最后附上研究的代码,算是比较靠谱的方法了,虽然仍是有必定的失败(第三方浏览器pagehide和pageshow不触发):
<button id="btn">点我点我啊!alert,不会弹出</button> <button id="btn2">点我点我啊!alert2,虽然有alert和info,info执行,可是alert不弹出</button> <button id="btninfo">点我点我啊!info能够</button> $(function(){ var $info = $('#info'); function info(msg){ var p = $(' '+msg+' '); $info.append(p); } $('#btn').on('click', function(){ openIos('baiduboxapp://', function(t){ if(t){ alert('timeout or no baidu APP'); }else{ alert('invoke success'); } }); }); $('#btn2').on('click', function(){ openIos('baiduboxapp://', function(t){ if(t){ info('timeout or no baidu APP2'); alert('timeout or no baidu APP2'); }else{ info('invoke success2'); alert('invoke success2'); } }); }); $('#btninfo').on('click', function(){ openIos('baiduboxapp://', function(t){ if(t){ info('timeout or no baidu APP'); }else{ info('invoke success'); } }); }); }); function openIos(url, callback) { if (!url) { return; } var node = document.createElement('iframe'); node.style.display = 'none'; var body = document.body; var timer; var clear = function(evt, isTimeout) { (typeof callback==='function') && callback(isTimeout); window.removeEventListener('pagehide', hide, true); window.removeEventListener('pageshow', hide, true); if (!node) { return; } node.onload = null; body.removeChild(node); node = null; }; var hide = function(e){ clearTimeout(timer); clear(e, false); }; window.addEventListener('pagehide', hide, true); window.addEventListener('pageshow', hide, true); node.onload = clear; node.src = url; body.appendChild(node); var now = +new Date(); //若是事件失败,则1秒设置为空 timer = setTimeout(function(){ timer = setTimeout(function(){ var newTime = +new Date(); if(now-newTime>1300){ clear(null, false); }else{ clear(null, true); } }, 1200); }, 60); }