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

scheme协议定义

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

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

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

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

下面看一个例子:

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 节点的配置拦截器规则

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

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

<data
android:scheme=""
android:host=""
android:port=""
android:path=""
android:mimeType=""
android:pathPattern=""
android:pathPrefix=""
android:ssp=""
android:sspPattern=""
android:sspPrefix=""/>

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

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

其中的 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 标签中打开。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Scheme</title>
</head>
<body>
<a href="wexin://" id="open">打开应用</a>
</body>
</html>

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

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

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

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

  • 新建一个隐藏的 iframe ,地址指向需要打开的url
  • 使用 window.location 或者 window.location.href 刷新当前页面
  • 新建一个隐藏的 a 标签,地址指向打开的url,并触发打开链接事件
  • 动态创建一个script脚本,在这个脚本中新建一个a标签并打开
// 打开url的方式
var urlOpen = {
'iframe' : function(url) {
var iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.src = url;
document.body.appendChild(iframe);
},
'location' : function(url) {
window.location = url;
},
'href' : function(url) {
var a = document.createElement('a');
a.style.display = 'none';
a.href = url;
document.body.appendChild(a);
a.click();
},
'script' : function(url) {
var script = document.createElement('script');
script.setAttribute('type', 'test/javascript');
script.innerHTML = '(function(){' +
'var a = document.createElement("a");' +
'a.style.display = "none";' +
'a.href = "' + url.replace(/"/g, '\\"') + '";' +
'document.body.appendChild(a);' +
'a.click();' +
'})()';
document.body.appendChild(script);
},
'open' : function(url) {
window.open(url);
}
};

浏览器判断是否安装应用

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

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

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

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

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

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

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

对于通过判断打开 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. 基于HTML5的WebGL经典3D虚拟机房漫游动画

    第一人称在 3D 中的用法要参考第一人称在射击游戏中的使用,第一人称射击游戏(FPS)是以第一人称视角为中心围绕枪和其他武器为基础的视频游戏类型 ; 也就是说,玩家通过主角的眼睛来体验动作.自从流派开 ...

  2. oracle存储过程统计用户各表记录数

    declare v_tName varchar(50); v_sqlanalyze varchar(500); v_num number; v_sql varchar(500); cursor c1  ...

  3. [认证授权] 5.OIDC(OpenId Connect)身份认证授权(扩展部分)

    在上一篇[认证授权] 4.OIDC(OpenId Connect)身份认证授权(核心部分)中解释了OIDC的核心部分的功能,即OIDC如何提供id token来用于认证.由于OIDC是一个协议族,如果 ...

  4. js中的break,continue和return到底怎么用?

    为什么要说个?好像很简单,但是我也会迷糊,不懂有时候为什么要用return,然而break和continue也经常和他放在一起. 所以就一起来说一说,这三个看起来很简单,却常常会出错的关键词的具体用法 ...

  5. Oracle单行函数基础运用

    单行函数 整个SQL的精髓:select语句+单行函数(背) 字符串函数 常用的处理字符串的函数有如下: No. 函数名 含义 1 UPPER(c1)  upper 将字符串全部转为大写 2 LOWE ...

  6. 入坑第二式 golang入坑系统

    史前必读: 这是入坑系列的第二式,如果错过了第一式,可以去gitbook( https://andy-zhangtao.gitbooks.io/golang/content/ )点个回放,看个重播.因 ...

  7. Python [习题] 文件操作:目录间copy 文件

    [习题] 指定一个源文件,实现copy到目标目录.例如把/tmp/sample1.txt 拷贝到/tmp/sample2.txt原文件需要有读权限(默认rt权限),目标文件需要给写(w即可)权限. I ...

  8. springmvc中对日期格式化的处理

    @DateTimeFormat(pattern="yyyy-MM-dd") 返回的时候java.util.Date pattern="yyyy-MM-dd"必须 ...

  9. openstack windows 2008镜像 制作

    openstack windows 2008镜像 制作 openstack centos6 centos7 kvm 镜像制作 http://www.cnblogs.com/elvi/p/7922421 ...

  10. javassist:字节码编辑器工具

    简介: javassist是一款可以在运行时生成字节码的工具,可以通过它来构造一个新的class对象.method对象,这个class是运行时生成的.可以通过简短的几行代码就可以生成一个新的class ...