从浏览器或者Webview 中唤醒APP_w97531的博客-程序员宝宝

技术标签: App  网易云  

本文来自网易云社区


作者:刘新奇

移动互联时代,很多互联网服务都会同时具备网站以及移动客户端,很多人认为APP的能帮助建立更稳固的用户关系,于是经常会接到各种从浏览器、webview中唤醒APP的需求,显然,这对于前端开发人员来说,是一件很纠结的事。

唤醒APP

目前常见的主动唤醒APP方式有几种:

Url scheme

Url scheme是iOS,Android平台都支持,只需要原生APP开发时注册scheme, 那么用户点击到此类链接时,会自动跳到APP。比如

<!-- 打开考拉APP首页 --><a href="kaola://www.kaola.com">打开APP</a><!-- 呼叫号码 --><a href="tel://13788889999">打开拨号</a>

如果配置scheme的路径,并在app中识别,则可以直接打开APP特定页面,如下:

<!-- 打开考拉APP商品详情 --><a href="kaola://www.kaola.com/product/8342.html">打开APP商品详情</a>

上述的链接,需要考虑手机是否支持此Scheme: 支持:弹出相应程序; 不支持:错误处理情况因平台而异,部分app会直接跳错误页(比如Android Chrome/41,iOS中老版的Lofter); 也有的停留在原页面,但弹出提示“无法打开网页”(比如iOS7);iOS8以及最新的Android Chrome/43 目前都是直接停留在当前页,不会跳出错误提示。 总体来看, iOS的支持程度比Android好,iOS在实际使用中,除非明确禁止的(比如微信),很少碰到不支持的情况;Android平台则各个app厂商差异很大,比如Chrome从25及以后就不再支持通过js触发(非用户点击),设置iframe src地址等来触发scheme跳转

Android intent

这是Android平台独有的,使用方式如下

intent:
   HOST/URI-path // Optional host 
   #Intent; 
      package=[string]; 
      action=[string]; 
      category=[string]; 
      component=[string]; 
      scheme=[string]; 
   end;

这里的HOST/URI-path, 与普通http URL 的host/path书写方式相同, package是Android app的包名,其它参数如action、category、component不是很理解, 具体见文档 , 比如打开考拉 app的商品详情,代码如下

<!-- 打开考拉APP --><a href="intent://www.kaola.com/product/8342.html#Intent;scheme=kaola;package=com.kaola;end">打开APP</a>

如果手机能匹配到相应的APP,则会直接打开;如没有安装,则会跳到手机默认的应用商店,比如Google原生系统Nexus 5,将会直接跳到Google Play, 对于国内各厂商定制过的系统,则跳转到各自的默认应用商店,或者弹出商店供选择。 intent 比scheme相对完善的一点是,提供一个打开失败去向URL的选项,可以通过指定参数 S.browser_fallback_url 来指定去向URL。 比如如下的打开APP动作,如果打开失败,则跳转到app下载页,这对于国内的特殊网络环境,还是挺有用的。

<!-- 打开考拉APP --><a href="intent://www.kaola.com/product/8342.html#Intent;scheme=kaola;package=com.kaola;S.browser_fallback_url=http%3A%2F%2Fapp.kaola.com;end">打开APP</a>

HTTP URL订阅

Android Chrome平台独有,app中订阅自有内容相关的URL,在Chrome中浏览相关网页时,会自动弹出提示,让用户选择用浏览器还是APP打开,通用性有限。

iOS内置APP广告条

在页面Head中增加meta, 添加智能 App 广告条 (iOS 6+ Safari), 如下

<meta"apple-itunes-app"content"app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL"

可以自动判断是否已安装应用, 可惜只能用于iOS+Safari, 在第三方应用中就不行了。 效果如下:

20180907111836c01a5144-104e-452d-a474-aa068cd974f7.png

Android Chrome内置app安装提示

这个是Mobile Chrome 43 beta新加入的特性,在用户浏览某一个网站多次后,如果Chrome发现该站点有原生APP,则会提示用户下载原生APP,此项特性开发者无法干预,完全是Google的推荐行为,在项目中用不上,具体见新闻报道

实际应用中存在的问题

移动平台提供这么多唤醒APP的方法,但是功能还不够完善,以下情况JS无法检测并做处理:

  1. APP如果唤醒失败,很多时候都会跳到错误页,影响用户体验,而我们的需求很可能是需要跳到下载或者其它页。

  2. APP成功唤醒,页面无法直接得知,系统没有提供此类回调。

