在移动端浏览器H5页面中,点击按钮打开本地应用主要通过 scheme 协议。本文主要介绍如何在浏览器H5页面中通过 scheme 协议打开本地应用。

scheme协议定义

scheme 是一种页面之间跳转的协议,不仅可以用于app之间进行跳转,还可以用于 H5 页面跳转到app页面。

无论Android还是IOS,都可以通过在H5页面中打开 scheme 协议的地址,从而打开本地app。

scheme 协议定义和 http 协议类似,都是标准的 URI 结构。

  1. [scheme:][//host:port][path][?query][#fragment]
  • scheme : 协议名称 - 必须
  • host : 协议地址 - 必须
  • port : 协议的端口,可以不填
  • path : 协议路径,可用 / 连接多个
  • query : 携带的参数可用 & 连接多个
  • fragment : 锚点

下面看一个例子:

  1. wexin://tencent.com:8080/dl/news/open?data=902323&params=test
  • weixin : 协议名称
  • tencent.com : 域名
  • 8080 : 端口
  • /dl/news/open : 页面的路径
  • data, params : 传递的参数

URI中的参数如果包含特殊字符,需要预先进行url编码,否则的话URI可能不能打开。

在 Android 中声明实现 scheme

要使得在浏览器或者别的应用中通过打开 scheme 协议来唤起应用,需要对该应用进行相关的配置。

首先需要在Android工程的 Manifest文件,给想要接收跳转的Activity添加 intent-filter 节点的配置拦截器规则

  1. <activity
  2. <!--定义响应该scheme协议的 activity 的名称 -->
  3. android:name=".DeepLinkActivity"
  4. <!--需要添加下面的intent-filter配置-->
  5. <intent-filter>
  6. <action android:name="android.intent.action.VIEW"/>
  7. <category android:name="android.intent.category.DEFAULT"/>
  8. <!--scheme 允许在浏览器中打开-->
  9. <category android:name="android.intent.category.BROWSABLE"/>
  10. <!--scheme 相关信息配置-->
  11. <data android:scheme="uuopen"
  12. android:host="uusama.com"/>
  13. </intent-filter>
  14. </activity>

上面的 data 节点中可以包含下面的信息来对相应的scheme进行过滤,一般需要配置 scheme 和 host。

  1. <data
  2. android:scheme=""
  3. android:host=""
  4. android:port=""
  5. android:path=""
  6. android:mimeType=""
  7. android:pathPattern=""
  8. android:pathPrefix=""
  9. android:ssp=""
  10. android:sspPattern=""
  11. android:sspPrefix=""/>

然后在相应的 activity 可以获取 uri 中参数。

  1. public class DeepLinkActivity extends AppCompatActivity {
  2. private static final String TAG = "DeepLinkActivity";
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. Intent intent = getIntent();
  8. Log.e(TAG, "scheme:" + intent.getScheme());
  9. Uri uri = intent.getData();
  10. Log.e(TAG, "scheme: " + uri.getScheme()); // 获取 scheme 名称
  11. Log.e(TAG, "host: " + uri.getHost()); // 获取 scheme 的host
  12. Log.e(TAG, "path: " + uri.getPath()); // 获取 scheme 的路径
  13. Log.e(TAG, "queryString: "+ uri.getQuery()); // 获取 scheme 的参数,?后面的部分
  14. Log.e(TAG, "queryParameter: " + uri.getQueryParameter("param")); // 获取 scheme 中的 param 参数
  15. }
  16. }

