web 调起 App? 光知道 scheme 可不够!

不少人会遇到这个问题,大多数都是站在移动端的角度去解释这个问题,本篇文章将会从web端的角度分析问题,解决问题html

背景

了解背景,有助于咱们更加深刻的理解需求,分析需求

用户和流量的量级决定了一款互联网产品的优秀度。对一款优雅的互联网产品而言,app端和web端是必不可少的,咱们借助它们造成闭环,保证用户体验和活跃度。除了端的覆盖,咱们还要作到端到端的交互,由此咱们提出了产品的需求: wap页唤起app,若是用户没装app则跳转到下载页(引导页都行)。若是用户已安装,根据URL跳到app内指定的界面,这也正是本文正要解决的问题android

1. 先说一个最常规的方法,也是最经常使用的方法:scheme

举个🌰:web

wzry://videolists.show/mark/penta_kill?num=1
复制代码

这种方式须要事先在app中注册相应的scheme,经过网页访问已注册的scheme,达到调起App客户端及相关界面json

Android的相关配置: AndroidManifest.xml
<activity android:name=".ui.SchameFilterActivity">
	<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:host="videolists.show"
	    android:path="/mark/penta_kill"
	    android:scheme="wzry"/>
	</intent-filter>
</activity>
复制代码
iOS 图像化配置还说啥

至于定义scheme之后的逻辑请自行google,可是逻辑中必定要作防御

好了咱们能够愉快的使用了浏览器

<a href="wzry://videolists.show//mark/penta_kill?vid=666">你过来啊!</a>
复制代码

(你也用直接访问地址的方式,这种方式有小坑:有些浏览器是会返回404状态码,或者变成搜索结果页,小烦)bash

声明sheme后,回过头来看一下需求:用户安装了app,调起app。用户未安装咱们须要引导用户下载 。那这里就有一个问题了:网页是不知道用户有没有安装app的。那咱们换一个思路----可不能够知道页面被置于后台了?页面进入后台,能够认为是唤起成功了;页面没进入后台,说明唤起失败(没安装or其余缘由)微信

一个新的API彻底知足上边提到的需求 : Page Visibility API,文档中详细的介绍了这个API---->能够准确的知道页面当前的状态(前台,后台等状态),可是这个API太新了,须要较新的浏览器支持,覆盖率有点低。放一张图感觉一下:app

因此咱们不能大面积使用。如之奈何?交给黑科技了: 定时器

我先说一下思路:ide

  • setTimeout的实现过程:ui

    浏览器尝试打开URL scheme并记录时间点t1,在2秒计时后,检查当前时间t2,若是t2-t1 > 2200ms,说明唤起app成功(唤起app会是浏览器的定时器延后执行),若是t2-t1 < 2200ms,可能没有安装app,能够引导用户进入下载页

  • setInterval实现过程

    原理上跟setTimeout类似,方法上换成设置一个比较小的时间间隔(例如20ms),运行屡次(例如100),比较运行完100次的总耗时与20*100的时间差。逻辑判断同setTimeout

优缺点:

  • setTimeout不稳定,由于Android是基于Linux分时多任务的,setTimeout的基准误差不会那么大,比较难调教

  • setInterval要好一点,页面一直处于前台(调起app失败),则100次跑完,总耗时与 100x20=2000ms不会有太大差别,但页面在后台运行时(调起app成功),此时间会明显超过2000ms

注:不知道setTimeout,setInterval为何会延迟执行的,请恶补一波它们的执行原理

好了嘴炮打完,上🌰:

setTimeout

var openTime = +new Date();
window.location.href = 'wzry://videolists.show/mark/penta_kill?num=1'
var timer = setTimeout(function () {
    if ((new Date()) - openTime < 2200) {//加了200ms基准偏差
        window.location.href = 'you app download page';
    }
    if ((new Date()) - openTime > 2200) {
        clearTimeout(timer);
    }
}, 2000);
复制代码

setInterval

var limit_num = 100;
var openTime = +new Date();
window.location.href = 'wzry://videolists.show/mark/penta_kill?num=1'
var timer = setInterval(function () {
   if(limit_num > 0){
        limit_num--;
   }else{
        if ((new Date()) - openTime < 2200) {//加了200ms基准偏差
            window.location.href = 'you app download page';
        }
        clearTimeout(timer);
   }
}, 20);
复制代码

当咱们完成这些操做以后,在通常环境下是能够正常唤起app的了

2. 那我再说一下特殊状况 ----微博,微信等

像这种爸爸级别的应用是有scheme白名单的,只有白名单内的scheme才不会被过滤掉,就问你怕不怕?嗯?

像这种咱们怎么去解决那?

(I). 其实最简单的办法就是像爸爸低头----使用应用宝。

使用它颁发给你的应用地址,向这个地址跳转,而后一切就交给爸爸了,直接无视微信什么的,直接带你飞到app内

(II). 使用 Universal Links

它是iOS9推出的一项强大的功能。可让你 经过http连接的方式唤起你的app(无论你的在微信/微博仍是其余app内,由于Universal Links是由系统直接处理的),下面我来简单说一下怎么使用Universal Links完成唤醒的app,你也能够经过官方文档详细的了解它。

首先

  • 必须给域名配置https才能使用它
  • 在开发者中心作配置:找到对应的App ID ——> Associated Domains,设置成Enabled
  • 打开工程,在capabilities中设置Associated Domains,在其中的Domains中填入你想支持的域名,注意必须以applinks:为前缀
  • 编辑apple-app-site-association文件(文件名,json格式不能改变,注意apple-app-site-association文件是没有格式后缀的)
{
    "applinks": {
        "apps": [],
        "details": [
            {
                "appID": "TeamID + BundleId TeamID",
                "paths": [ "/mark/penta_kill?num="]
            }
        ]
    }
}
复制代码
  • 上传该文件到域名的根目录,确保能够被访问

作完这些,你就能够尝试唤起你的iOS app了

这里还要强调一下 拦截的地址 必定要与当前webview的url 不在同一个域名下。这样Universal Links才会生效,不要问我怎么知道的,都是血泪啊

3. 还有最后一种 ---- 本身作引导,引导用户浏览器打开,绕过限制。不过这样,步骤较多,折损率可能会升高

综上,Android app除了使用应用宝跳转唤起和引导页没发现其余更好的办法,iOS方案多了个Universal Links,这也是为何咱们常常看到有些app在微信/微博中 iOS端能够直接唤起app,而Android端常常是须要走一道应用宝的缘由

好了,以上内容就是我对唤起app的一些总结和经验,但愿能够帮助到你

未经本人容许,不得转载。文章有疏漏浅薄之处,请各位大神斧正

修改 : 通过验证微信添加了一个屏蔽Universal Links的爆炸功能,大体原理参考:Prevent universal links from opening in WKWebView/UIWebView

微信内置浏览器想怎么改就怎么改,厉害厉害

相关文章
相关标签/搜索