实际需求、解决方案

  1. 要在打开APP失败时,不能使当前页面跳到错误页,且打开失败时,有失败函数回调。

  2. 如果成功打开APP,有成功函数回调。 针对第一点,可以将打开动作放到iframe中,就算跳转失败仍能停留在当前页面;那剩下的问题就是如何检测APP是否成功打开; 网上常见解决方案如下:

    //创建一个隐藏的iframevar ifr = document.createElement('iframe');
    ifr.src = 'com.baidu.tieba://';
    ifr.style.display = 'none';document.body.appendChild(ifr);//记录唤醒时间var openTime = +new Date();window.setTimeout(function(){ document.body.removeChild(ifr); //如果setTimeout 回调超过2500ms,则弹出下载
     if( (+new Date()) - openTime > 2500 ){     window.location = 'http://exam.com/xxxx.apk';
     }
    },2000)

    此脚本利用了程序切换到后台时,计时器回调会被推迟的原理,如果APP被唤醒,那么此网页必然进入后台,如果用户从APP再切换回来,时间一般也会超过2.5s;如果app没有唤醒,则setTimeout 基本上会准时回调,时间不会超过2s。但是实际上,这个仅仅在iOS平台有效,Android由于是多任务的,应用放到后台,setTimeout 基本上还是会准时触发,所以这个逻辑还不够完善。

那Android 浏览器有没有方法检测应用是否进入了后台呢? 页面可见性API(Page Visibility API), 可以通过检测 document.hidden 或 document.[webkit|moz|ms]Hidden 来检查页面是否可见,或者订阅页面的visibilitychange事件; 如果仅仅应用在新版Android及Chrome上,这个是很美好的,对于老版本(<4.4)及Android Webview, 则不可用。

暮然回首,那人却在灯火阑珊处,setInterval,对,就setInterval, 如果设置比较小的运行间隔(<30ms),在浏览器或者webview中,应用切换到后台,setInterval 会被很明显的延迟执行,比如设置一个运行间隔20ms,总计运行100次的定时器,如果页面一直处于前台,则100次跑完,总耗时与20ms x 100 = 2000ms 不会有太大差异, 但页面在后台运行时,此时间会明显超过2000ms。 可以利用这一点来实现是否成功打开APP检测及回调。 代码如下:

function openApp(openUrl, appUrl, action, callback) {    //检查app是否打开
    function checkOpen(cb){        var _clickTime = +(new Date());        function check(elsTime) {            if ( elsTime > 3000 || document.hidden || document.webkitHidden) {
                cb(1);
            } else {
                cb(0);
            }
        }        //启动间隔20ms运行的定时器,并检测累计消耗时间是否超过3000ms,超过则结束
        var _count = 0, intHandle;
        intHandle = setInterval(function(){
            _count++;        
            var elsTime = +(new Date()) - _clickTime;            if (_count>=100 || elsTime > 3000 ) {
                clearInterval(intHandle);
                check(elsTime);
            }
        }, 20);
    }    //在iframe 中打开APP
    var ifr = document.createElement('iframe');
    ifr.src = openUrl;
    ifr.style.display = 'none';    if (callback) {
        checkOpen(function(opened){
            callback && callback(opened);
        });
    }    document.body.appendChild(ifr);      
    setTimeout(function() {        document.body.removeChild(ifr);
    }, 2000);  
}

iframe方式打开APP的问题:

  • Android Chrome/25+ 无法打开APP,所以最好是APP配合监听http URL 来实现。

  • iOS、Android平台,近期发现在没有安装对应app时尝试唤醒,有少数APP会连当前页面(iframe的父页面)也变成错误页的情况。

其它问题: 微信无法打开或者下载,打开APP这个基本无解,下载则只能让应用进驻应用宝市场,然后检测到在微信中运行时,跳转到应用宝页面下载。


网易云大礼包:https://www.163yun.com/gift

本文来自网易云社区,经作者刘新奇授权发布


相关文章:
【推荐】 一个只有十行的精简MVVM框架(下篇)
【推荐】 人力资源管理中的大数据应用之道

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/w97531/article/details/82493797

智能推荐

【keynote专场】AI First时代的云计算-2017CCTC大会-专题视频课程_fendahaohe的博客-程序员宝宝

当今,企业”上云”节奏正在加速,特别是在以人工智能技术为代表的新一波技术浪潮推动下,企业一方面通过云技术增强了自身的数据存储连接、计算以及智能应用能力;另一方面,利用基于云计算之上的大数据、人工智能等新技术,企业又可以以较小的成本、更高效地挖掘出提升企业业务的数据与方法,实现云、数、智的自然融合和协力发展。...

MyBatis之如何解决数据库数据加密解密_mybatis 数据库密码加密_spring_root的博客-程序员宝宝

前言:介绍一个简单的MyBatis加解密方式,日常学习工作中提及这种方法的比较少,所以拿来说说,如果已经知道这种方法的忽略本文一、背景在我们数据库中有些时候会保存一些用户的敏感信息,比如:手机号、银行卡等信息,如果这些信息以明文的方式保存,那么是不安全的。假如:黑客黑进了数据库,或者离职人员导出了数据,那么就可能导致这些敏感数据的泄漏。因此我们就需要找到一种方法来解决这个问题。二、解决方案由于我们系统中使用了Mybatis作为数据库持久层,因此决定使用Mybatis的TypeHandler或

