uniapp项目上企业微信应用经历
前言
本文同样发于稀土掘金文章。我不知道同文章发2个平台是否允许,如果不允许的话可以私信或者留言告诉我否?谢谢
一、背景
uniapp项目,之前针对的app开发,真机调试安装都以app端为目标,做了很久,完成度较高,突然提需求要整上企业微信…我目前还是实习生,做之前完全没接触过这方面知识,踩了很多坑之后现在来记录下自己的经历,也想帮助后来者(做的时候查资料、debug太痛苦了)。
可能本文介绍的不是最优方案,作者目前还是实习生所以经验上可能有所欠缺,有更好的方案或哪里写的不好请指教:D。
二、项目结构
项目中nvue,vue页面混合使用,本篇文章所用到的项目结构展示
.
├── common #公共基础文件
│ └── wxJSSDK.js #企业微信sdk
├── pages #页面
│ └── a.vue
├── App.vue
├── main.js
├── template.h5.html #入口
.
前端要做的事
一、和后端交流建立测试应用
建议都先看看 企业微信开发文档
沟通后,先建一个企业(群),然后建一个应用,在工作台进入。因为企业微信调用特殊api需要可信且备案域名,需要前端搞一个域名或者内网穿透,我这里是用了nginx搭配内网穿透,买的花生壳的服务,nginx配置就简单带过吧,主要是转发访问到本地打包出来的文件,然后设置禁用缓存策略(不然很长一段时间打开都调的缓存);以及在某处塞一个带验证码的txt文件,后端访问一次后可以在企业微信加入可信域名白名单。
二、配置sdk
区分一下,项目里用的api分 通用api 和 特殊api,通用api引入即可使用,默认通过wx.fn()调用,特殊api需要验证权限后才能允许调用,引入后通过 wx对象或者 jWeixin对象引用,这里看到有两个wx对象,冲突了,后面会说我的解决方案。
最难的一步
长话短说,在查阅大量博客和文档,甚至官方问答社区后,我目前得出的结论(2023-02-12)是:
- 1.复制这个链接 http://open.work.weixin.qq.com/api/jsapidemo 到企业微信发送打开,随便一个群里都行,上面有的api,我称之为特殊api,需要注册后使用,具体注册流程看官方文档,简单来说就是每个页面用它的api都得先验证权限,等回调后再使用
- 2.通过npm下载的jweixin-module缺失手势返回接口。似乎手动cv代码到本地也不起作用(同事报告),只能在线引入,参考官方文档 步骤一 目前是jWeixin1.2.0。
- 3.安卓和ios,原本要用不同的对象调用注册后才能用的特殊api
- 4.通用api,引入文件后使用wx对象调用
针对此,我做的事有:
- 在入口文件(template.h5.html 或者有些是 index.html)里加入以下代码,引入wx对象,目前我最常用到的通用api是在企业微信中更换标题。
<script>
// 判断环境
console.log('navigator.userAgent: ', navigator.userAgent);
var ua = navigator.userAgent.toLowerCase();
if(ua.match(/micromessenger/i) == 'micromessenger') {
console.log('>>>微信环境<<<');
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://res.wx.qq.com/open/js/jweixin-1.2.0.js';
document.head.appendChild(script);
}
</script>
- 在common下新建js文件,我命名为wxJSSDK
- 在main.js中引入wxJSSDK.js,并挂载到全局对象()
// main.js
import Vue from 'vue'
import App from './App'
/* ... */
// ios调试工具,后面介绍
import VConsole from 'vconsole'
import jwx from '@/common/wxJSSDK'
var ua = navigator.userAgent.toLowerCase();
if(ua.match(/micromessenger/i) == 'micromessenger') {
Vue.prototype.$jwx = jwx
new VConsole()
}
为什么挂到全局对象,因为特殊api每次用都要先验证,为了不在每个页面文件都写同一遍代码,做成全局对象会很方便,要用的时候就 this.$jwx.fn() 即可。
- wxJSSDK.js代码
仅供参考。这部分就要处理上面说的几个痛点,封装后在页面就以this.$jwx.fn()使用了。
import store from 'xxx'
console.log('load SCRIPT');
const nuA = navigator.userAgent.toLowerCase();
// 本页面也要引入sdk
let script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://res.wx.qq.com/open/js/jweixin-1.2.0.js';
document.body.appendChild(script);
let commonWx = null;
if(!nuA.includes('micromessenger')) {
console.log('非微信环境');
} else {
// 安卓wx jWeixin都存在,ios下jWeixin不存在...所以会影响到后面
// 需要处理成同一个对象
// 可以先指定commonWx为jWeixin
setTimeout(()=>{
try{
commonWx = jWeixin;
}catch(e) {}
if(nuA.includes('iphone')) {
commonWx = wx;
}
}, 500);
}
export default {
initJssdk: function(callback) {
//获取当前url然后传递给后台获取授权和签名信息
var cUrl = window.location.href.split('#')[0];
uni.request({
// 按企业微信官方文档要求,要传当前网页的URL, 不包含#及其后面部分 给后端处理
url: '后端获取签名的接口地址',
data:{
url: cUrl // 例如 http://www.xxx.com/test/interface
},
method: 'xxx', // GET或者POST最常用
header: {
// 你的请求必带的头字段,一般是token什么的,登录时一般存store
'xxx': store.xxx
},
success: (res) => {
//注入config权限配置
commonWx.config({
beta: true,
debug: false,
appId: res.xxx.appId,
timestamp: parseInt(res.xxx.timestamp),
nonceStr: res.xxx.nonceStr,
signature: res.xxx.signature,
// 这里是需要用到的特殊api名称
jsApiList: [
'onHistoryBack'// 控制返回
]
});
if (callback) {
callback();
}
}
})
},
// 封装微信JSSDK方法
// return true放行,反之不执行
onHistoryBack(fn) {
this.initJssdk();
commonWx.ready(() => {
commonWx.onHistoryBack(() => {
fn();
return false;
})
});
commonWx.error(res => {
console.log("config fail:", res);
});
},
}
三、开发者工具
网址均复制到企业微信自建企业内粘贴发送打开。
官方特殊api demo http://open.work.weixin.qq.com/api/jsapidemo
(安卓下有效,点击→信息→TBS settings→打开vConsole调试功能) http://debugx5.qq.com
一是企业微信官方做的demo,可以看某api在移动端表现效果。
二是安卓端下点击可以勾选是否显示开发者工具(前端应该都知道这东西的重要性),当然苹果端就要借助库了,看上面main.js写法,通过npm安装(安卓同样有效)。
npm install vconsole
主要需求和开发建议
一、主要需求
1.手势返回
如不指定,默认下是返回前一个页面,即调用uni.navigateBack,当然最终也是调的wx.navigateBack,通用api不需要注册
那什么时候需要指定呢,我遇到的一个场景是 新增页,点击打开弹框组件选择人员,此时手势返回应该是关闭弹框而非关闭页面
还记得前文配的wxJSSDK.js么,因为在main.js中挂载到了全局对象jwx,现在可以直接用了。
例如在 add.vue ,在mounted处第一行添加以下代码以及其他代码:
mounted() {
if(xxx) {
this.$jwx.onHistoryBack(this.fn);
wx.setNavigationBarTitle({title: '当前页面标题'});
}
...
}
...
methods: {
fn() {
if(弹框打开) {
this.弹框show = false;
} else {
uni.navi...
}
}
}
额外注意,如果是tabbar页面,企业微信是直接退出的!不会监听不会阻拦直接退出…
2.标题栏
通用api,原生wx对象就有(在template处引入),console.log(wx)即可看,所以直接使用,我的话会用在mounted第一行,同手势返回,代码如上图。
3.登录与账号绑定问题
需求:员工打开应用附带信息进行绑定应用账号操作,之后打开应用即自动登录
涉及OAuth2认证,首先,在应用管理页面处理回调时,回调路径选择前端入口,比如https://open.weixin.qq.com/…&redirect_uri={前端入口如http://www.test.com/nothing/login}…
正常情况下最终会回调进入前端页面,路径附带着参数,我的情况是传递了code,state,例如/nothing/login?code=xx&state=xx,获取参数后转发给后端,后端接企业微信api,回调后就可以返回获取用户当前企业id或者用户id,包括本地数据等等,之后继续走逻辑。
二、开发建议
- 跨端问题
uniapp很强,但是还不够,开发途中确实发现一些安卓和ios的区别,例如苹果手机一些版本屏幕下有黑条感应区,对应的要添加viewport-fit=cover等。
- 多人开发
如果是多人开发,但应用只能配一个回调路径,那其他人想使用api怎么办呢?我这边是每个人搞一个域名+内网穿透,虽然应用只能配一个回调路径,但是可以添加可信域名到白名单,允许可信域通过企业微信检查从而调用api → 直接把链接发在聊天点击进入即可(仅限于调用api比如手势返回,打开扫码这些)。