接入场景
企业内部开发
面向企业内部开发人员或行业定制ISV,通过开放接口与企业内部系统实现对接,满足企业个性化需求
第三方应用开发
面向SaaS服务合作伙伴,将产品以第三方应用的形式接入企业微信,为企业提供服务
智慧硬件开发
面向智能硬件厂商,基于企业微信提供的硬件SDK,升级硬件能力,并提供软硬一体的场景化方案
现公司比较容易入手的是前两个场景,开发的应用可以仅限企业内部使用,也可以申请成为第三方应用服务商,开发并发布第三方应用供其他企业使用。 运用企业微信提供的API,如通讯录管理、应用管理、消息推送、身份验证、移动端SDK、素材、OA数据接口、企业支付、电子发票,可以完成诸如以下功能的应用开发: 通讯录管理:企业可以将已有的通讯录跟企业微信通讯录同步,避免同时维护多套通讯录。 应用管理:在企业微信中创建应用后,企业可以将已有的系统以应用方式接入企业微信,为企业提供丰富的办公应用。 消息推送:企业的通知可以快速触达成员,也可以接收成员发来的消息,让信息传递更高效。 身份验证:通过OAuth2识别用户身份,成员访问企业网页时可以免密码自动登录。 移动端SDK:JS-SDK可以调用企业微信原生客户端的能力,提升成员的使用体验。企业微信登录、分享SDK帮助移动应用实现快速登录、内容分享。
开始开发之前
开始开发之前需要了解到企业微信中几个重要的数据
corpid
每个企业都拥有唯一的corpid
,登录企业微信管理后台点击“我的企业”-“企业信息”下查看“企业ID”(需要有管理员权限)
userid
每个成员都有唯一的userid
,即所谓“帐号”。在管理后台->“通讯录”->点进某个成员的详情页,可以看到。
另外还有部门id:组织架构的分类id;tagid
:标签的id,可新建标签并将成员加入该标签的分类中。
接下来我们从开发一个简单的企业内部应用入手
创建应用
登录企业微信管理端 -> 应用与小程序 -> 应用 -> 自建,点击“创建应用”,设置应用log、应用名称等信息,创建应用。
创建应用后可以得到应用的两个关键信息,AgentId
,和Secret
AgentId
:每个应用都有唯一的agentid
secret
:secret
是企业应用里面用于保障数据安全的“钥匙”,每一个应用都有一个独立的访问密钥,为了保证数据的安全,secret
务必不能泄漏。
功能开发
下面开发一个向应用发送消息的功能
获取
access_token
通过corpid
和secret
获取access_token
,用GET
方式请求URL
:https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=ID&corpsecret=SECRECT
发送消息 构建消息体并发送消息,使用
POST
请求URL
:https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=access_token
,消息体的为json格式{ "touser" : "UserID1|UserID2|UserID3", // 接收消息的用户列表 "toparty" : "PartyID1|PartyID2", // 接收消息的部门列表 "totag" : "TagID1 | TagID2", // 接收消息的标签列表 "msgtype" : "text", // 消息类型 "agentid" : 1, // 应用id "text" : { // 消息内容 "content" : "来自node的消息" }, "safe":0 // 是否保密 }
另外消息模块还能监听消息接收事件。以上展示的是服务端的API能完成的事情,服务端API还提供通讯录管理、外部联系人管理、身份验证、应用管理、消息推送、素材管理、OA数据接口、企业支付、电子发票等功能。 比如可以读取和修改企业微信通讯录,这样就可以做到通讯录和人员架构统一处理,对接企业内的其他独立应用。
你可以用postman
做接口测试,也可以使用企业微信接口调试工具
发起请求,或自己写个脚本。
const request = require('./request');
const corpid = '111111';
const corpsecret = '1111111';
// 获取accessk_token
request(`https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${corpid}&corpsecret=${corpsecret}`, {
method: 'GET'
})
.then(res => {
return JSON.parse(res).access_token
})
// 构造消息体
.then((access_token) => {
let message = {
"touser" : "YeMao", // 接收者ID列表
"msgtype" : "text",
"agentid" : 1000002,
"text" : {
"content" : "来自node的消息"
},
"safe": 1
};
return request(`https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${access_token}`, {
method: 'POST',
body: message
});
})
.then((res) => {
console.log('成功发送:' + res);
})
客户端能力
企业微信提供客户端API,主要运用在3个方面,小程序、JS-SDK、移动端-SDK,和微信的功能几乎一致。
小程序
注意:企业微信移动客户端从2.5.8版本开始,有内置小程序基础库,开发者无需做适配,即可将微信小程序移植到企业微信上运行,同时开发者也可以针对企业微信提供的特殊接口开发出更适应于企业内部场景的小程序。需注意,目前企业微信只支持运行已在微信侧上架的小程序,暂不支持独立的企业微信小程序。
在企业微信环境下运行的小程序,部分接口有些变动,比如如果在企业微信环境下调用wx.login
,实际上是以微信的身份进行登录的,而需要调用wx.qy.login
。
企业微信小程序的开发与微信小程序开发几乎没有区别,只需要注意部分接口的差异性即可,比如上面提到的登录接口,还有wx.qy.checkSession
、wx.qy.getEnterpriseUserInfo
。
如果你希望你的小程序在企业微信和微信中都能运行,那么最基础的是应该判断当前运行环境,可以通过wx.getSystemInfo
或wx.getSystemInfoSync
获取,在企业微信中运行时,改方法会返回的数据中会额外增加字段environment: "wxwork"
。之后将进行不同的小程序登录流程。
开发及发布
企业微信小程序是微信小程序在企业中运行,所以你需要在微信公众平台上完成小程序的创建,和后续的发布。总结起来大概是以下步骤:
- 微信公众平台注册小程序,并像常规程序一样设置小程序的开发者等信息。
- 在开发者工具中开发调试,企业微信专有接口,在开发者工具中创建“预览”二维码,在企业微信中扫描二维码运行并调试小程序。
- 提交小程序审核发布。
- 在企业微信管理端进行小程序的授权、关联和可见范围设置。
- 可见用户通过工作台进入小程序。
企业微信专用接口
不是所有的小程序接口和组件都能被企业微信小程序支持,具体应该查看小程序接口支持表,并在企业微信环境下实际调试,企业微信提供的专用接口的调用方法统一为wx.qy.[接口名]
。
wx.qy.canIUse
判断接口支持情况,调用参数和小程序相关接口类似${API}.${method}.${param}.${options}
,具体可以查看官方文档。
其余还有wx.qy.getEnterpriseUserInfo
获取企业成员基本信息、wx.qy.getAvatar
获取企业成员头像、wx.qy.getQrCode
获取企业成员个人二维码、wx.qy.getMobile
获取企业成员手机号等。
还有企业通讯录与会话相关的方法,具体可以查看相关API文档
小程序demo
demo能力设想:通过人脸识别,实现员工打卡功能。 问题拆解:
- 整套人脸识别系统采用第三方接口,比如百度人工智能。
- 小程序识别用户登录上文使用上文的登录流程实现,登录后后端可以拿到用户在对应企业中的唯一id。
- 企业通讯录有对应api获取全部成员信息,比如:
https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?access_token=ACCESS_TOKEN&department_id=DEPARTMENT_ID&fetch_child=FETCH_CHILD
获取部门成员,百度人脸库有相应api创建人脸信息。企业微信有相应回调可监听企业通讯录变更事件。以上API可以实现统一维护企业成员信息。 - 签到时的人脸信息获取使用
<camera />
组件,和相机组件控制wx.createCameraContext
实现图片采集,使用wx.uploadFile
实现图片上传。camera
组件在官方文档中标记为不支持企业微信,但在实际测试中可正常运行。 - 后端接收到图片并处理后发送到百度人脸库,获取并处理人脸匹配信息,返回结果给客户端。
核心业务逻辑如下图所示:
demo只实现核心的客户端和服务端逻辑,省略登录流程、人脸库和通讯录同步流程。人脸库直接在百度云管理后台中创建。
客户端
<view class='main' bindtap='punch'>
{{ time }}
</view>
<camera device-position="front" flash="auto" binderror="error" class='camera' ></camera>
Page({
data: {
time: ''
},
refreshTime: function () {
// 显示当前时间
let date = this.date = new Date();
let time = date.toTimeString().slice(0, 8)
this.setData({
time
})
},
onLoad: function (options) {
// 插件相机上下文
this.ctx = wx.createCameraContext();
this.refreshTime()
setInterval(() => {
this.refreshTime()
}, 1000)
},
punch: function () {
wx.showLoading({
title: '正在签到',
mask: true
});
// 获取相片
this.ctx.takePhoto({
success: (res) => {
// 上传照片
wx.uploadFile({
url: 'http://10.0.0.20:8080/punch',
filePath: res.tempImagePath,
name: 'image',
success: (res) => {
if (res.data === 'SUCCESS') {
wx.showToast({
title: '打卡成功'
});
} else {
wx.showToast({
title: '打卡失败',
icon: 'none'
});
}
},
fail: () => {
wx.showToast({
title: '打卡失败',
icon: 'none'
});
}
})
}
})
}
}
服务端
获取百度云access_token
//
const request = require('request-promise');
const client_id = '0000000';
const client_secret = '0000000000';
let authInfo = {};
module.exports = async function () {
if (authInfo.access_token) {
return authInfo;
} else {
// 获取accessk_token
return request(`https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=${client_id}&client_secret=${client_secret}`, {
json: true
})
.then(data => {
authInfo = data
return authInfo;
})
.catch(error => {
authInfo = {}
return authInfo;
})
}
}
人脸验证接口
const getToken = require('./access_token');
const request = require('request-promise');
module.exports = function face (data) {
return getToken()
.then(info => {
if (!info.access_token) {
throw Error('Get access_token failed');
}
return info.access_token;
})
.then(token => {
// 请求人脸匹配数据
return request(`https://aip.baidubce.com/rest/2.0/face/v3/search?access_token=${token}`, {
body: data,
json: true,
method: 'POST'
})
.then(data => data)
})
.then(res => {
console.log(res)
return res.result;
})
}
服务入口
const express = require('express');
const multer = require('multer');
const face = require('../baiduAI/face');
const app = express();
const storage = multer.memoryStorage();
const upload = multer({ storage });
//
let group_id = 'LUWEI';
app.post('/punch', upload.single('image'), async (req, res) => {
// 接收小程序上传的图片
let image = req.file.buffer.toString('base64')
let result = await face({
image,
image_type: 'BASE64',
group_id_list: group_id
})
// 处理并返回签到信息
if (!result) {
return res.send('FAIL');
}
let user = result.user_list[0];
/*
对比当前登录的用户是否是匹配的用户,完整流程需要操作数据库,保存签到信息
user.user_id
*/
// 用户匹配打分
if (user.score > 80) {
return res.send('SUCCESS');
}
return res.send('FAIL');
})
以上便是企业微信及其能力的简要介绍,可以看到企业微信的应用和微信的公众号类似,小程序几乎一样,所以只要你会微信开发,企业微信开发也能快速上手。
作者简介:叶茂,芦苇科技web前端开发工程师,代表作品:口红挑战网红小游戏、服务端渲染官网。擅长网站建设、公众号开发、微信小程序开发、小游戏、公众号开发,专注于前端领域框架、交互设计、图像绘制、数据分析等研究。 一起并肩作战: yemao@talkmoney.cn 访问 www.talkmoney.cn 了解更多