elf section类型_elf文件类型六 Dynamic Section(动态section)_林筱涵的博客-程序员宝宝

Dynamic Section(动态section)假如一个object文件参与动态的连接,它的程序头表将有一个类型为PT_DYNAMIC的元素。该“段”包含了.dynamic section。一个_DYNAMIC特别的符号,表明了该section包含了以下结构的一个数组。+ Figure 2-9: Dynamic Structuretypedef struct {Elf32_Sword d_ta...

因果图法设计测试用例_叫我小菲菲的博客-程序员宝宝

因果图法设计测试用例1. 定义:因果图法是一种利用图解法分析输入的各种组合情况,从而设计测试用例的方法,他适合与检查程序输入条件的各种组合情况。2. 意义:等价类划分和边界值分析方法都是着重考虑输入条件,但没有考虑输入条件的各种组合、输入条件之间的相互制约关系。这样虽然各种输入条件可能出错的情况已经测试测试到了,但多个输入条件组合起来可能出错的情况却被疏忽了。3. 认识因果图·如果

STM32 bootloader_weixin_30873847的博客-程序员宝宝

不需要拆机就能对产品进行固件升级是很多人想要的效果,不仅方便而且节省精力和成本。那么如何完成这项工作呢?接下来所介绍的Bootloader就可以完成这项工作,通过Bootloader引导程序完成固件的升级。下面来浅析STM32Bootloader设计。首先谈谈stm32的ISP和IAP区别和联系。ISP(In-System Programming)在系统可...

随便推点

TX2 ubuntu18.04 arm64架构 桌面系统为lxde 系统为轻量级 成功安装ros_风一样的航哥的博客-程序员宝宝

如标题所述:硬件采用:TX2 ubuntu18.04 arm64架构 桌面系统为lxde来安装ros,安装了两次都意外失败了,后来终于找到了问题。在ros wiki 官网(http://wiki.ros.org/melodic/Installation/Ubuntu)中有设置源的时候,就有:sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" &gt; /etc/apt/sour.

UPC个人训练赛28(做题记录)_WE xiye的博客-程序员宝宝

1.计算 Σ1-AΣ1-BΣ1-C abc的值解析:在这种求和题中,a b c 可以被 提到前面变成Σa ΣbΣc然后分别运用等差数列计算注意事项:每一项在计算的过程中都要进行取余操作计算完成之后,在三项相乘时需要先将前两个相乘 →取余再将算好的结果跟最后一个相乘 →取余 否则会发生爆long long 的结果2.一个宽为L的道路上,有N盏路灯输入N,L下一行输入 N个数字,表示 路灯在道路上的位置坐标假设d时每个路灯的照明半径,问当照明半径d能将整个道路(0-L) 全部点亮

Apache ShardingSphere数据库中间件配置对未分片的表不做sql检测_trycache的博客-程序员宝宝

应用场景:数据库中间件版本是ShardingSphere-4.1.1。(单库)数据库中有5张表,分别是a,b,c,d,e。现在仅对a,b,c进行分表,其余两张表d,e不分表。我的问题是:只包含d,e两张表的sql查询能不能不走shardingsphere的解析器,想直接避开无关表的解析。现在的情况是都走了解析器。即在单库应用的情况下解决该问题,直接避开无关表的解析。因为很多sql的实际使用都是带子查询的,并且这些参与查询的数据表也是很多部分表的。ShardingSphere中间件sql解析拦截器配置

第14章 Proxmox VE桌面虚拟化或桌面云_开源云桌面proxmox_4/5$全真龙门的博客-程序员宝宝

第14章 Proxmox VE桌面虚拟化或桌面云做了很长一段时间的运维部门负责人,除了负责管控IDC机房的业务系统服务器外,还得兼管公司内部的办公网络。虽然不用亲自去帮同事搬主机、安装系统,但面对堆积如山的、分配不出去的旧电脑,很是犯愁。为什么这样呢?因为有员工辞职,需要收回电脑,等新的员工入职,再把回收的电脑分配出去。但新来的员工,觉得旧电脑配置太低,不愿意接受,于是只能再采购新电脑,以致于旧电脑库存越来越多。14.1 办公场景使用PC机面临的问题除了上述所言电脑资产浪费而外,传统型的办公

Simple, high-performant, dynamic, lightweight and powerful AOP for Java_cuim0002的博客-程序员宝宝

AspectWerkz is a dynamic, lightweight and high-performant AOP framework for Java. AspectWerkz offers both power an...

推荐文章

热门文章

相关标签