最近写项目,遇到一个比较有意思的需求,涉及到公司所有前端工作,H5,Android,IOS
需求是这样的,
公司运营推广APP,对外分享一个链接,这个链接由h5写成,主要就是用来介绍APP的,蛋疼的是,在末尾加了两个按钮,一个用来下载IOS的app,一个用来下载android的app,重点来了啊,在点击按钮之前先判断手机中是否有该APP,有的话,直接打开,没有的话,就直接下载!
听着需求挺简单的,我当时一听也挺简单的,第一反应想的是:遍历,遍历检索app,识别包名,但是做着做着,就感觉不对了,为什么呢?回头仔细想想!因为啊,这个链接是有运维人员发的分享,这个分享我们压根就不知道会被发到什么地方去,有可能是qq好友,有可能是qq空间,微信,新浪,甚至各种社交平台,那么也就是说这个h5页面已经脱离了我们android的控制范围了,控制不了那还怎么与js交互啊,不能交互,还怎么通过android来进行遍历检索app啊,瞬间就懵逼了!!
苦苦思索啊,最后还是在百度的帮助下解决问题,不得不说,百度的强大啊!这里先给出两个链接吧:
https://blog.csdn.net/u010394015/article/details/51444744
https://blog.csdn.net/liulinghuidage/article/details/53906813
我就是通过这两篇文章解决的问题,有兴趣的可以先去了解一下!
这两篇文章中都提到了一个关键词:Scheme (方案),这个属性及其重要,他可以实现app的内部跳转,外部唤起,最重要的是js也可以通过他
仔细想想,仔细琢磨,惊然发现,app跳转页面竟然有多种方式,
最常见的一种:
Intent intent = new Intent(Entrust_CP_Activity.this, Entrust_SQ_Activity.class);
startActivityForResult(intent, DashApplication.CP_TO_SQ_req);
或者
Intent intent = new Intent(activity, Login_New_Activity.class);
startActivity(intent);
还有一种,也是常常被我们忽略的一种,就是通过Scheme来实现跳转:
PackageManager packageManager = getPackageManager();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("xl://goods:8888/goodsDetail?goodsId=10011002"));
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
boolean isValid = !activities.isEmpty();
if (isValid) {
startActivity(intent);
}
其中 xl://goods:8888/goodsDetail?goodsId=10011002 是一种内部约定的协议,需要遵守它的顺序结构:在 https://blog.csdn.net/liulinghuidage/article/details/53906813 这个链接中有提到,讲的很详细,他是这样说的:
URL Scheme协议格式:
先来个完整的URL Scheme协议格式:
xl://goods:8888/goodsDetail?goodsId=10011002
通过上面的路径 Scheme、Host、port、path、query全部包含,基本上平时使用路径就是这样子的。
xl代表该Scheme 协议名称
goods代表Scheme作用于哪个地址域
goodsDetail代表Scheme指定的页面
goodsId代表传递的参数
8888代表该路径的端口号
URL Scheme如何使用:
1.)在AndroidManifest.xml中对<activity />标签增加<intent-filter />设置Scheme
<activity
android:name=".GoodsDetailActivity"
android:theme="@style/AppTheme">
<!--要想在别的App上能成功调起App,必须添加intent过滤器-->
<intent-filter>
<!--协议部分,随便设置-->
<data android:scheme="xl" android:host="goods" android:path="/goodsDetail" android:port="8888"/>
<!--下面这几行也必须得设置-->
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>
这样配置一番的话,是不是就有一种眼前一亮的感觉,如果还是持有怀疑态度的话,也不要紧,我们还有一套检测的代码:
4.)如何判断一个Scheme是否有效
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
PackageManager packageManager = getPackageManager();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("xl://goods:8888/goodsDetail?goodsId=10011002"));
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
boolean isValid = !activities.isEmpty();
if (isValid) {
startActivity(intent);
}
}
});
将这段代码粘入同一model下的另一个activity的点击事件中,运行看看能不能调起那个被配置的activity,能的
话就说明配置没有问题,不能就说明配置错误,反正我试了,是没问题的。。。
以上说了那么多,还是没有具体的来解决我项目中的问题,不要急,好戏才刚开始~
当配置成功后,我们只需要将这个协议发给js人员就ok了,
这里再附上一份js的代码:
//打开(下载)App
function dian(){
var ua = window.navigator.userAgent.toLowerCase();
//微信
if(ua.match(/MicroMessenger/i) == 'micromessenger'){
window.location.href='downLoadForPhone';
}else{//非微信浏览器
if (navigator.userAgent.match(/(iPhone|iPod|iPad);?/i)) {
var loadDateTime = new Date();
window.setTimeout(function() {
var timeOutDateTime = new Date();
if (timeOutDateTime - loadDateTime < 5000) {
window.location = "";//ios下载地址
} else {
window.close();
}
},2000);
window.location = "schema://";
}else if (navigator.userAgent.match(/android/i)) {
var state = null;
try {
window.location = 'xl://goods:8888/goodsDetail?goodsId=10011002'; // 这个协议可以随便换
setTimeout(function(){
window.location= ""; //android下载地址
},500);
} catch(e) {}
}
}
最后将这份js代码打上服务器版本,用浏览器运行一下,完美收工!!
这里提醒一下,android人员不要自作聪明,以为将h5页面放到本地,通过webview运行就能跑通,明确的告诉你,不可能,跑不通,因为我试过!!具体为什么,还在研究中!百度上倒是给了一个说法,好像是要将apk以及h5放在同一服务器下的,具体怎么弄的,我也没实践过,留着以后补吧~~~
---------------------
作者:Android小哥哥~
来源:CSDN
原文:https://blog.csdn.net/weixin_40430041/article/details/81707355
版权声明:本文为博主原创文章,转载请附上博文链接!