在部分场景下,用户在微信内访问网页时需要跳转到 APP 使用完整服务,为此我们提供了“微信开放标签”以满足微信内网页跳转到 APP 的需求。 微信内网页跳转 APP 功能已向全体开发者开放,当用户访问已认证服务号的 JS 接口安全域名时,可以通过“微信开放标签”打开符合条件的 APP 。
使用前需将「 JS 接口安全域名绑定的服务号」绑定在「移动应用的微信开放平台账号」下,并确保服务号与此开放平台账号同主体且均已认证。请前往?微信开放平台-管理中心-公众号详情-接口信息?设置域名与所需跳转的移动应用。
获得此设置入口的权限,需同时满足如下条件:
绑定域名的要求:
绑定移动应用的要求
绑定次数
绑定域名和移动应用后,即可在网页中使用“微信开放标签”跳转对应的移动应用。详见《微信开放标签说明文档》
?
- 服务号需要认证!且服务号和移动应用是同主体,或者有关联关系!
- 绑定JS接口安全域名:在微信号后台操作;绑定的域名是分享到微信端的网页的域名。
- 在微信开放平台的应用管理--公众号,关联需要跳转的App。
填写的信息包含:安全域名,移动应用名称,Appid;具体信息视实际情况哈!
以上是开发前的配置准备。
- 本人开发的思路:客户端页面在初始化时请求服务端中的接口,将网页的url及参数传给该接口(之前就因为网址写死导致一直没有调通),服务端获取到url进行签名算法,回传给客户端签名,时间戳等参数,客户端通过config接口进行权限验证,验证成功后,开放标签便生效。
微信开放标签是微信公众平台面向网页开发者提供的扩展标签集合。通过使用微信开放标签,网页开发者可安全便捷地使用微信或系统的能力,为微信用户提供更优质的网页体验。
此文档面向网页开发者,介绍微信开放标签如何使用及相关注意事项。需要注意的是,微信开放标签有最低的微信版本要求、最低的系统版本要求,以及最低的JS接口文件版本要求。
对于符合微信或系统最低版本要求但仍无法使用微信开放标签的场景,将会在下方使用步骤中的wx.config
权限验证成功后触发WeixinOpenTagsError
事件告知开发者。仅无法使用微信开发标签,JS-SDK其他功能不受影响。可通过如下方法监听并进行回退兼容:
document.addEventListener('WeixinOpenTagsError', function (e) {
console.error(e.detail.errMsg); // 无法使用开放标签的错误原因,需回退兼容。仅无法使用开放标签,JS-SDK其他功能不受影响
});
?用于页面中提供一个可跳转指定App的按钮。注意:Android平台通过开放标签跳转App,App必须接入微信OpenSDK,详细参见文档《Android微信OpenSDK接入指南》。
根据目前已知的错误场景,回退兼容建议如下:
微信开放标签使用步骤与微信JS-SDK类似,也需要引入JS文件等步骤。如果是公众号身份的网页,需要绑定安全域名,如果是使用小程序云开发静态网站托管的小程序网页,则不需绑定安全域名即可直接使用(即跳过下面"步骤一:绑定安全域名")。
登录微信公众平台进入“公众号设置”的“功能设置”里填写“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 标准模块加载方法加载。
与使用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。
wx.ready(function () {
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中
});
wx.error(function (res) {
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名
});
所有开放标签都能像普通的HTML标签一样在页面中直接使用,不需要再进行额外的处理。
如果所使用的标签允许提供插槽,由于插槽中模版的样式是和页面隔离的,因此需要注意在插槽中定义模版的样式。插槽模版及样式均需要通过<script type="text/wxtag-template"></script>
进行包裹。另外,对于具名插槽还需要通过slot
属性声明插槽名称,下文标签插槽中的default插槽为默认插槽,可不声明插槽名称。
对于标签事件,均可通过event.detail
获得详细信息。如果无特殊说明,下文标签事件说明中的返回值均指代event.detail
中的内容。
另外,需要注意以下几点:
position: fixed; top -100;
等,尽量不要写在插槽模版的节点中,请声明在标签或其父节点上;frame-src https://*.qq.com webcompt:
,才能在页面中正常使用开放标签。此功能仅开放给已认证的服务号,服务号绑定“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 |
安装
```shell
npm install jweixin-module --save
```
UMD?
```http
https://unpkg.com/jweixin-module/out/index.js
```
概述 | 微信开放文档微信开发者平台文档https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115
链接参数通过后台获取?
?debug: true,是否开启调试
jsApiList:为需要的api接口openTagList: ['wx-open-launch-app'] 我为需要的标签
// import jWeixin from 'weixin-js-sdk'
var jWeixin = require('jweixin-module')
import { wxSDKAuthority } from './api.js'
// 获取微信版本号
function getWeixinVersion() {
var version = "";
var weixinInfo = navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i);
if (weixinInfo && weixinInfo.length > 1) {
version = weixinInfo[1];
}
return version;
}
// 获取手机版本号
function getMobileOSVersion() {
var userAgent = navigator.userAgent;
// Check for iOS
if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
var match = userAgent.match(/OS (\d+)_(\d+)_?(\d+)?/);
if (match) {
return {
version: parseInt(match[1], 10),
device: "ios"
}
}
}
// Check for Android
if (/Android/.test(userAgent)) {
var match = userAgent.match(/Android\s([0-9\.]*)/);
if (match) {
return {
version: parseFloat(match[1]),
device: "Android"
}
}
}
// Return null if the OS version cannot be determined
return false;
}
/**
* 判断版本号
* @param {Object} version1
* @param {Object} version2
* 如果version1小于version2,则返回-1。
* 如果version1大于version2,则返回1。
* 如果version1等于version2,则返回0。
*/
function compareVersions(version1, version2) {
const v1 = version1.split('.');
const v2 = version2.split('.');
for (let i = 0; i < Math.max(v1.length, v2.length); i++) {
const num1 = parseInt(v1[i] || 0);
const num2 = parseInt(v2[i] || 0);
if (num1 < num2) {
return -1;
} else if (num1 > num2) {
return 1;
}
}
return 0;
}
// 判断设否
function checkSystemVersion() {
var mobileOSVersion = getMobileOSVersion();
if (mobileOSVersion.device === "ios" && compareVersions(mobileOSVersion.version.toString(), "10.3") >= 0) {
console.log('ios设备', mobileOSVersion, );
return true;
}
if (mobileOSVersion.device === "Android" && compareVersions(mobileOSVersion.version.toString(), "5.0") >= 0) {
console.log('安卓设备', mobileOSVersion);
return true;
}
if (!mobileOSVersion) {
console.log('未知设备', mobileOSVersion);
return true
}
console.log('不符合要求', mobileOSVersion);
return false;
}
export default {
initJssdk: function() {
return new Promise(async (resolve, reject) => {
const url = window.location.href.split("#")[0]
console.log(url);
var isWeixinVersion = compareVersions(getWeixinVersion(), '7.0.12') >= 0 //判断微信版本号
console.log(getWeixinVersion(), isWeixinVersion, '微信版本号');
if (isWeixinVersion && checkSystemVersion()) {
try {
let res = await wxSDKAuthority({ link: url });
jWeixin.config({
debug: true,
appId: res.appId,
timestamp: res.timestamp,
nonceStr: res.nonceStr,
signature: res.signature,
jsApiList: [],
openTagList: ['wx-open-launch-app']
});
jWeixin.ready(() => {
console.log('wx-sdk-ready');
resolve();
});
jWeixin.error(error => {
console.log('wx-sdk-error:', error);
reject(error);
});
} catch (error) {
console.log('未知异常:', error);
reject(error);
}
} else {
reject("微信版本或手机型号过低");
}
});
}
}
import integralTask from './utils/utils.js'
Vue.config.productionTip = false
Vue.prototype.$tool = integralTask
插槽模版的内容和样式与主页面相互隔离,使用数据驱动的方式去更改插槽模版中的内容和样式将不会得到更新。
- 页面中与布局和定位相关的样式,如
position: fixed; top -100;
等,尽量不要写在插槽模版的节点中,请声明在标签或其父节点上;- 对于有CSP要求的页面,需要添加白名单
frame-src https://*.qq.com webcompt:
,才能在页面中正常使用开放标签。
<template>
<view class="main">
<!-- IOS显示部分 -->
<wx-open-launch-app id="launch_btn" appid="appid" :extinfo="urlLink" class="launch_app"
@error="handleErrorFn" @launch="handleLaunchFn" @ready="handleComponentReady">
<script type="text/wxtag-template">
<style>
.btn {
background-color: #008A00;
text-align: center;
border-radius: 30px;
color: white;
font-size: 16px;
width: 60%;
line-height: 36px;
}
</style>
<button class="btn">打开手机银行</button>
</script>
</wx-open-launch-app>
<view class="mask-box" v-if="maskFlage">
<img src="../../images/mask-box.png"></image>
</view>
<view class="dt"></view>
<view class="dt1">
<img src="../../images/sjyh.png" style="width:100%;display: block;" />
</view>
<button class="btn2" @click="golink" v-if="!isLaunchLoad">打开手机银行</button>
</view>
</template>
<script>
import { getSignmsg } from '../../utils/api.js'
let app = null
export default {
data() {
return {
maskFlage: false,
isLaunchLoad: false,
urlLink: ''
}
},
onShow() {
app = getApp().globalData
var json = this.initUrlStr()
console.log(json);
app.order_id = json.order_id || '';
app.key = json.key || '';
let urlLink = '微信跳转app需要的参数'
console.log(urlLink, "===========微信跳转app需要的参数=============");
this.golink()
},
methods: {
initUrlStr: function() {
var r = window.location.search.substring(1)
if (r) {
r = decodeURI(r);
var json = "{";
var arr = r.split("&");
for (var i = 0; i < arr.length; i++) {
var arri = arr[i].split("=");
json += arri[0] + ":'" + arri[1] + "'";
if (i != arr.length - 1) {
json += ",";
}
}
json += "}";
return eval("(" + json + ")");
} else {
var json = {};
return json;
}
},
// 判断环境
async getCurrentEnvironment() {
var userAgent = navigator.userAgent.toLowerCase();
console.log(userAgent, '当前环境');
if (userAgent.indexOf('alipay') !== -1) {
console.log('支付宝');
this.maskFlage = true
return true;
} else if (userAgent.indexOf('micromessenger') !== -1) {
console.log('微信');
try {
await this.$tool.initJssdk()
} catch (e) {
console.log(e, '=====================');
this.maskFlage = true
}
return true;
} else if (userAgent.indexOf('unionPay/1.0') !== -1) {
console.log('云闪付');
this.maskFlage = true
return true;
} else {
console.log('浏览器');
return false;
}
},
golink() {
if (this.getCurrentEnvironment()) {
console.log("非浏览器环境");
} else {
// 浏览器打开
let url = '要打开的app'
console.log(app.key, 'appkey');
console.log(app.order_id, 'order_id');
window.location.href = url
// const ifr = document.createElement('iframe');
// ifr.src = url;
// ifr.style.display = 'none';
// document.body.appendChild(ifr);
}
},
// 监听error 函数
handleErrorFn(e) {
console.log('用户点击跳转按钮后出现错误', e)
},
// 监听launch 函数
handleLaunchFn(e) {
console.log('用户点击跳转按钮并对确认弹窗进行操作后触发', e)
},
handleComponentReady(data) {
this.isLaunchLoad = true;
console.log('标签初始化完毕,可以进行点击操作:', data);
},
}
}
</script>
<style>
page {
height: 100%;
width: 100%;
}
.main {
height: 100%;
width: 100%;
}
.btn2 {
position: fixed;
background-color: #008A00;
text-align: center;
margin-left: 20%;
border-radius: 30px;
color: white;
font-size: 16px;
width: 60%;
display: block;
line-height: 36px;
bottom: 88px;
}
.dt {
width: 100%;
height: 7.5%;
}
.dt1 {
width: 100%;
}
.mask-box {
display: flex;
position: fixed;
min-height: 100vh;
display: block;
z-index: 999;
width: 100%;
}
.mask-box img {
width: 100%;
height: 100%;
}
.launch_app {
margin-left: 20%;
position: fixed;
width: 100%;
display: block;
bottom: 88px;
}
</style>