网页打开APP

本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2021-07-03

『转载』

伪协议

这种方式需要App先注册伪协议,然后在浏览器等应用中加载伪协议链接便可以打开。这种方式几乎所有操作系统都支持。

每一个本地应用(App)都可以向操作系统申请注册一个独一无二的伪协议,当有人尝试加载该伪协议链接时操作系统就会打开注册了该伪协议的本地应用。

当用户点击伪协议链接时,浏览器会询问操作系统,是否有本地App注册了此协议,如果有就打开App,如果没有就弹窗提示App未安装,页面没有变化。

通用链接(仅iOS9)

伪协议在iOS 9.0以后会弹出一个确认弹窗,而在iOS 9.0之后的版本提供了通用链接来解决这一问题。

当用户点击通用链接时,浏览器会询问操作系统,是否已安装App。

如果安装了,则进行签名校验,校验通过则打开App,否则就直接展示通用链接页面。

如果没有安装,则直接展示通用链接页面。

但是这种方法不能兼容QQ浏览器。

应用宝微下载

上面两种方案组合起来在绝大多数情况下都能正常工作,但在微信中这两种方式都无法打开App,好在有应用宝微下载可以作为一个可选方案来处理此问题。

应用宝微下载需要注册腾讯应用宝账号,并按照腾讯的文档指引进行配置集成。

当用户点击应用宝微下载链接时,浏览器会正常跳转到应用宝微下载页面。

该页面会检查是否安装了应用宝。

如果安装了就打开应用宝App,然后在应用宝App检查是否安装目标App,安装了就直接打开,未安装就下载目标App

如果没有安装应用宝,则弹出安全下载 / 普通下载,点击之后直接下载应用宝。

梳理流程

判断平台

是ios 还是 Android

ios :

  • 如果是QQ浏览器,直接采用应用宝微下载
  • 如果不是,判断版本是否在9.0以上,如果是,使用通用协议,如果不是使用伪协议。

Android:

  • 如果是微信,直接采用应用宝微下载
  • 如果不是微信,直接使用伪协议。

其他平台:

  • 直接使用伪协议

使用伪协议的情况,有两种,成功打开了(本地有安装)就展示App,没有打开(本地未安装)就跳转到App下载页。因为在使用伪协议打开App的时候如果没有安装App则页面提示,不做其他操作的。

代码

// app-launcher.js

class AppLauncher {
  // 获取浏览器UA
  Browser = this.getBrowser();

  // 默认参数
  constructor(config = {
    // App在苹果应用商店发布的地址
    appStoreLink: '',
    // App在应用宝推广的链接
    appBabyLink: '',
    // 直接打开App使用的协议
    schema: '',
    // iOS 9以上,使用通用链接
    universalLink: ''
  }) {
    this.config = config;
  }

  // 获取浏览器ua
  getBrowser() {
    var UA = navigator.userAgent || '';

    var isAndroid = function () {
      return UA.match(/Android/i) ? true : false;
    }();

    var isQQ = function () {
      return /(iPad|iPhone|iPod).*? (IPad)?QQ\/([\d.]+)/.test(UA) || /\bV1_AND_SQI?_([\d.]+)(.*? QQ\/([\d.]+))?/.test(UA);
    }();

    var isQQBrowser = function () {
      return /MQQBrowser/i.test(UA);
    }();

    var isIOS = function () {
      return UA.match(/iPhone|iPad|iPod/i) ? true : false;
    }();

    var isSafari = function () {
      return /iPhone|iPad|iPod\/([\w.]+).*(safari).*/i.test(UA);
    }();

    var isWx = function () {
      return UA.match(/micromessenger/i) ? true : false;
    }();

    var isWb = function () {
      return UA.match(/weibo/i) ? true : false;
    }();

    var isAndroidChrome = function () {
      return (UA.match(/Chrome\/([\d.]+)/) || UA.match(/CriOS\/([\d.]+)/)) && isAndroid && !isQQ;
    }();

    var isQZ = function () {
      return UA.indexOf('Qzone/') !== -1;
    }();
    
    return {
      isAndroid: isAndroid,
      isIOS: isIOS,
      isSafari: isSafari,
      isQQ: isQQ,
      isQQBrowser: isQQBrowser,
      isWb: isWb,
      isWx: isWx,
      isQZ: isQZ,
      isAndroidChrome: isAndroidChrome
    };
  }

  //  获取ios版本号
  getIOSVersion() {
    const ver = navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/);
    const version = parseInt(ver[1], 10);
    return version;
  }

  // 打开App主逻辑
  launch() {
    var browser = this.Browser;
    var config = this.config;

    if (browser.isAndroid) {
      // Android上的微信,直接跳转应用宝
      if (browser.isWx) {
        this.go(config.yyb);
      } else {
      // 其他使用伪协议
        this._openApp();
      }
    } else if (browser.isIOS) {

      var version = this.getIOSVersion();
      
      if (browser.isQQBrowser) {
        // iOS上的QQ浏览器,直接跳转应用宝
        this.go(config.yyb);
      } else if (version >= 9) {
        // iOS9以上,使用通用链接打开
        this.go(config.universalLink);
      } else {
        // iOS9以下尝试直接使用伪协议
        this._openApp();
      }
    } else {
      // 其他平台使用 伪协议
      this._openApp();
    }
  }

  // 跳转
  go(url) {
    location.href = url;
  }

  // 使用伪协议的封装
  _openApp() {
    var _this = this;
    var browser = this.Browser;
    var config = this.config; 

    // 使用scheme唤起
    this.tryCallApp(config.schema);
    // 检查伪协议是否成功唤起了App
    this.checkOpen(function (isSuccess) {
      if (isSuccess) {
        // 如果成功打开,则不继续跳转
        return;
      } // 打开失败之后


      if (browser.isIOS) {
        // iOS跳转App Store
        _this.go(config.appStore);
      } else {
        // 其它设备跳转应用宝
        _this.go(config.yyb);
      }
    });
  }

  // 使用伪协议唤起App
  tryCallApp(scheme) {
    var aLink = document.createElement('a');
    aLink.href = scheme;
    document.body.appendChild(aLink);
    aLink.addEventListener('click', function (e) {
      e.stopPropagation();
    });
    aLink.click();
  }

  // 检查伪协议是否成功唤起了App
  checkOpen(callback) {
    var inter = null;
    var statue = false;
    var count = 0;
    inter = window.setInterval(function () {
      count++;
      statue = document.hidden || document.webkitHidden;

      if (statue || count > 40) {
        callback(statue);
        clearInterval(inter);
      }
    }, 50);
  }

}

使用

import { AppLauncher } from './app-launcher.js';
 
new AppLauncher({
  // App在苹果应用商店发布的地址
  appStoreLink: '...',
  // App在应用宝推广的链接
  appBabyLink: '...',
  // 直接打开App使用的协议
  schema: '...',
  // iOS 9以上,使用通用链接
  universalLink: '...'
}).launch();