在移动端浏览器H5页面中,点击按钮打开本地应用主要经过 scheme 协议。本文主要介绍如何在浏览器H5页面中经过 scheme 协议打开本地应用。javascript
scheme 是一种页面之间跳转的协议,不只能够用于app之间进行跳转,还能够用于 H5 页面跳转到app页面。html
不管Android仍是IOS,均可以经过在H5页面中打开 scheme 协议的地址,从而打开本地app。java
scheme 协议定义和 http 协议相似,都是标准的 URI 结构。android
[scheme:][//host:port][path][?query][#fragment]
下面看一个例子:web
wexin://tencent.com:8080/dl/news/open?data=902323¶ms=test
URI中的参数若是包含特殊字符,须要预先进行url编码,不然的话URI可能不能打开。数组
要使得在浏览器或者别的应用中经过打开 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。app
<data android:scheme="" android:host="" android:port="" android:path="" android:mimeType="" android:pathPattern="" android:pathPrefix="" android:ssp="" android:sspPattern="" android:sspPrefix=""/>
而后在相应的 activity 能够获取 uri 中参数。ide
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 信息:
在浏览器中打开 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代码中打开链接有如下几种方式:
// 打开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中判断页面是否进入后台来判断打开成功。有下面这些事件和属性能够利用:
上面这些事件或者属性并非全部浏览器都支持。下面是一个给出为 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的文件。并且对于已经安装了应用的用户来讲,用户体验也很差。
使用这种技术的同时,考虑到其不肯定性,应该作好备选方案。充分考虑到该页面的用户群体是否主要为新用户,以及访问的浏览器分布,从而制定相应的对用户来讲比较友好的引导和备选方案。