其中的 intent 实例有下面的方法可以获取相应的 scheme 信息:

  • getScheme() :获取Uri中的scheme名称:[scheme:]
  • getSchemeSpecificPart() :获取Uri中的scheme-specific-part:部分:[//host:port][path]
  • getFragment() :获取Uri中的Fragment部分:[#fragment]
  • getAuthority() :获取Uri中Authority部分:[//host:port]
  • getPath() :获取Uri中path部分:[path]
  • getQuery() :获取Uri中的query部分:[?query]
  • getHost() :获取Authority中的Host字符串
  • getPost() :获取Authority中的Port字符串
  • List< String> getPathSegments() :依次提取出Path的各个部分的字符串,以字符串数组的形式输出
  • getQueryParameter(String key) :获取query部分中 key 对应的参数值

在浏览器中打开 scheme

在浏览器中打开 scheme 就像打开一个不同的http地址一样。可以在一个 a 标签中打开。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Scheme</title>
  6. </head>
  7. <body>
  8. <a href="wexin://" id="open">打开应用</a>
  9. </body>
  10. </html>

点击上面的H5页面中的链接将会尝试唤醒微信,在一些浏览器中,可能会弹出一个提示框,询问用户是否允许打开应用。

如果打开的 scheme 在本地没有对应的 app,则点击连接不会反应。

当然还可以使用 JavaScript 代码打开,只需要添加相应的事件触发和处理即可。

在JavaScript代码中打开连接有以下几种方式:

  • 新建一个隐藏的 iframe ,地址指向需要打开的url
  • 使用 window.location 或者 window.location.href 刷新当前页面
  • 新建一个隐藏的 a 标签,地址指向打开的url,并触发打开链接事件
  • 动态创建一个script脚本,在这个脚本中新建一个a标签并打开
  1. // 打开url的方式
  2. var urlOpen = {
  3. 'iframe' : function(url) {
  4. var iframe = document.createElement('iframe');
  5. iframe.style.display = 'none';
  6. iframe.src = url;
  7. document.body.appendChild(iframe);
  8. },
  9. 'location' : function(url) {
  10. window.location = url;
  11. },
  12. 'href' : function(url) {
  13. var a = document.createElement('a');
  14. a.style.display = 'none';
  15. a.href = url;
  16. document.body.appendChild(a);
  17. a.click();
  18. },
  19. 'script' : function(url) {
  20. var script = document.createElement('script');
  21. script.setAttribute('type', 'test/javascript');
  22. script.innerHTML = '(function(){' +
  23. 'var a = document.createElement("a");' +
  24. 'a.style.display = "none";' +
  25. 'a.href = "' + url.replace(/"/g, '\\"') + '";' +
  26. 'document.body.appendChild(a);' +
  27. 'a.click();' +
  28. '})()';
  29. document.body.appendChild(script);
  30. },
  31. 'open' : function(url) {
  32. window.open(url);
  33. }
  34. };

浏览器判断是否安装应用

很多时候用户在浏览器中打开 scheme 链接的时候,用户不一定安装了应用,这个时候打开会失效,我们希望打开这个动作应该下载应用。这个时候需要判断用户是否安装应用。

其实判断用户是否安装某个应用的方法,就是直接打开这个应用的 scheme,查看是否打开成功。但是这就是问题之所在。

我们无法在浏览器中准确地知道打开 scheme 是否成功,浏览器或者系统没有给我么这样的回调。我们只能用迂回的方法去判断。

比如在JavaScript中判断页面是否进入后台来判断打开成功。有下面这些事件和属性可以利用:

  • pagehide : 页面隐藏时触发
  • visibilitychange : 页面隐藏没有在当前显示时触发(切换tab也会触发该事件)
  • document.hidden : 当页面隐藏时,该值为true,显示时为false

上面这些事件或者属性并不是所有浏览器都支持。下面是一个给出为 id 为 open 的按钮添加打开scheme或者下载事件的例子。

  1. var downloader,
  2. scheme = 'weixin://', // 需要打开的 scheme 地址
  3. download='index'; // 如果打开scheme失效的app下载地址
  4. // 给 id 为 open 的按钮添加点击事件处理函数
  5. document.getElementById('open').onclick = function () {
  6. window.location.href = scheme; // 尝试打开 scheme
  7. // 设置3秒的定时下载任务,3秒之后下载app
  8. downloader = setTimeout(function(){
  9. window.location.href = download;
  10. }, 3000);
  11. };
  12. document.addEventListener('visibilitychange webkitvisibilitychange', function () {
  13. // 如果页面隐藏,推测打开scheme成功,清除下载任务
  14. if (document.hidden || document.webkitHidden) {
  15. clearTimeout(downloader);
  16. }
  17. });
  18. window.addEventListener('pagehide', function() {
  19. clearTimeout(downloader);
  20. });
  21. }

对于通过判断打开 scheme 的耗时来确实是否打开应用的做法是很容易失效的,因为无法判断打开成功以后,页面的JS是否还在执行,而且打开应用的耗时也是不可控的。

总之,没有完美的解决方案在H5页面中判断本地是否安装了某个应用,不过使用监听当前页面是否隐藏的方法能够很大程度的作为判断依据。

也有的应用不管用户是否安装应用,用户点击链接的时候,同时打开 scheme 和拉起下载页面,这种方式牺牲了很大的用户体验。

局限性

这种通过 scheme 打开本地应用的方式并不是所有浏览器都支持,尤其是在微信浏览器中是不支持使用 scheme 打开应用的,除非微信官方添加了白名单。QQ浏览器中倒是支持。

而且一些浏览器会询问用户是否打开,而另外一些则直接打开应用。

一般的做法是,判断当前浏览器是否为微信,如果是微信的话,则弹出一个遮罩层,提示用户使用其他浏览器打开。

还有就是在微信浏览器中使用应用宝的微下载,将当前页面重定向到应用宝的下载页面,不过这种方式的转化率很低。

有一个好消息是,在IOS9.0以上的系统中,可以使用 universal links 打开本地应用,不过Android不支持。

另外一个备选方案是,在微信浏览器中,使用iframe的方式打开一个包体地址(.apk结尾的url)进行下载时,会拉起一个选择框,让你选择打开的应用。不过这种方式对于某些域名无效,对于一些特殊的下载文件无效,如不能下载.rar的文件。而且对于已经安装了应用的用户来说,用户体验也不好。

使用这种技术的同时,考虑到其不确定性,应该做好备选方案。充分考虑到该页面的用户群体是否主要为新用户,以及访问的浏览器分布,从而制定相应的对用户来说比较友好的引导和备选方案。

原文出处:http://uusama.com/493.html

移动浏览器H5页面通过scheme打开本地应用的更多相关文章

  1. ionic 实现 应用内(webview中html页面点击) 和 应用外 (浏览器html页面点击) 打开本地安装应用

    应用内(webview中html页面点击) : 应用内打开本地安装应用指的是webview里打开应用,需要2个步骤: 1: 需要下载一个cordova插件:com.lampa.startapp ,也可 ...

  2. iOS/Android 浏览器(h5)及微信中唤起本地APP

    在移动互联网,链接是比较重要的传播媒质,但很多时候我们又希望用户能够回到APP中,这就要求APP可以通过浏览器或在微信中被方便地唤起. 这是一个既直观又很好的用户体验,但在实现过程中会遇到各种问题: ...

  3. 判断终端类型、微信的文章防盗链、h5页面跳转打开新的app、跳转到app市场

    判断终端的类型.安卓.ios.微信.qq function  GetMobelType()  {                 var  browser  =   {                 ...

  4. 浏览器h5新建文件 保存到本地(相当于浏览器写文件)

    function doSave(value, type, name) {         var blob;         if (typeof window.Blob == "funct ...

  5. android webview处理h5打开本地文件浏览器的功能

    这周遇到一个比较棘手的问题,需要在android上边集成h5页面,并且在h5页面上,需要用户能够上传android本地的照片,一开始我以为webview会自动处理掉的,因此没太留意,当真正集成时,才发 ...

  6. 如何判断一个 APP页面是否是H5页面

    1.无网络断开网络,显示404或则错误页面的是H5 2.页面布局a.在手机设置.开发者选项中开启显示布局边界功能:b.进入应用查看布局边界:c.原生应用可以看到各个控件的布局边界,H5只有整个页面的一 ...

  7. 如何判断一个 APP页面是否是H5页面(转载)

    1.无网络断开网络,显示404或则错误页面的是H5 2.页面布局a.在手机设置.开发者选项中开启显示布局边界功能:b.进入应用查看布局边界:c.原生应用可以看到各个控件的布局边界,H5只有整个页面的一 ...

  8. 微信中通过页面(H5)直接打开本地app的解决方案

    简述 微信中通过页面直接打开app分为安卓版和IOS版,两个的实现方式是完全不同的. 安卓版实现:使用腾讯的应用宝,只要配置了“微下载”之后,打开链接腾讯会帮你判断本地是否已经安装了app,如果本地安 ...

  9. 京东在html5页面中打开本地app的解决方案

    转:https://blog.csdn.net/CameloHuang/article/details/64476385 从html5打开本地的app–如果本地没有app就跳转到下载页面,大家都会认为 ...

随机推荐

  1. 查看oracle数据库里哪些语句耗时最长或者效率最低

    CPU: select * from (select v.sql_id, v.child_number, v.sql_text, v.elapsed_time, v.cpu_time, v.disk_ ...

  2. js 图片转换为base64

    <input id="file" type="file"> <img id="img" style="max-h ...

  3. [转] 深刻理解Python中的元类(metaclass)

    非常详细的一篇深入讲解Python中metaclass的文章,感谢伯乐在线-bigship翻译及作者,转载收藏. 本文由 伯乐在线 - bigship 翻译.未经许可,禁止转载!英文出处:stacko ...

  4. 静态频繁子图挖掘算法用于动态网络——gSpan算法研究

    摘要 随着信息技术的不断发展,人类可以很容易地收集和储存大量的数据,然而,如何在海量的数据中提取对用户有用的信息逐渐地成为巨大挑战.为了应对这种挑战,数据挖掘技术应运而生,成为了最近一段时期数据科学的 ...

  5. lua 函数调用1 -- 闭包详解和C调用

    这里, 简单的记录一下lua中闭包的知识和C闭包调用 前提知识: 在lua api小记2中已经分析了lua中值的结构, 是一个 TValue{value, tt}组合, 如果有疑问, 可以去看一下 一 ...

  6. 0:A+B Problem-poj

    0:A+B Problem 总时间限制:  1000ms 内存限制:  65536kB 描述 Calculate a + b 输入 Two integer a,,b (0 ≤ a,b ≤ 10) 输出 ...

  7. 京东分布式缓存redis应用实战

    互联网应用特点三高:高并发.高可用.高性能,要达到这几个目标,好的方法方式是建立相应指标, 来进行准确描述,有了准确指标进行监控,方能易于实现我们设定目标. 先将指标介绍下,方便下面相关术语使用,qp ...

  8. spring bean的创建过程

    spring的核心容器包括:core.beans.context.express language四个模块.所以对于一个简单的spring工程,最基本的就是依赖以下三个jar包即可: <depe ...

  9. SpringCloud学习笔记(3)——Hystrix

    参考Spring Cloud官方文档第13.14.15章 13. Circuit Breaker: Hystrix Clients Netflix提供了一个叫Hystrix的类库,它实现了断路器模式. ...

  10. ThinkPHP中ajax绑定select下拉框无法显示

    html代码: 控制器代码: 其中的<option value="{$vo.gradeId}">{$one.gradeName}</option> 在操作过 ...