从同构的角度和降级支持的角度来看,使用Android和iOS系统增强的AppLinksUniversal Links,通过HTTPS统一标准打开APP是标准的选择。

使用自定义Scheme打开APP适用于:

  1. 网站尚不支持HTTPS;
  2. App的iOS版本尚未添加Universal Links支持;
  3. APP的Android版本尚未添加AppLinks支持,同时需要支持Android 6.0以下版本。

使用自定义Scheme打开App的难点在于浏览器的兼容性问题和alert弹窗的提示干扰问题。 在iOS和Android中可以用location.href请求自定义Scheme可以打开App,用iframe只能在Android中打开,在iOS中无法打开。故下面的实现用location.href请求的方案。

DEEP-LINK.JS基础上修改为applink,放在团队代码库下。 将原来DeepLink的方案扩展为AppLink,使其兼容常见下载的需求。

基本思路

  1. 自动跳转链接赋值给href属性作为下载的默认值;
  2. 将AppStore地址、Android下载包地址、应用宝推广链接和应用deeplink地址赋值给自定义属性供程序使用;
  3. 将下载链接进行优化,避免302跳转带来的性能损失;
  4. 监听a链接点击事件,当存在deeplink时,尝试打开App,打开失败后进行下载或AppStore跳转(微信内部跳转到应用宝);
  5. visibility发生变化后,取消备用方案执行。

核心代码

<a 
    href="download-link"                         // 服务器端设置的根据UA判断的自动跳转链接,包含下面4中情况
    data-href-android="android-download-link"    // Android包下载地址
    data-href-ios="itunes-link"                  // itunes地址
    data-href-qq-android="myapp-link"            // 应用宝推广地址
    data-href-qq-ios="myapp-link"                // 应用宝推广地址
    data-deeplink="deep-link"                    // 跳转App地址
>立即打开</a>
// 下载链接优化代码
// 根据agent取指定的值进行优化赋值
function optimize(anchor) {
    if (!anchor) {
        return;
    }

    var href = anchor.getAttribute('data-href-' + agent);

    if (!href) {
        return;
    }

    anchor.href = href;
}
// 尝试打开App代码
// App打开之后,浏览器转入后台运行,计时器会暂停,根据这个时间差判断是否打开了App
// 如果App打开失败,则执行后备方案,跳转到href地址进行App下载活安装
document.body.addEventListener('click', function (e) {
    // Hijack click event

    var target = e.target,
        deeplink = target.getAttribute('data-deeplink'),
        start;

    if (target.tagName.toLowerCase() !== 'a' || !deeplink || clicked || timeout) {
        return;
    }

    e.preventDefault();
    e.stopImmediatePropagation();

    // Store start time
    start = Date.now();
    clicked = true;

    // Timeout to detect if the link worked
    timeout = setTimeout(function () {
        // Check if any of the values are unset
        if (!clicked || !timeout) {
            return;
        }

        // Reset things
        clicked = false;
        timeout = null;

        // Has the user left the screen? ABORT!
        if (Date.now() - start >= delay * 2) {
            return;
        }

        open(target.href);
    }, delay);

    // Go to app
    open(deeplink);
}, false);
// 取消备用代码执行
// 当浏览器窗口发生visibility变化时,App应该被调起过
function handleVisibilityChange() {
    // Triggered on blur
    if (!clicked || !timeout) {
        return;
    }

    // Reset everything
    clearInterval(timeout);
    timeout = null;
    clicked = false;
}

document.addEventListener(visibilityChange, handleVisibilityChange, false);

测试结果

任何技术方案和要交付的工作,必须做足够多的测试,因为我们要为自己的产出负责,要为下游的测试同事负责——而且自我再多的测试也是不足够充分的,总有一些小漏洞在暗处等着你我,出现问题解决问题这是我们的态度。

已安装启动测试结果

系统版本\浏览器系统浏览器UC浏览器百度浏览器QQ浏览器猎豹浏览器
iOS 8.4.1直接启动ActionSheet确认打开AppStore,返回后触发ActionSheet确认打开AppStore直接启动直接启动,返回后打开应用宝App页面直接启动,返回后浏览器内部打开AppStore
iOS 9.3.5弹窗确认直接启动直接启动直接启动,返回后打开应用宝App页面直接启动
iOS 10.1.1弹窗确认ActionSheet确认直接启动直接启动,返回后打开应用宝App页面直接启动,返回后浏览器内部打开AppStore
Z2 Android 4.4.2直接启动ActionSheet确认,返回后触发下载无法启动,触发下载弹窗确认,返回后触发下载弹窗确认
MX5 Android 5.0.1直接启动,触发下载直接启动,触发下载无法启动,触发下载弹窗确认,返回后触发下载弹窗确认
X6 Android 5.0.2ActionSheet确认,返回后触发下载ActionSheet确认,返回后触发下载无法启动,触发下载弹窗确认,返回后触发下载弹窗确认,返回后触发下载
T2 Android 5.1.1直接启动ActionSheet确认无法启动,触发下载弹窗确认,返回后触发下载直接启动
Mi5 Android 6.0.1直接启动ActionSheet确认,返回后触发下载无法启动,触发下载弹窗确认,返回后触发下载弹窗确认,返回后触发下载
6P Android 7.0.0直接启动ActionSheet确认,返回后触发下载无法启动,触发下载弹窗确认弹窗确认,返回后触发下载

未安装下载测试结果

系统版本\浏览器系统浏览器UC浏览器百度浏览器QQ浏览器猎豹浏览器
iOS 8.4.1先显示链接错误弹窗,再AppStore打开确认先显示链接错误弹窗,之后ActionSheet提醒打开AppStore直接打开AppStore打开应用宝App页面提示应用未安装之后在浏览器内部打开AppStore
iOS 9.3.5先显示链接错误弹窗,再AppStore打开确认ActionSheet提醒打开AppStore直接打开AppStore打开应用宝App页面提示应用未安装之后打开AppStore
iOS 10.1.1先显示链接错误弹窗,再AppStore打开确认直接打开AppStore直接打开AppStore打开应用宝App页面浏览器内部打开AppStore
Z2 Android 4.4.2打开自定义scheme页面ActionSheet提示打开App,关闭ActionSheet后开始下载直接下载直接下载直接下载
MX5 Android 5.0.1直接下载直接下载直接下载直接下载直接下载
X6 Android 5.0.2直接下载ActionSheet提示打开App,关闭ActionSheet后开始下载直接下载直接下载直接下载
T2 Android 5.1.1直接下载直接下载直接下载直接下载直接下载
Mi5 Android 6.0.1直接下载ActionSheet提示打开App,关闭ActionSheet后开始下载直接下载直接下载直接下载
6P Android 7.0.0选择下载器下载ActionSheet提示打开App,关闭ActionSheet后开始下载直接下载直接下载直接下载

参考资料

  1. 移动DeepLink的前生今世;
  2. DEEP-LINK.JS
  3. DEEPLINK 与增长黑客:低成本实现用户增长的方法论
  4. Deep Link是什么
  5. How to Deep Link to Your Mobile App from Your Website
  6. Deferred Deep Linking in iOS
  7. 支持IOS9+和Android5+,JS打开APP的解决方案
  8. 怎么在网页中打开你的app
  9. IOS9通用链接(universal link)



http://testudy.cc/tech/2016/11/25/applink.html