以安卓为例,实现h5调起app步骤:
-
在安卓AndroidManifest.xml中,启动Activity下添加属性:
<intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="xxx" /> </intent-filter>
自定义scheme://host/path,例如:mqqwpa://im/chat?chat_type=wpa,对应安卓中的data:
<data android:scheme="mqqwpa" android:host="im" android:pathPrefix="/chat"/>
“?”后带参chat_type,值为wpa,跟我们常用的http url或api是一样的:http://www.baidu.com?id=1!
-
Activity中,写接收代码:
String action = getIntent().getAction(); if (Intent.ACTION_VIEW.equals(action)) { Uri uri = getIntent().getData(); if (uri != null) { LogUtil.e(uri.getHost() + uri.getPath()); } }
我们通过getHost和getPath来判断具体的打开路径,通过
uri.getQueryParameter("id")
来获取参数,然后再跳转到目标Activity! -
接下来,在网页中写一个超链接
<a href="mqqwpa://im/chat?chat_type=wpa">打开app</a>
,点击超链接即可调起App!
这里有两个需要注意点的:
-
1.我们该如何定义scheme://host/path?
一般的,我们定义路径时,最好只定义scheme,例如:
<data android:scheme="xxx" />
而不定义具体的host和path,这样做的好处是,我们不可能仅仅只跳转一个Actviity,当需要跳转多个Activity时,我们只需要在h5中写不同的路径(保证scheme统一)就行,代码中我们通过获取host和path去判断具体跳转意图既可!
-
2.我们该将scheme定义在哪个Activity?
这里需要再次强调第一条,为什么要只定义scheme,而不定义具体host和path,因为我们不仅仅只需要打开一个Activity,如果定义具体host和path,那么我们就需要在清单文件中的不同activity下定义多个data,这样做理论上也是可以的,但弊端就是,当我们打开某个具体Activity后按返回键会直接退出应用,这样应该不符合良好的用户体验吧?
所以,一般的,最好把scheme定义在启动页SplashActivity,代码中只需在SplashActivity->MainActivity这一步后面加上intent的action以及scheme的判断,再次跳转即可:
startActivity(new Intent(mContext, MainActivity.class)); String action = getIntent().getAction(); if (Intent.ACTION_VIEW.equals(action)) { Uri uri = getIntent().getData(); if (uri != null) { if (uri.getHost().equals("xxx") && uri.getPath().equals("/xxx")) { String id = uri.getQueryParameter("id"); if (!TextUtils.isEmpty(id)) { Intent intent = new Intent(mContext, XXXActivity.class); intent.putExtra(Const.PARAM_ID, id); startActivity(intent); } } } }
这样就可以快速进入目标Activity,且按返回键时,会返回到MainActivity中,不会退出应用(Splah和Main的启动方式最好为SingleTask)!
这样,一个h5调起app的功能就写好了,但当你拿出来给产品和测试同学使用的时候,就会被无情打脸!!!
问题一,当用户未安装app时,点击调起链接没有任何反应,而产品需求是,未安装app,跳转至下载页面,已安装app直接打开;
问题二,也是最致命的问题,一般的分享推广推销都是在微信中进行的,当你在微信中给一个好友分享一个推广网页时,好友点击打开app没有任何反应,你会不会感到绝望?
先说问题一,因为h5中无法直接判断用户是否安装了应用,所以广大网友也有自己的解决办法,就是点击打开app按钮时,调用js方法,不管安装没安装,在n秒后都进入下载页!但实际上,当你在浏览器中点击后,浏览器都会有一个弹框提示“是否打开app”,用户同意的快还好,如果同意的慢,一是弹框几秒后会消失,二是因为我们写了下载方法,所以会弹出下载提示,这个体验是非常糟糕的!
window.location = "mqqwpa://im/chat?chat_type=wpa";
let loadDateTime = new Date();
window.setTimeout(function () {
let timeOutDateTime = new Date();
if (timeOutDateTime - loadDateTime < 5000) {
window.location = "http://qq.apk";
} else {
window.close();
}
},
500);
我这里有一个相对完美的解决办法,自己做一个过渡页(h5),在过渡页中通过window.onlaod自动打开我们的scheme,过渡页中有两个按钮,打开和下载,当用户未安装应用时无法自动跳转,就直接停留在过渡页,用户可以根据需求做出选择!
下面是一个直接打开qq聊天窗口的例子:
当我们跳转至该网页时,会自动提示是否打开app,当停留在此页面时,用户可以选择打开或下载!
但实际使用时,又被无情打脸,也就是上面所说的问题二,在qq全家桶,qq,qq浏览器,微信中,window.onload失效,无法自动跳转,只能手动点击跳转:
而在微信中,不但window.onload失效,就连手动点击也是完全没有反应的,这就让人犯了难,全国最火的广告推广软件微信不支持调起app?这可如何是好?
当然,解决办法也不是没有,腾讯应用宝提供了自家的微下载推广功能,前提是你的app在腾讯应用宝上架了才能使用:
腾讯开发平台后台管理,打开自己的应用:
配置安卓和ios应用地址,定义好scheme,然后将h5中的链接改为应用宝提供的链接,此时再次在qq全家桶中测试,会进入应用宝提供的应用打开和下载过渡页,在此页面会自动调起app:
但别急,又出问题了,qq全家桶没问题了,但其它浏览器又出问题了:
其它浏览器打开此界面,完全不识别应用,只有下载按钮可选!!!
这。。。笔者也是很无语。。。,那么现在的解决办法只有判断浏览器,是qq,微信 还是其它浏览器,然后跳转不同链接,qq全家桶就跳转应用宝链接,其它浏览器就跳转自定义scheme:
let u = navigator.userAgent;
if (u.indexOf('QQ') > -1 || u.indexOf('WeChat') > -1) {
window.location ="https://a.app.qq.com/o/simple.jsp?pkgname=com.tencent.mobileqq";
} else {
window.location = path;
}
但问题又来了(这么多问题笔者也米有办法- -),虽然应用宝页面可以调起app,但我定义的scheme以及参数呢?无法传递和接收啊??是个大问题!
但,别着急,腾讯开放平台提供了applink能力,接入后,就可以将自己的scheme拼接在应用宝链接后面,在qq全家桶包括微信中完美打开指定页面,同时支持安卓和苹果,需要指出的是,applink能力需要申请,而且不支持用户直接后台操作申请,需要加qq群找管理申请(这个操作笔者也有点迷- -!),另外如果你未安装app,那么在应用宝链接页面点击下载后,它会自动将你得scheme信息复制到剪切板上,你在下载安装并打开app后,可以检测剪切板内容,并做相应跳转!
打开腾讯应用宝接入文档:找到下方:
进入qq群,找群主申请,通过后在链接后面拼接自己的scheme(需要urlencode)就可以了:
window.location ="https://a.app.qq.com/o/simple.jsp?pkgname=com.tencent.mobileqq
&android_schema=xxx&ios_scheme=xxx";
以下是对于各浏览器对h5调起app的支持情况总结:
QQ/QQ浏览器 | 微信 | 其它浏览器 | |
---|---|---|---|
window.onload | 不支持 | 不支持 | 支持 |
自定义scheme | 支持 | 不支持 | 支持 |
自定义下载 | 支持 | 不支持 | 支持 |
应用宝链接 | 支持 | 支持 | 不支持 |
H5页面源码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Title</title>
<style>
* {
margin: 0;
padding: 0;
}
.container {
max-width: 640px;
height: 100vh;
margin: auto;
background: #3a8ee6;
text-align: center;
padding-top: 50%;
}
.container img {
width: 80px;
height: 80px;
margin-bottom: 40px;
}
.container .btn {
margin-top: 10px;
width: 80%;
height: 45px;
background: #2bd9b4;
border-radius: 23px;
color: white;
text-align: center;
line-height: 45px;
margin-left: 10%;
}
</style>
</head>
<body>
<div class="container">
<div>
<img src="https://pp.myapp.com/ma_icon/0/icon_6633_1631677952/96">
</div>
<div class="btn" onclick="openApp()">打开QQ</div>
<div class="btn" onclick="toDown()">下载QQ</div>
</div>
<script>
let path = "mqqwpa://im/chat?chat_type=wpa&uin=800013811";
function toDown() {
let u = navigator.userAgent;
let url;
if (u.indexOf('iPhone') > -1) { //iphone
url = "https://apps.apple.com/cn/app/qq/id444934666"
} else if (u.indexOf('Android') > -1) { //android
url = "https://down.qq.com/qqweb/QQ_1/android_apk/Android_8.8.28.6155_537094708_32.apk"
}
window.location = url;
}
function openApp() {
let u = navigator.userAgent;
if (u.indexOf('QQ') > -1 || u.indexOf('WeChat') > -1) {
window.location =
"https://a.app.qq.com/o/simple.jsp?pkgname=com.tencent.mobileqq&android_schema=" + encodeURIComponent(path) +
"&ios_scheme=" + encodeURIComponent(path);
} else {
window.location = path;
}
}
window.onload = function() {
openApp();
}
</script>
</body>
</html>
微下载Applink接入文档:
### android_schema 参数传递方式(该协议在浏览器能唤起的即可)
例如,原微下载链接为:
http://a.app.qq.com/o/simple.jsp?pkgname=com.xxx.xxx
对应的应用跳转伪协议为:
xxx://xxx/test?id=1
则在原微下载链接中传递android_schema 参数即可,注意需要做urlencode,如下:
http://a.app.qq.com/o/simple.jsp?pkgname=com.xxx.xxx
&android_schema=xxx%3A%2F%2Fxxx%2Ftest%3Fid%3D1
如果需要安卓和IOS同时支持APPlink,则把两个对应的schema拼接即可
例:http://a.app.qq.com/o/simple.jsp?pkgname=com.xxx.xxx
&ios_scheme=xxx%3A%2F%2Fxxx%2Ftest%3Fid%3D1
&android_schema=xxx%3A%2F%2Fxxx%2Ftest%3Fid%3D1
PS:
1、通常scheme带的第一个参数用?连接;
2、scheme自查:
A.将未encode的scheme:xxx://xxx/test?id=1,直接复制到浏览器的地址栏里,点击进入;
B.将encode的scheme拼在微下载的链接测试页面自测
http://qzs.qq.com/open/yyb/wxz_tools/html/schemetools.html?type=1&sch=
xxx%3A%2F%2Fxxx%2Ftest%3Fid%3D1