从浏览器或者Webview 中唤醒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, 在第三方应用中就不行了。 效果如下:
Android Chrome内置app安装提示
这个是Mobile Chrome 43 beta新加入的特性,在用户浏览某一个网站多次后,如果Chrome发现该站点有原生APP,则会提示用户下载原生APP,此项特性开发者无法干预,完全是Google的推荐行为,在项目中用不上,具体见新闻报道
实际应用中存在的问题
移动平台提供这么多唤醒APP的方法,但是功能还不够完善,以下情况JS无法检测并做处理:
APP如果唤醒失败,很多时候都会跳到错误页,影响用户体验,而我们的需求很可能是需要跳到下载或者其它页。
APP成功唤醒,页面无法直接得知,系统没有提供此类回调。
实际需求、解决方案
要在打开APP失败时,不能使当前页面跳到错误页,且打开失败时,有失败函数回调。
如果成功打开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
本文来自网易云社区,经作者刘新奇授权发布
相关文章:
【推荐】 21分钟学会写编译器
从浏览器或者Webview 中唤醒APP的更多相关文章
- 手机浏览器_安卓_苹果手机Webview 中唤醒APP
Url scheme是iOS,Android平台都支持,只需要原生APP开发时注册scheme, 那么用户点击到此类链接时,会自动跳到APP.比如 <!-- 打开考拉APP首页 --> & ...
- 微信浏览器内 h5 直接唤醒 app 之 微信开放标签 wx-open-launch-app
以前微信浏览器内想要直接唤醒 app 要么接微信的应用宝要么你是腾讯的干儿子. 而在微信在2020年5月分推出了“微信开放标签”功能 wx-open-launch-app 用于微信浏览器内直接唤醒 a ...
- 【转】H5 浏览器和 webview 后退缓存机制
来源:https://juejin.im/entry/588b44a08fd9c544813ed5b3 一.背景 用户点击浏览器工具栏中的后退按钮,或者移动设备上的返回键时,或者JS执行history ...
- 在UC浏览器打开链接唤醒app,假设没有安装该app,则跳转到appstore下载该应用
在UC浏览器打开链接唤醒app,假设没有安装该app,则跳转到appstore下载该应用 须要在project中设置例如以下: 1.打开project中的myapp-Info.plist文件 2.打开 ...
- ionic 实现 应用内(webview中html页面点击) 和 应用外 (浏览器html页面点击) 打开本地安装应用
应用内(webview中html页面点击) : 应用内打开本地安装应用指的是webview里打开应用,需要2个步骤: 1: 需要下载一个cordova插件:com.lampa.startapp ,也可 ...
- ios下微信浏览器如何唤醒app?app已上架应用宝
android下可以通过在应用宝微下载地址后面加参数&android_schema='应用schema'来实现,ios下如何实现? ios下微信浏览器如何唤醒app?app已上架应用宝 > ...
- 在手机浏览器中判断App是否已安装
从网上搜到之前手机中判断App是否安装可以通过onblur事件+定时器来实现. 但现在要做这个功能时,按网上的说法已经不能实现了.因为现在浏览器中打开App,window不会触发onblur事件. 在 ...
- 利用ios safari浏览器生成桌面快捷方式并唤醒app的示例代码
html 内容: //通过a链接唤醒app <a href="app约定好的scheme" id="qbt" style="display:n ...
- WebView中打开相机,文件选择器的问题和解决方法
近几年前端开发真是越来越火,H5页面开发的移动端页面甚至有夺我原生开发半壁江山的意思,忧伤忧伤.不过从实际情况考虑,H5一套代码到处跑的特性,我们的Android, IOS ...也就只能呵呵了.然而 ...
随机推荐
- ACM-ICPC (10/11)
莫比乌斯 今年的多校比赛,莫比乌斯反演的题目经常出现,但是我们队对于这种题可以说是直接放掉,不是因为没学过,多少了解一些,但是也只是皮毛,导致根本就做不出来,其实想一想,其实次数多了,就可以看出原因了 ...
- 对枚举数据类型使用switch
- 【luogu P2661 信息传递】 题解
题目链接:https://www.luogu.org/problemnew/show/P2661#sub 一种利用并查集求最小环的做法: 对于每个同学看作一个点,每次信息传递是一条有向边,当出现最小环 ...
- 中小学信息学奥林匹克竞赛-理论知识考点--IP地址
IP地址同身份证号一样,具有唯一性! 每个人都有一个唯一的标识:身份证号. 互联网中的计算机也一样,具有一个唯一的标识:IP地址. IP地址是一个32位的二进制数,通常被分割为4个“8位二进制数”(也 ...
- <body> 中的 JavaScript
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...
- 第二章:RESTful API
学习内容 使用Spring MVC编写Restful API 使用Spring MVC处理其他web应用常见的需求和场景 如何处理静态资源和异常,如何使用Spring MVC的拦截器,文件的上传下载, ...
- 菜鸟笔记 -- Chapter 6 面向对象
在Java语言中经常被提到的两个词汇是类与对象,实质上可以将类看作是对象的载体,它定义了对象所具有的功能.学习Java语言必须要掌握类与对象,这样可以从深层次去理解Java这种面向对象语言的开发理念, ...
- oracle 的分页查询与mysql 的分页查询
oracle 的分页查询: select * from (select o.*,rownum rn from Persons o) where rn >40 and rn <=60 : ...
- nodejs+express开发blog(1)
前言 Nodejs是一个年轻的编程框架,充满了活力和无限激情,一直都在保持着快速更新.基于Nodejs的官方Web开发库Express也在同步发展着,每年升级一个大版本,甚至对框架底层都做了大手术.在 ...
- 构建高可靠hadoop集群之5-服务级别授权
本人翻译自: http://hadoop.apache.org/docs/r2.8.0/hadoop-project-dist/hadoop-common/ServiceLevelAuth.html ...