# 目录

1 概述

1.1 使用步骤

1.2 使用说明

2 开放标签

2.1 跳转小程序:wx-open-launch-weapp

2.2 跳转App:wx-open-launch-app

2.3 服务号订阅通知:wx-open-subscribe

2.4 音频播放:wx-open-audio

3 在Vue、React等框架中使用

4 附录-所有开放标签列表

# 概述

微信开放标签是微信公众平台面向网页开发者提供的扩展标签集合。通过使用微信开放标签,网页开发者可安全便捷地使用微信或系统的能力,为微信用户提供更优质的网页体验。

此文档面向网页开发者,介绍微信开放标签如何使用及相关注意事项。需要注意的是,微信开放标签有最低的微信版本要求、最低的系统版本要求,以及最低的JS接口文件版本要求。

  • 微信版本要求为:7.0.12及以上
  • 系统版本要求为:iOS 10.3及以上、Android 5.0及以上
  • JS接口文件:1.6.0以上 (例如:http://res.wx.qq.com/open/js/jweixin-1.6.0.js)

对于符合微信或系统最低版本要求但仍无法使用微信开放标签的场景,将会在下方使用步骤中的wx.config权限验证成功后触发WeixinOpenTagsError事件告知开发者。仅无法使用微信开发标签,JS-SDK其他功能不受影响。可通过如下方法监听并进行回退兼容:

document.addEventListener('WeixinOpenTagsError', function (e) {
  console.error(e.detail.errMsg); // 无法使用开放标签的错误原因,需回退兼容。仅无法使用开放标签,JS-SDK其他功能不受影响
});

根据目前已知的错误场景,回退兼容建议如下:

  1. iOS15底层WebKit接口发生变更,微信版本8.0.8以下(不包括8.0.8)无法使用开放标签,可引导用户升级最新版本微信;
  2. 开放标签依赖Web Components方案,极少部分Android系统可能由于版本太低而不支持,可引导用户升级系统固件。

# 使用步骤

微信开放标签使用步骤与微信JS-SDK类似,也需要引入JS文件等步骤。如果是公众号身份的网页,需要绑定安全域名,如果是使用小程序云开发静态网站托管的小程序网页,则不需绑定安全域名即可直接使用(即跳过下面"步骤一:绑定安全域名")。

# 1. 绑定域名

登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。

# 2. 引入JS文件

在需要调用JS接口的页面引入如下JS文件:http://res.wx.qq.com/open/js/jweixin-1.6.0.js (支持https)

如需进一步提升服务稳定性,当上述资源不可访问时,可改访问:http://res2.wx.qq.com/open/js/jweixin-1.6.0.js (支持https)

备注:支持使用 AMD/CMD 标准模块加载方法加载。

# 3. 通过config接口注入权限验证配置并申请所需开放标签

与使用JS-SDK配置方式相同,所有需要使用开放标签的页面必须先注入配置信息,并通过openTagList字段申请所需要的开放标签,否则将无法使用(同一个url仅需调用一次)。开放标签的申请和JS接口的申请相互独立,因此是可以同时申请的。

wx.config({
  debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印
  appId: '', // 必填,公众号的唯一标识
  timestamp: , // 必填,生成签名的时间戳
  nonceStr: '', // 必填,生成签名的随机串
  signature: '',// 必填,签名
  jsApiList: [], // 必填,需要使用的JS接口列表
  openTagList: [] // 可选,需要使用的开放标签列表,例如['wx-open-launch-app']
});

签名算法见JS-SDK说明文档的附录,所有开放标签列表见文末的附录1。

# 4. 通过ready接口处理成功验证

wx.ready(function () {
  // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中
});

# 5. 通过error接口处理失败验证

wx.error(function (res) {
  // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名
});

# 使用说明

所有开放标签都能像普通的HTML标签一样在页面中直接使用,不需要再进行额外的处理。

如果所使用的标签允许提供插槽,由于插槽中模版的样式是和页面隔离的,因此需要注意在插槽中定义模版的样式。插槽模版及样式均需要通过<script type="text/wxtag-template"></script>进行包裹。另外,对于具名插槽还需要通过slot属性声明插槽名称,下文标签插槽中的default插槽为默认插槽,可不声明插槽名称。

对于标签事件,均可通过event.detail获得详细信息。如果无特殊说明,下文标签事件说明中的返回值均指代event.detail中的内容。

另外,需要注意以下几点:

  1. 页面中与布局和定位相关的样式,如position: fixed; top -100;等,尽量不要写在插槽模版的节点中,请声明在标签或其父节点上;
  2. 对于有CSP要求的页面,需要添加白名单frame-src https://*.qq.com webcompt:,才能在页面中正常使用开放标签。

# 开放标签

# 跳转小程序:wx-open-launch-weapp

用于页面中提供一个可跳转指定小程序的按钮。使用此标签后,用户需在网页内点击标签按钮方可跳转小程序。H5通过开放标签打开小程序的场景值为1167。

# 开放对象

  1. 已认证的服务号,服务号绑定“JS接口安全域名”下的网页可使用此标签跳转任意合法合规的小程序。
  2. 已认证的非个人主体的小程序,使用小程序云开发的静态网站托管绑定的域名下的网页,可以使用此标签跳转任意合法合规的小程序。

# 错误提示

若跳转时出现以下页面,表示网页绑定的服务号或小程序无权限,请检查是否符合上述开放对象条件。

无权限提示

# 属性

名称 必填 默认值 备注
appid 所需跳转的小程序appid,即小程序对应的以wx开头的id
username 所需跳转的小程序原始id,即小程序对应的以gh_开头的id(跳转时,有appid会优先使用appid,没有appid才会使用username)
path 所需跳转的小程序内页面路径及参数
env-version release 所需跳转的小程序版本,合法值为:正式版release、开发版develop、体验版trial(支持的微信版本:iOS 8.0.18及以上、Android 8.0.19及以上)
extra-data 以JSON格式字符串向所需跳转的小程序传递数据。小程序可在App.onLaunchApp.onShow等中获取;小游戏可在wx.onAppShowwx.getLaunchOptionsSync等中获取(支持的微信版本:iOS 8.0.18及以上、Android 8.0.19及以上)

# 插槽

名称 必填 默认值 备注
default 跳转按钮模版及样式

# 事件

名称 冒泡 返回值 备注
ready 标签初始化完毕,可以进行点击操作
launch { appId: string, userName: string, path: string } 用户点击跳转按钮并对确认弹窗进行操作后触发
error { errMsg: string, appId: string, userName: string, path: string } 用户点击跳转按钮后出现错误

备注:error事件返回值errMsg说明如下。

errMsg 说明
"launch:fail" 跳转失败

# 用例

<wx-open-launch-weapp
  id="launch-btn"
  appid="wx12345678"
  path="pages/home/index?user=123&action=abc"
>
  <script type="text/wxtag-template">
    <style>.btn { padding: 12px }</style>
    <button class="btn">打开小程序</button>
  </script>
</wx-open-launch-weapp>
<script>
  var btn = document.getElementById('launch-btn');
  btn.addEventListener('launch', function (e) {
    console.log('success');
  });
  btn.addEventListener('error', function (e) {
    console.log('fail', e.detail);
  });
</script>

# 跳转APP:wx-open-launch-app

用于页面中提供一个可跳转指定App的按钮。注意:Android平台通过开放标签跳转App,App必须接入微信OpenSDK,详细参见文档《Android微信OpenSDK接入指南》

补充说明:1、必须真机才能渲染该标签;2、文字链无法拉起该标签

# 开放对象

此功能仅开放给已认证的服务号,服务号绑定“JS接口安全域名”下的网页可使用此标签跳转满足一定条件的App。在使用该标签之前,首先需要前往微信开放平台管理中心-公众账号或小程序详情-接口信息-网页跳转移动应用-关联设置中绑定所需要跳转的App。详细配置规则参考文档《微信内网页跳转APP功能》

# 属性

名称 必填 默认值 备注
appid 所需跳转的移动应用的AppID
extinfo 跳转所需额外信息

备注:对于extinfo属性,用于携带额外信息,格式自定义,由跳转的App自⾏解析处理。对应iOS微信OpenSDK中的messageExt字段(LaunchFromWXReq.message.messageExt),或对应Android微信OpenSDK中的messageExt字段(ShowMessageFromWX.Req.message.messageExt),详细参见文档《App获取开放标签<wx-open-launch-app>中的extinfo数据》

# 插槽

名称 必填 默认值 备注
default 跳转按钮模版及样式

# 事件

名称 冒泡 返回值 备注
ready 标签初始化完毕,可以进行点击操作
launch { appId: string, extInfo: string } 用户点击跳转按钮并对确认弹窗进行操作后触发
error { errMsg: string, appId: string, extInfo: string } 用户点击跳转按钮后出现错误

备注:error事件返回值errMsg说明如下。

errMsg 说明
"launch:fail" 当前场景不支持跳转,或Android上该应用未安装,或iOS上用户在弹窗上点击确认但该应⽤未安装
"launch:fail_check fail" 校验App跳转权限失败,请确认是否正确绑定AppID

# 用例

<wx-open-launch-app
  id="launch-btn"
  appid="your-appid"
  extinfo="your-extinfo"
>
  <script type="text/wxtag-template">
    <style>.btn { padding: 12px }</style>
    <button class="btn">App内查看</button>
  </script>
</wx-open-launch-app>
<script>
  var btn = document.getElementById('launch-btn');
  btn.addEventListener('launch', function (e) {
    console.log('success');
  });
  btn.addEventListener('error', function (e) {
    console.log('fail', e.detail);
  });
</script>

# 服务号订阅通知按钮:wx-open-subscribe

服务号提供在网页端设置订阅通知的能力。调起客户端服务号订阅通知界面,返回用户订阅通知的操作结果。

开放对象:已认证的服务号。服务号绑定“JS接口安全域名”下的网页可使用此标签调起订阅。

具体表现如图:

# 注意事项

  • 开放标签有最低的微信版本和系统版本要求,无法渲染出订阅按钮时,开发者需自行做低版本处理。
  • 一次性模板id和永久模板id不可同时使用。
  • 开发者工具里支持清除授权和模拟订阅,目前为假数据模拟,实际效果请在真机调试。

# 属性

名称 必填 默认值 备注
template 模版id,多个模版id以逗号隔开

# 插槽

名称 必填 默认值 备注
default 订阅按钮模版及样式
style 用于集中定义default插槽所需用到的样式

# 事件

名称 冒泡 返回值 备注
success {errMsg: 'subscribe:ok', subscribeDetails: string} 订阅按钮操作成功事件
error {errMsg: string, errCode: string} 订阅按钮操作失败事件
# success事件属性说明
属性 类型 说明
errMsg string 按钮操作成功时errMsg值为'subscribe:ok'
subscribeDetails string [TEMPLATE_ID]是动态的键,即模版id,值包括:'accept'、'reject'、'cancel'、'filter','accept'表示用户同意订阅该条id对应的模版消息,'reject'表示用户拒绝订阅该条id对应的模版消息,'cancel'表示用户取消订阅该条id对应的模版消息,'filter'表示该模版应该标题同名被后台过滤。例如:{ errMsg: "subscribe:ok", subscribeDetails: "{"TenvU22BA1jCp4YHfYEpRuESXYReQyDuhs4vbdWA99I":"{\"status\":\"accept\"}"}"表示用户同意订阅TenvU22BA1jCp4YHfYEpRuESXYReQyDuhs4vbdWA99I这条消息。
# error事件属性说明
属性 类型 说明
errMsg string 订阅按钮调用失败错误信息
errCode string 订阅按钮调用失败错误码

备注:error事件返回值errMsgerrCode说明如下。

errCode errMsg 说明
10001 template can't be empty 参数传空了
10002 Request list fail 网络问题,请求消息列表失败
10003 Request subscribe fail 网络问题,订阅请求发送失败
10004 Invalid template id 参数类型错误
20001 No template data return, verify the template id exist 没有模板数据,一般是模板 ID 不存在 或者和模板类型不对应 导致的
20002 Templates type must be same 模板消息类型 既有一次性的又有永久的
20003 Templates count out of max bounds 模板消息数量超过上限
20004 The main switch is switched off 用户关闭了主开关,无法进行订阅
20005 This mini program was banned from subscribing messages 服务号被封禁

# 用例

<wx-open-subscribe template="TenvU22BA1jCp4YHfYEpRuESXYReQyDuhs4vbdWA99I" id="subscribe-btn">
  <script type="text/wxtag-template" slot="style">
    <style>
      .subscribe-btn {
        color: #fff;
        background-color: #07c160;
      }
    </style>
  </script>
  <script type="text/wxtag-template">
    <button class="subscribe-btn">
      一次性模版消息订阅              
    </button>
  </script>
</wx-open-subscribe>
<script>
var btn = document.getElementById('subscribe-btn');
btn.addEventListener('success', function (e) {            
  console.log('success', e.detail);
});   
btn.addEventListener('error',function (e) {             
  console.log('fail', e.detail);
});
</script>

# 音频播放:wx-open-audio

扩展音频标签,用于接入微信浮窗播放器。

# 开放对象

此功能仅开放给已认证的服务号,服务号绑定“JS接口安全域名”下的网页可使用此标签进行浮窗音频播放。

# 属性

名称 必填 默认值 备注
src - 设置音频播放链接
title "unknown" 设置音频名称
episode "unknown" 设置专辑名称
singer "unknown" 设置歌手名称
cover "" 设置专辑封面
<wx-open-audio
  title="别找我麻烦"
  singer="蔡健雅"
  episode="说到爱"
  src="http://xxx.xxx.com/.mp3"
  cover="http://xxx.xxx.com/xxx.jpg"
></wx-open-audio>

# 插槽

该标签的视图可以理解成是一个播放按钮,因此具有以下插槽:

名称 必填 默认值 备注
default - 播放按钮默认视图,用于音频未在播放状态时显示,如果没有,默认显示微信音频播放按钮(40px*40px)
playing - 用于音频在播放状态时显示,如果没有,默认显示default插槽视图或者微信音频播放按钮
style 用于集中定义default插槽和playing插槽所需用到的样式
<wx-open-audio src="http://xxx.xxx.com/.mp3">
  <script type="text/wxtag-template">
    <div class="playBackground"></div>
  </script>
  <script type="text/wxtag-template" slot="playing">
    <div class="pauseBackground"></div>
  </script>
  <script type="text/wxtag-template" slot="style">
    <style>
      .playBackground {
        width: 60px;
        height: 64px;
        background: url("xxx");
        background-repeat: no-repeat;
        background-size: 100%;
        cursor: pointer;
      }
      .pauseBackground {
        width: 60px;
        height: 64px;
        background: url("xxx");
        background-repeat: no-repeat;
        background-size: 100%;
        cursor: pointer;
      }
    </style>
  </script>
</wx-open-audio>

# 实例属性

名称 备注
src 获取和设置音频播放链接
title 获取和设置音频名称
episode 获取和设置专辑名称
singer 获取和设置歌手名称
cover 获取和设置专辑封面
ended 获取音频目前是否结束播放
paused 获取音频目前是否暂停播放
duration 获取音频长度,单位秒
readyState 获取音频当前就绪状态,含义对齐W3C标准,但只有1/2/4三种状态
currentTime 获取和设置播放进度,单位秒(*音频正在后台播放时或正在后台暂停时设置才生效)
playbackRate 微信7.0.15及以上支持获取和设置播放速率,范围0~2 (*音频正在后台播放时设置才生效)
error 获取音频相关错误信息

备注:error属性说明如下。

错误 说明
"play:fail" 调用play方法失败
"pause:fail" 调用pause方法失败
"seek:fail" 设置currentTime失败
"ratechange:fail" 设置playbackRate失败
// <wx-open-audio id="audio"></wx-open-audio>
const audio = document.getElementById('audio');
console.log(audio.src);
console.log(audio.title);
console.log(audio.episode);
console.log(audio.singer);
console.log(audio.cover);
console.log(audio.error);
console.log(audio.ended);
console.log(audio.paused);
console.log(audio.duration);
console.log(audio.readyState);
console.log(audio.currentTime);
console.log(audio.playbackRate);
audio.src = 'http://xxx.xxx.com/.mp3'
audio.title = '别找我麻烦'
audio.episode = '说到爱'
audio.singer = '蔡健雅'
audio.cover = 'http://xxx.xxx.com/xxx.jpg'
audio.currentTime = 100;
audio.playbackRate = 1.0

# 实例方法

名称 备注
load 重新加载音频
play 播放音频,出于用户体验考虑,只有在用户首次点击触发播放后,才允许调用
pause 暂停播放音频
// <wx-open-audio id="audio"></wx-open-audio>
const audio = document.getElementById('audio');
audio.load();
audio.play();
audio.pause();

# 事件

名称 冒泡 可取消 备注
ready 音频标签初始化完成
// <wx-open-audio id="audio"></wx-open-audio>
const audio = document.getElementById('audio');
audio.addEventListener('ready', function (event) {
  // 标签初始化完成
});
名称 冒泡 可取消 备注
durationchange/loadedmetadata 拉取音频meta信息成功
// <wx-open-audio id="audio"></wx-open-audio>
const audio = document.getElementById('audio');
audio.addEventListener('durationchange', function (event) {
  // 获取到音频长度
  const state = event.detail;
  console.log(state.duration);
});
audio.addEventListener('loadedmetadata', function (event) {
  // 音频meta信息只有长度,因此loadedmetadata会接着马上触发
  const state = event.detail;
  console.log(state.duration);
});
名称 冒泡 可取消 备注
canplay 音频可以播放
// <wx-open-audio id="audio"></wx-open-audio>
const audio = document.getElementById('audio');
audio.addEventListener('canplay', function (event) {
  // 可随时播放
  const state = event.detail;
  console.log(state.duration);
});
名称 冒泡 可取消 备注
play 音频开始播放
// <wx-open-audio id="audio"></wx-open-audio>
const audio = document.getElementById('audio');
audio.addEventListener('play', function (event) {
  // 开始播放
});
名称 冒泡 可取消 备注
pause 音频停止播放
// <wx-open-audio id="audio"></wx-open-audio>
const audio = document.getElementById('audio');
audio.addEventListener('pause', function (event) {
  // 停止播放
});
名称 冒泡 可取消 备注
timeupdate 播放时,音频相关信息同步
// <wx-open-audio id="audio"></wx-open-audio>
const audio = document.getElementById('audio');
audio.addEventListener('timeupdate', function (event) {
  const state = event.detail;
  console.log(state.src);         // 当前音频来源
  console.log(state.title);       // 当前音频标题
  console.log(state.episode);     // 当前专辑名称
  console.log(state.singer);      // 当前歌手名称
  console.log(state.cover);       // 当前专辑封面
  console.log(state.playState);   // 播放状态,'playing' | 'pause' | 'seeked'
  console.log(state.paused);      // 是否暂停
  console.log(state.buffered);    // 已缓冲位置,单位秒
  console.log(state.currentTime); // 当前播放位置,单位秒
});
名称 冒泡 可取消 备注
seeked 设置currentTime以后,音频播放位置变更完成
// <wx-open-audio id="audio"></wx-open-audio>
const audio = document.getElementById('audio');
audio.addEventListener('seeked', function (event) {
  // 播放位置变更完成
  const state = event.detail;
  console.log(state.currentTime); // 变更后播放位置,单位秒
});
名称 冒泡 可取消 备注
ratechange 设置playbackRate以后,音频播放速率变更完成(微信7.0.15及以上支持)
// <wx-open-audio id="audio"></wx-open-audio>
const audio = document.getElementById('audio');
audio.addEventListener('ratechange', function (event) {
  // 播放位置变更完成
  const state = event.detail;
  console.log(state.playbackRate); // 变更后播放速率
});
名称 冒泡 可取消 备注
ended 音频播放结束
// <wx-open-audio id="audio"></wx-open-audio>
const audio = document.getElementById('audio');
audio.addEventListener('ended', function (event) {
  // 播放结束
});
名称 冒泡 可取消 备注
error 音频加载、播放或操作过程中发生错误
// <wx-open-audio id="audio"></wx-open-audio>
const audio = document.getElementById('audio');
audio.addEventListener('error', function (event) {
  // 发生错误
  const error = event.detail;
  console.log(error.errMsg);
  // 1. play:fail(调用play方法失败)
  // 2. pause:fail(调用pause方法失败)
  // 3. seek:fail(设置currentTime失败)
  // 4. ratechange:fail(设置playbackRate失败)
});

# 在Vue、React等框架中使用

插槽模版的内容和样式与主页面相互隔离,使用数据驱动的方式去更改插槽模版中的内容和样式将不会得到更新。

# 在Vue中使用

开放标签属于自定义标签,Vue会给予未知标签的警告,可通过配置Vue.config.ignoredElements来忽略Vue对开放标签的检查。

<wx-open-audio
  :title="title"
  src="http://xxx.xxx.com/.mp3"
  @canplay="canplay"
  @pause="pause"
  @seeked="seeked"
>
  <script type="text/wxtag-template">
    <button>播放</button>
  </script>
</wx-open-audio>

# 在React中使用

因为不兼容合成事件,所以需要绑定原生事件。

function Audio() {
  const audio = useRef(null);
  useEffect(() => {
    const canplay = () => {};
    const pause = () => {};
    const seeked = () => {};
    audio.current.addEventListener('canplay', canplay);
    audio.current.addEventListener('pause', pause);
    audio.current.addEventListener('seeked', seeked);
    return () => {
      audio.current.removeEventListener('canplay', canplay);
      audio.current.removeEventListener('pause', pause);
      audio.current.removeEventListener('seeked', seeked);
    };
  }, []);
  return (
    <wx-open-audio
      ref={audio}
      title="别找我麻烦"
      src="http://xxx.xxx.com/.mp3"
    >
      <script type="text/wxtag-template">
        <button>播放</button>
      </script>
    </wx-open-audio>
  );
}

# 附录-所有开放标签列表

<wx-open-launch-weapp>

<wx-open-launch-app>

<wx-open-subscribe>

<wx-open-audio>