微信内H5页面唤醒App

首先,简述一下这个需求的背景,产品希望能够让用户在微信内,打开一个h5页面,然后就能唤醒公司中维护的app,这个是为了能够更好的引流。

唤醒app的三种方案

IOS系统-Universal Link(通用链接)

Universal Links可以通过配置指定域名路径直接唤醒APP,一步到位

具体配置看这篇文章

https://juejin.cn/post/6937614343840202766

遇到的问题:

apple-app-site-association文件放在app域名(假设: https://my.app.com/)下

json 复制代码
{
    "applinks": {
        "apps": [],
        "details": [
            {
                "appID": "******",
                "paths": [ "/abc/*" ]
            },
        ]
    }
}

使用Universal Link其实就是跳转到一个页面(中间页),地址:https://my.app.com/abc/index.html

根据上面配置,这个地址是已经固定了的,这需要跟app域名保持一致,并且在paths配置里面的目录下,为了能够获取到apple-app-site-association文件

ts 复制代码
const universalLink = 'https://my.app.com/abc/index.html?redirectUrl=' + window.location.href
location.replace(universalLink);

如果未下载app,则会跳转失败,在中间页中处理,跳转失败后再返回到当前页面。

html 复制代码
<script>
    function getQueryStringArgs(url, opt) {
      const { decode = true, multiple = false } = opt || {};
      const args = {};
      if (!(typeof url === 'string' && url.includes('?'))) return args;

      const arr = url.split('?');
      const qs = arr.length === 2 ? arr[1] : '';
      if (!(typeof qs === 'string' && qs.length)) return args;

      const items = qs.split('&');
      for (let i = 0; i < items.length; i++) {
        const meta = items[i];
        if (!(typeof meta === 'string' && meta.includes('='))) continue;
        const item = meta.split('=');
        const key = decode ? decodeURIComponent(item[0]) : item[0];
        const value = decode ? decodeURIComponent(item[1]) : item[1];
        if (Object.prototype.hasOwnProperty.call(args, key) && multiple) {
          const temp = args[key];
          args[key] = Array.isArray(temp) ? [...temp, value] : [temp, value];
        } else {
          args[key] = value;
        }
      }
      return args;
    }
    const { redirectUrl } = getQueryStringArgs(location.href)
    if (typeof redirectUrl === 'string' && redirectUrl) {
      location.replace(redirectUrl + '?callType=universalLink') // 处理唤醒app失败场景
    }
  </script>

上面这段逻辑如果直接放在html中,最好先手动转一下ES5语法,然后压缩一下,这样兼容性好,上面这样展示,是为了可读性好。

总结:

ios系统使用Universal Link在微信和浏览器内都能够正常的唤醒App,且兼容性比较好。但是需要注意中间页域名需要跟app域名保持一致;唤醒app的h5链接域名不能跟中间页域名一致。

直接扫二维码进入另一个页面,需要进行点击操作才能跳转,IOS不允许打开页面立刻就跳转。

URL-Schemes

URL scheme是App提供给外部的可以直接操作App的规则。

  • 比如微信提供了打开扫一扫的URL scheme。weixin://dl/scan
  • 比如支付宝提供了转账的URL scheme。alipayqr://platformapi/startapp?saId=20000116
  • 比如知乎提供了打开回答页面的URL scheme。zhihu://answers/{id}

如何找到某个app的URL Scheme呢?可以看下面这篇文章

https://zhuanlan.zhihu.com/p/53439246

安卓唤醒app呢,就是使用这种方式

比如:安卓开发提供的是

那跳转的链接是什么样的呢?

ts 复制代码
const schemeURL = 'myapp://www.myapp.apk'
window.href = schemeURL;

如何判断唤醒失败呢?

没有什么好办法来判断,后面只能触发了唤醒操作之后,监听页面几秒之后是否隐藏来判断,目前默认是2秒

ts 复制代码
export function getSupportedProperty() {
  let hidden;
  let visibilityChange;

  if (typeof document.hidden !== 'undefined') {
    // Opera 12.10 and Firefox 18 and later support
    hidden = 'hidden';
    visibilityChange = 'visibilitychange';
    // @ts-ignore
  } else if (typeof document.msHidden !== 'undefined') {
    hidden = 'msHidden';
    visibilityChange = 'msvisibilitychange';
    // @ts-ignore
  } else if (typeof document.webkitHidden !== 'undefined') {
    hidden = 'webkitHidden';
    visibilityChange = 'webkitvisibilitychange';
  }

  return {
    hidden,
    visibilityChange,
  };
}
/**
 * 判断页面是否隐藏(进入后台)
 */
export function isPageHidden() {
  const ob = getSupportedProperty();
  const hidden = ob?.hidden;
  if (typeof hidden === 'undefined') return false;
  // @ts-ignore
  return document[hidden];
}
/**
 * 检测是否唤端成功
 * 在唤起执行后,当前页面调用此方法根据页面隐藏变化检测是否唤醒成功
 * @param {number} timeout 定时时间,默认2秒
 * @return {Object} Promise对象
 */
export function checkOpen(timeout = 2000) {
  return new Promise((resolve, reject) => {
    const ob = getSupportedProperty();
    const visibilityChange = ob?.visibilityChange;

    const check = () => {
      const pageHidden = isPageHidden();
      if (pageHidden) {
        resolve(); // 页面被隐藏,说明唤醒成功
      } else {
        reject(new Error('唤醒超时'));
      }
    };
    const timer = setTimeout(() => {
      check();
    }, timeout);

    const fn = () => {
      if (typeof visibilityChange !== 'undefined') {
        document.removeEventListener(visibilityChange, fn);
      } else {
        window.removeEventListener('pagehide', fn);
      }
      check(); // 唤醒执行后,立马触发页面隐藏变化,可检测是否唤醒成功
      clearTimeout(timer); // 未到达指定时间,页面隐藏变化,清除定时器
    };

    if (typeof visibilityChange !== 'undefined') {
      document.addEventListener(visibilityChange, fn);
    } else {
      window.addEventListener('pagehide', fn);
    }
  });
}

总结:

安卓使用URL Schemes在微信中是不能跳转的,在浏览器中是能够正常拉起。

微信开放标签

由于在微信环境内,所以可以使用微信提供的能力来唤醒app,微信内禁止使用URL Schemes唤醒app,其实就是微信的一种保护机制。

微信文档:

https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_H5_Launch_APP.html

如上图,使用这个功能,有很多限制,而且需要配置,但是为了安卓用户成功引流,产品还是要求使用这个功能。

微信配置

1.关联App-微信开发平台

微信开发平台配置关联App,关联App需要appId,已经有App的域名

微信开发平台地址: https://open.weixin.qq.com/

2.H5页面域名配置-微信公众平台

JS安全域名需要配置当前h5页面的域名

微信公众号地址: https://mp.weixin.qq.com/

3.初始化微信SDK,需要获取签名

微信开发SDK文档

https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html

这需要后端开发接口, 去获取签名

使用微信开放标签说明:

https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_Open_Tag.html

ts 复制代码
async getWxSignatureData() {
      const url = window.location.href.split('#')[0];
      const res = await getJsapiSignParamers(url);
      const { appId, signature, timestamp, nonceStr } = res.data;
      wx.config({
        debug: false,
        appId: appId,
        timestamp: timestamp,
        nonceStr: nonceStr,
        signature: signature,
        jsApiList: ['showOptionMenu'], // 必填,故使用一个非实际使用的api用于填充
        openTagList: ['wx-open-launch-app'], // 可选,需要使用的开放标签列表
      });

      wx.ready(() => {
        console.info('wx sdk ready');
        console.info('调用接口初始化wx sdk 成功');
        this.initWxSDKStatus = 'success';
      });

      wx.error(res => {
        console.error('调用接口初始化wx sdk 失败', res);
        this.initWxSDKStatus = 'fail';
      });
    },

接口返回的就是这样的数据结构

只有这样才能正常初始化微信的SDK,只有正常初始化SDK才能够使用微信开放标签的能力。

然后后端开发的时候要注意:签名需要后端配置白名单ip,文档说明如下:

https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html

安卓手机,如果出现唤醒app之后,打开了应用,但是并未成功唤起,那是因为Android应用有要求,需要安卓开发兼容一下就行了~

微信环境内场景

接下来就分析一下,在微信中有几种分享的场景:

1.微信好友之间链接分享

这种方式,使用微信标签是不能唤醒App的,除非是在关注公众号里面,这个公众号就是上面绑定了JS安全域名的公众号

这样点击这个链接就能正常用微信标签唤醒

2.微信好友之间卡片分享

这种点击打开是能够正常唤醒App的,而且不需要使用公众号,但是这种分享有限制,需要打开页面点击右上角分享给其他好友会带上卡片形式,如果在浏览器中就只是复制链接了,微信不会自动识别成卡片

而且这个分享其实就是微信的一个功能

https://developers.weixin.qq.com/minigame/dev/api/share/wx.onShareAppMessage.html

3.长按识别二维码识别H5链接

这种也能正常唤醒App,而且不需要关注公众号,也很方便,不需要将链接分享给其他人,只需要将唤醒App的链接做出二维码就行了。

全部流程图

相关推荐
轻口味2 分钟前
【每日学点鸿蒙知识】AVCodec、SmartPerf工具、web组件加载、监听键盘的显示隐藏、Asset Store Kit
前端·华为·harmonyos
alikami5 分钟前
【若依】用 post 请求传 json 格式的数据下载文件
前端·javascript·json
吃杠碰小鸡39 分钟前
lodash常用函数
前端·javascript
wmd131643067121 小时前
将微信配置信息存到数据库并进行调用
数据库·微信
emoji1111111 小时前
前端对页面数据进行缓存
开发语言·前端·javascript
泰伦闲鱼1 小时前
nestjs:GET REQUEST 缓存问题
服务器·前端·缓存·node.js·nestjs
m0_748250031 小时前
Web 第一次作业 初探html 使用VSCode工具开发
前端·html
一个处女座的程序猿O(∩_∩)O1 小时前
vue3 如何使用 mounted
前端·javascript·vue.js
m0_748235951 小时前
web复习(三)
前端
AiFlutter1 小时前
Flutter-底部分享弹窗(showModalBottomSheet)
java·前端·flutter