一文理清H5调起App那些事

Posted 白玉梁

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文理清H5调起App那些事相关的知识,希望对你有一定的参考价值。

以安卓为例,实现h5调起app步骤:

  1. 在安卓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!

  2. 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!

  3. 接下来,在网页中写一个超链接<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

以上是关于一文理清H5调起App那些事的主要内容,如果未能解决你的问题,请参考以下文章

一文理清H5调起App那些事

一文理清H5调起App那些事

如何实现在H5里调起高德地图APP

如何实现在H5里调起高德地图APP?(上)

如何实现在H5里调起高德地图APP

一文搞懂PyTorch与CUDA那些事