项目背景:
uniapp开发的app(Android和ios),需要将话题分享到微信内,再通过点击微信内的链接打开一个h5页面,跳转到app内。如果已安装则打开app,未安装则跳转应用宝,在ios下应用宝会自动跳转App Store。
实现效果展示:
准备工作:
微信内访问网页时跳转到 APP条件:
- 服务号已认证(认证费300元)
- 开放平台账号已认证(认证费300元)
- 服务号与开放平台账号同主体(认证信息需要属于同一主体(公司)!如果认证失败前面的钱就打水漂了)
1、微信公众号(注意是服务号,不是订阅号。是服务号!服务号!服务号!)
需要将服务号进行认证,拿到开发者ID(AppID)和开发者密码(AppSecret),并设置IP白名单(IP为计算签名的服务器ip)
2、服务号绑定JS接口安全域名,也就是移动端h5页面的域名
3.关联移动应用和服务号
微信开放平台准备一个账号,主体需要和微信公众的服务号一致,并将服务号绑定在微信开放平台账号下,并在开放平台内绑定app,并设置域名与所需跳转的app。
在移动页面创建应用,审核状态为通过
在公众号页面绑定服务号,一定注意这里账号类型必须是服务号,如果是订阅号无法进行接口关联设置
点击关联设置输入移动应用的appid即可绑定成功(如果没有这个关联设置,去检查你的账号类型是不是服务号。如果是订阅号就没有关联设置)
代码实现:
第一步:uniapp前端代码实现
在uniapp的对应app项目里写好分享事件,这里使用的uniapp 的分享AP
首先在manifest.json的模块配置中勾选Share(分享),并输入微信开发平台移动应用的appid
// 话题分享,点击分享,跳转到对应的h5页面,然后通过h5跳转到app内
function shareTopic(postId){
console.log("ffffffffff",postId)
const share = reactive({
id: postId,
})
// #ifdef APP
uni.share({
provider:'weixin', //分享服务提供商(即weixin|qq|sinaweibo)
type: 0 , //0图文、1纯文字、2、纯图片 、3、音乐
scene:'WXSceneSession',//provider 为 weixin 时必选 WXSceneSession分享到聊天界面,WXSceneTimeline分享到朋友圈,WXSceneFavorite分享到微信收藏
title:props.postValue.title,//分享内容的标题
summary:props.postValue.content,//分享内容的摘要
href:`http://baidu.com/user/talk/post/index?postId=${share.id}`,//跳转链接,type 为 0 时必选
imageUrl:'https://图片.png',//图片地址,type 为 0、2、5 时必选
success(res) {
//成功返回的参数
console.log(res);
shareData(share);
},
fail(err) {
//失败返回的参数
console.log(err);
}
})
// #endif
}
*这里参数title和summary,imageUrl请根据自己项目填写对应的内容
*type:分享形式,如图文、纯文字、纯图片、音乐、视频、小程序等。默认图文 0。
*href:跳转链接 (这个就是打开app的页面链接地址 这个地址还需要和微信公众平台配置,后面会提到具体配置)
第二步:配置在微信里打开的h5页面
*用于页面中提供一个可跳转指定App的按钮。注意:Android平台通过开放标签跳转App,App必须接入微信OpenSDK(uniapp这些sdk都是内置好的 不用配置)。
*补充说明:1、必须真机才能渲染该标签(开发时可以使用微信开发者工具的公众号网页项目模式调试);2、文字链无法拉起该标签
其中appID就是前面在微信开放平台中移动应用的appID
h5页面示例代码:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="zh-CN">
<head>
<meta charset="utf-8"/>
<title>移动应用</title>
</head>
<body>
<div class="content">
<div>这里写你自己的内容</div>
<div class="fotterbox">
<!-- launch:当用户点击打开APP时触发的事件 -->
<!-- error:当失败时触发的事件 -->
<!-- extinfo: 需要传递给App的信息字符串 -->
<wx-open-launch-app
id="launch-btn"
appid="微信开放平台移动应用的appid"
@launch="AppLaunch"
@error="handleError"
style="position: absolute;top: 0;left: 0;right: 0;height:auto"
>
<script type="text/wxtag-template">
<style>.btn {
width: 100%;
height: 120px;
border-radius: 70px;
border: none;
color: white;
font-size: 40px;
}</style>
<button class="btn">打开APP</button>
</script>
</wx-open-launch-app>
</div>
</div>
<script src="http://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script> <!-- 引入微信JS -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<!--vue3.0-->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script setup>
const href = location.href.split('#')[0];
console.log("href:"+href)
// 打开APP
const AppLaunch = (res) => {
console.log('AppLaunch', res); // 打开APP成功
};
const handleError = (res) => {
console.log('handleError', res); // 打开APP失败
window.location.replace('跳转到应用宝的该app链接'); // 失败跳转到应用宝下载
};
// 微信环境判断
if (!is_weixn()) {
console.error('当前不是微信环境');
}
function initwxlaunch() {
axios({
method: 'get',
url: '/wxShare/token?url=' + encodeURIComponent(href)
}).then((res) => {
console.log("sss", JSON.stringify(res.data.data));
// alert(encodeURIComponent(href))
wx.config({
debug: false, // 关闭调试模式,在测试开发过程中打开
appId: res.data.data.appId, // 必填,公众号的唯一标识
timestamp: res.data.data.timestamp, // 必填,生成签名的时间戳
nonceStr: res.data.data.nonceStr, // 必填,生成签名的随机串
signature: res.data.data.signature, // 必填,签名
jsApiList: ['checkJsApi','onMenuShareAppMessage'],
// 必填,需要使用的JS接口列表
openTagList: ['wx-open-launch-app'] // 可选,需要使用的开放标签列表
});
wx.ready(function () {
console.log('wx.ready 调用成功');
wx.checkJsApi({
jsApiList: ['checkJsApi', ''], // 校验跳转APP的标签是否可用
success: function (res) {
console.log(res,'1可用');
},
fail: function (err) {
console.log(err, '不可用');
}
})
wx.onMenuShareAppMessage({
title: 'App', // 分享标题
desc: '', // 分享描述
link: location.href.split('#')[0], // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: '', // 分享图标
success: function () {
console.log('分享成功');
},
cancel: function () {
console.log('取消分享');
}
});
});
wx.error(function (res) {
console.log("error:", res);
});
}).catch((error) => {
console.error('获取签名失败', error);
});
}
</script>
</body>
</html>
第三步:后端工作
签名步骤:
- 获取access_token 官方文档
appid和secret参数就是开发者ID(AppID),开发者密码(AppSecret) GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
- 成功后会拿到access_token
{"access_token":"sdfad.....1561","expires_in":7200}
- 获取jsapi_ticket,用第一步拿到的access_token 采用http GET方式请求获得jsapi_ticket(有效期2小时,后端需要对jsapi_ticket全局缓存,微信有请求次数限制)
GET https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
- 成功后会得到ticket
{ "errcode":0, "errmsg":"ok", "ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA", "expires_in":7200 }
- 计算签名,官方文档
拼接参数
jsapi_ticket参数为上一个步骤拿到的ticket,noncestr为随机字符串,timestamp为当前时间戳,url为当前前端页面的URL地址(不包含#后面的字符,所以这里最好做成活的,让前端传过来),字段名和字段值都采用原始值,不进行URL 转义
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value
对拼接后的字符串进行sha1签名,得到signature
0f9de62fce790f9a083d5c99e95740ceb90c27ed
将下面的参数返回给前端即可
{
appId: '', // 开发者ID(AppID)
timestamp: , // 生成签名的时间戳
nonceStr: '', // 生成签名的随机字符串
signature: '',// sha1签名
}
测试
所有的都配置好,就可以在微信开发者工具中的 公众号网页项目 中进行测试了
开发测试运行效果:
注意:签名算法的生成规则(接口签名校验工具)
此时,如果你后端把相关信息传过来后,就实现了从h5页面跳转到app内。
从app分享到微信再到微信网页跳转至app对应页面,其中需要注意的是在微信开放平台和微信公众平台的相关配置,看配置是否成功可以在微信开发者工具里测试,把debug模式打开,就可以看到对应的日志反应是否是配置成功了的。
还有各个环节的传递参数,记得存取好。
结尾:
只有在签名,域名,都验证成功后,开放标签才会显示,否则是看不见开放标签按钮的
开放标签的样式只能写在 里面的style标签内,写在外面是不生效的
可以将开放标签外面套一个div,然后div定位到需要的地方,用自己的按钮显示在那个位置,然后将开放标签内的按钮设置成透明,盖在上面,这样方便调试样式(原理:用户看见的是我们自己的按钮,实际点击到的是微信的开放标签按钮)
为了便于调试可以使用 微信开发者工具 - 公众网页 - 下进行调试,调试时是需要将代码放到JS安全域名下的服务器上的,所以每修改代码都要提交到服务器,非常繁琐,(可以通过配置host来实现本地调试,将安全域名映射到本地服务器然后搭配微信开发者工具进行预览调试)