iOS中使用schema协议调用APP和使用iframe打开APP的例子


在iOS中,需要调起一个app可以使用schema协议,这是iOS原生支持的,并且因为iOS系统中都不能使用自己的浏览器内核,所以所有的浏览器都支持,这跟android生态不一样,android是可以自己搞内核的,但是iOS不行。

在iOS中提供了两种在浏览器中打开APP的方法:Smart App Banner和schema协议。

Smart App Banner

即通过一个meta 标签,在标签上带上app的信息,和打开后的行为,例如:app-id之类的,代码形如:

https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/PromotingAppswithAppBanners/PromotingAppswithAppBanners.html
今天Smart APP Banner不是我们的主角,我们说的是schema

使用schema URL来打开iOS APP

schema类似自定义url协议,我们可以通过自定义的协议来打开自己的应用,形如:

复制代码 代码如下:

myapplink://
# 例如 facebook的
fb://
# itunes的
itms-apps://
# 还有短信也是类似的
sms://

如果要打开一个app,最简单的方式是通过一个链接,如我们在html中这样写:
复制代码 代码如下:

<a href="myapplink://">打开我的app</a>

当用户点击链接的时候就可以打开对应的app。

绑定click事件

但是实际中我们更多的情况是绑定事件,比如做个弹层啥的,不能一味的用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不触发):

复制代码 代码如下:

<p><button id="btn">点我点我啊!alert,不会弹出</button></p>
<p><button id="btn2">点我点我啊!alert2,虽然有alert和info,info执行,但是alert不弹出</button></p>
<p><button id="btninfo">点我点我啊!info可以</button></p>

$(function(){

  var $info = $('#info');

  function info(msg){
    var p = $('<p>'+msg+'</p>');
    $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);
}



相关阅读:
Html5 web本地存储实例详解
设置Linux系统文件权限
如何调整mac分辨率?苹果mac分辨率设置方法
PHP实现仿Google分页效果的分页函数
iOS模仿电子书首页实现书架布局样式
JS实现仿QQ面板的手风琴效果折叠菜单代码
PHP自带方法验证邮箱是否存在
PHP正则表达式过滤html标签属性(DEMO)
jquery ajax结合thinkphp的getjson实现跨域的方法
ThinkPHP使用心得分享-分页类Page的用法
如何调试异步加载页面里包含的js文件
JavaScript编程中实现对象封装特性的实例讲解
JavaScript获取图片像素颜色并转换为box-shadow显示
QuiteRSS: Linux桌面的RSS阅读器 你值得拥有
快速导航
PHP MySQL HTML CSS JavaScript MSSQL AJAX .NET JSP Linux Mac ASP 服务器 CMS SQL jQuery C# C++ java Android IOS oracle MongoDB PostgreSQL SQLite 交通频道 G4722 G1875 G215 G569 G421 G6733 G7577 G8906 G1235 G4916 G7291 G1953 G245 G662 G1570 G6285 G719 G1836 G1346 G4781 G4908 G289 G6781 G9290 G7358 G1928 G1815 G325 G132 G4901 G6012 G6290 G7131 G5367 G184 G151 G5303 G1136 G6481 G7028 G575 G1744 G7660 G7693 G2344 G4937 G1234 G1814 G6252 G1492 G253 G2926 G883 G9275 G1231 G556 G241 G1306 G7646 G8103 G600 G1858 G9678 G6160 G7156 G825 G1125 G7249 G1809 G1350 G432 G9466 G7067 G785 G6404 G4663 G7008 G150 G823 G1514 G7529 G1201 G2353 G205 G7629 G9409 G6147 G677 G390 G8016 G9239 G456 G828 G8045 G491 G7145 G397 G7012 G1021 G6482 G2322 G7264 G1301 G9247 G96 G1294 G7133 G4824 G7005 G1653 G5307 G1213 G822 G4837 G1422 G411 G6227 G1571 G359 G1882 G6074 G7678 G21 G7077 G1272 G8918 G9645 G461 G1254 G1846 G8021 G7303 G1104 G76 G82 G621 G218 G8533 G2341 G8543 G555 G8013 G4802 G1364 G1153 G1342 G1861 G8905 G590 G4780 G668 G9261 G1304 G1638 G1395 G2914 G8003 G7158 G1833 G1873 G8128 G1856 G1841 G8709 G7346 G4612 G2103 G835 G8712 G381 G7240 G8932 G507 G29 G4054 G6273 G6752 G426 G211 G9473 G7119 G2333 G1567 G6153 G360 G4011 G5301 G7648 G8010 G8015 G6706 G614 G423 G8557 G9465 G72 G6018 G8901 G7030 G123

丹东 云霄 辽中 德阳 克拉玛依 惠山 招远 昭通 铁岭西 延吉西 军粮城北 定西 晋中 许昌东 郫县 诏安 七台河 高碑店东 南昌 延安 敦化 铜陵北 嵩明 鲘门 扬中 龙里北 舟山 洛阳 运城北 鞍山 西昌 邵阳北 绍兴 白山 三明 肇东 陵水 衡山西 嘉善 宜都 泰兴 泉州 汉口 东胜西 昌图西 锦州南 安阳东 怀化 黄南 亚龙湾 扬州 温州 南翔北 福安 金山北 永川东 安达 曲阜东 郑州西 天门 绍兴北 涪陵北 阳泉北 三亚 葫芦岛北 徐州 阳江 辽源 新泰 阿坝 孝感北 三穗 金寨 保山 高安 安阳 牟平 西双版纳 信阳 繁昌西 哈尔滨北 达州 新余 沈阳南 四平 扶余北 伊宁 郴州西 济源 水家湖 民权北 福鼎 如皋 奉化 全州南 安庆 太姥山 武汉 乐清 皮口 武昌 茂名 邯郸 资阳 马鞍山 三水南 泰安 包头东 衡阳东 南丰 仙桃西 安吉 罗源 山海关 平湖 惠州 资阳北 淄博 丹阳 莱州 巴东 关岭 盐城 锦州 格尔木 益阳 大英东 吉林 湛江 临安 襄汾西 渑池南 当涂东 辽阳 徐水 贺州 韶关 光明城 邯郸东 普安县 南江口 铜川 五龙背东 张家港 烟台南 萍乡北 青堆 长乐 江门 台州 衡水 湘潭北 闽清北 高邑西 盖州西 石柱县 潮汕 肇庆 泰康 邵东 湖州 余姚 平凉 宜宾 增城 沧州 都匀 防城港 鹰潭北 海东西 福田 余姚北 岳池 广州北 南安 蓬莱 瓦房店西 李石寨 葛店南 海安 无锡东 上饶 通辽 四会 桂林西 砀山南 兰州 滨海 龙口 绅坊 莱西 石林西 深圳 大连北 成都 上海西 孝感 杏树屯 德清 嘉兴

Copyright © 2016 phpStudy |