头图

背景

最近针对于大客户企业微信群聊业务诉求做定制化开发,增强功能场景和业务管理抓手,比如获取群聊ID,统计群聊咨询问题,一键推送群聊消息等业务场景。针对于新手在这里记录分享了从新建项目,到账号申请,再到项目接入,场景问题分析,最终上线的全流程,希望对你有帮助。

开发文档

企业微信管理后台 https://work.weixin.qq.com/wework_admin/frame
企业微信开发者中心文档 https://developer.work.weixin.qq.com/document

内部应用

基于微信生态的开发有小程序和公众号,同样,也可以基于企业微信生态开发H5或者小程序,它们都定义为应用。企业微信应用有自带的基础应用,第三方应用和自建应用。
image.png

聊天工具栏

初识工具栏页面

在PC端群聊或者用户聊天右边侧边有一个TAB栏,在这里可以通过后台进行配置。这里我们简单的配置一个百度页面。【客户与上下游】> 【客户联系】>【聊天工具】> 【聊天工具栏管理】https://work.weixin.qq.com/wework_admin/frame#/customer/chatMenu

iShot_2023-12-06_13.50.21.png

image.png

自建应用&工具栏关系

在一个应用的聊天工具栏里,我们可以配置多个页面。但是在一个群聊的侧边工具栏管理可以录入来自不同应用的配置页面。它们之间的关系大致如下。

聊天工具栏加载条件

聊天工具栏不是在所有聊天场景都会有的,只有外部用户或者外部群才会显示。
企业微信用户 A 添加了其实企业的用户 B,那么 B 就是这个企业的外部联系人。 比如加了微信用户,就会有微信图标,也就是外部联系人。
image.png
把外部联系人加入群聊,这个群就是外部联系群。
image.png

本地开发调试

我们本地项目启动一般是localhost或者IP+端口号,在管理端配置工具栏链接也是可以加载的

image.png

企微JS-SDK接入

我们尝试接入企微的JS-SDK 为网页应用提供了调用原生能力的通道。

企业微信 JS-SDK 网页应用通过 JS-SDK 可以调起拍照、选择图片、录音、获取地理位置信息等手机系统能力。同时可以使用群聊、群发和朋友圈等企业微信特有能力,为企业微信用户提供更优质的网页应用体验。

引入JS文件

在需要调用JS接口的页面引入JS文件

<script src="//res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>

config接口注入权限验证

所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA(single-page application)的web app可在每次url变化时进行调用)。
wx.config({
    beta: true,// 必须这么写,否则wx.invoke调用形式的jsapi会有问题
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,企业微信的corpID,必须是本企业的corpID,不允许跨企业使用
    timestamp: '', // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名,见 附录-JS-SDK使用权限签名算法
    jsApiList: [] // 必填,需要使用的JS接口列表,凡是要调用的接口都需要传进来
});

在这里我们需要关注的字段signature,通过JS-SDK使用权限签名算法获得,其中企业jsapi\_ticket时H5应用调用企业微信JS接口的临时票据,它是签名算法中重要组成部分。由于jsapi\_ticket有效期为7200秒,并对调用频次有限制(一小时内,一个企业最多可获取400次,且单个应用不能超过100次),在生产环境一般放在服务端生成并缓存。

企微签名工具

但是我们前期本地开发想快速获取到,可以使用以下命令:

# CORPID、SECRET为占位符,请自行填入真实的企业ID和应用Secret
npx wwutil ticket CORPID SECRET

但是企微一般会禁用获取
image.png
需要从管理后台进行可用IP配置,路径:应用管理-开发者接口-企业可信IP。
image.png
配置可信IP后
image.png
这样我们就获取到了企业ticket和应用ticket,这里我们需要的是企业ticket的,应用ticket的作用后面我们会用到。
接下来我们去 签名工具页生成signature

image.png
注意noncestrltimestampwx.config接口和签名保持一致。得到了签名signature,这样wx.config的必要参数已满足。

自定义企微签名插件

上述我们使用企业微信官方的签名工具,需要手动执行并复制临时票据ticket,调整相关参数在签名工具生成后在复制signature到代码中,在签名过期后又需要重复这个环节。本着“偷懒是创造力的源泉”,我们可以自行实现签名相关前端工具。在这里,我分别实现了vitejswebpack版的企微应用鉴权插件:vite-plugin-ww-authww-auth-webpack-plugin

ww-auth-webpack-plugin

使用npm安装

npm install ww-auth-webpack-plugin

然后在webpack.config.js或者vue.config.js中你可以这样配置

//...
const WwAuthPlugin = require('ww-auth-webpack-plugin')
module.exports = defineConfig({
  // ...
  configureWebpack: {
    plugins: [
      new WwAuthPlugin({
        corpid: "", // 必填,企业微信的corpid,必须与当前登录的企业一致
        corpsecret: "", // 必填,密钥
        timestamp: "", // 必填,生成签名的时间戳
        noncestr: "", // 必填,生成签名的随机串
        agentid: "", // 必填,企业微信的应用id (e.g. 1000247)
        url: "", // 页面URL
      }),
    ],
  },
});

页面加载时,即可通过请求__wwAuthInfo__.json获取企业微信SDK鉴权所需信息。

// 初始化企业微信鉴权
export const initSdk = async () => {
   const authInfo = await fetch("__wwAuthInfo__.json").then((response) =>
    response.json()
  );
  const { noncestr, timestamp, corpid, corpsign } = authInfo;

  return new Promise((resolve, reject) => {
    wx.config({
      beta: true, // 必须这么写,否则wx.invoke调用形式的jsapi会有问题
      debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
      appId: corpid, // 必填,企业微信的corpID,必须是本企业的corpID,不允许跨企业使用
      timestamp, // 必填,生成签名的时间戳
      nonceStr: noncestr, // 必填,生成签名的随机串
      signature: corpsign, // 必填,签名,见 附录-JS-SDK使用权限签名算法
      jsApiList: ["chooseImage"] // 必填,需要使用的JS接口列表,凡是要调用的接口都需要传进来
    });
  });
};

vite-plugin-ww-auth

使用npm安装

npm install vite-plugin-ww-auth

然后在vue.config.ts中你可以这样配置

//...
import viteWwAuth from "vite-plugin-ww-auth";
// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
  // 环境变量
  const env = loadEnv(mode, root, "");
  return {
    // ...
    plugins: [
      viteWwAuth({
        corpid: '', // 必填,企业微信的corpid,必须与当前登录的企业一致
        corpsecret: '', // 必填,密钥
        timestamp: '', // 必填,生成签名的时间戳
        noncestr: '', // 必填,生成签名的随机串
        agentid: '', // 必填,企业微信的应用id (e.g. 1000247)
        url: '',
      })
    ],
  };
});

页面加载时,即可从window.__wwAuthInfo__获取企业微信SDK鉴权所需信息

const authInfo = window.__wwAuthInfo__;

// 初始化企业微信鉴权
export const initSdk = async () => {
  const { noncestr, timestamp, corpid, corpsign } = authInfo;

  return new Promise((resolve, reject) => {
    wx.config({
      beta: true, // 必须这么写,否则wx.invoke调用形式的jsapi会有问题
      debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
      appId: corpid, // 必填,企业微信的corpID,必须是本企业的corpID,不允许跨企业使用
      timestamp, // 必填,生成签名的时间戳
      nonceStr: noncestr, // 必填,生成签名的随机串
      signature: corpsign, // 必填,签名,见 附录-JS-SDK使用权限签名算法
      jsApiList: ["chooseImage"] // 必填,需要使用的JS接口列表,凡是要调用的接口都需要传进来
    });
  });
};

接下来,本地项目启动,SDK报错:wx.config:not match any reliable domain.
image.png

意思就是没有匹配可信的域名,其实JS-SDK在其API文档就有明确的说明image.png

可信域名

所有的JS接口只能在企业微信应用的可信域名下调用(包括子域名),且可信域名必须有ICP备案且在管理端验证域名归属。
验证域名归属的方法在企业微信的管理后台“我的应用”里,进入应用,设置应用可信域名。

image.png

完成企业主体认证(联系客服)

当配置域名提示“域名主体校验不通过“时,请根据域名的不同情况进行处理:

  1. 第三方服务商域名。如果需要第三方服务商为企业开发应用,为保障企业数据安全,请通过企业微信代开发模式提供。
  2. 同主体或关联主体的域名。如果配置域名的备案主体确实与企业认证/验证主体相同,或具有关联关系,可以联系企业微信客服处理。需要提交
    1)企业corpid、企业全称和域名
    2)提供股权比例关系证明(如企业信用信息查询系统截图、上市公司年报、财报、招股书等可公开查询的信息)

配置可信域校验

这里我们将一级域名(sf-express.com)关联到了当前企业微信主体,这样后续开通其他内部应用使用二级域名无需再申请可信域名。只需在域名站点根目录下放置校验文件即可。企业微信会读取该文件完成可信校验,这样在聊天工具栏配置的页面URL才允许加载。
image.png
应用管理-自建-网页授权及JS-SDK

image.png
应用管理-自建-配置到聊天工具栏

本地代理调试

我们在本地开发调试,启动服务访问一般是localhost:port或者ip:port形式,这种形式是不能配置到可信域的(因为与认证域名不匹配,可信域是一个完整的域名,并且是外网的)。而工具栏页加载的是我们配置的可信域名URL,要想将本地服务页面在企微工具栏页直接嵌入佳,则需要“骗过”可信域名的限制。这时,可以修改我们主机的host或者使用代理软件,将访问可信域URL代理到localhost:port上,这样实际访问的是我们本地开发的服务。

image.png
这里代理软件为了方便修改维护,使用CharlesWhistle
我使用的Charles代理,设置很简单,Tools > Map Remote 填写访问和代理的地址+端口等即可。
image.png

image.png
2023-11-19 18-24-24.2023-11-19 18\_26\_16.gif

JS-SDK调用

下面我们可以正常使用JS-SDK调用原生能力了,比如checkJsApi检测某个API是否可用

wx.checkJsApi({
  jsApiList: ["chooseImage"], // 需要检测的JS接口列表
  success: function (res) {
    showDialog({ message: JSON.stringify(res) });
  }
});

2023-11-27 16-19-04.2023-11-27 16\_30\_17.gif

agentConfig注入应用权限

我们再尝试获取群ID

wx.invoke('getCurExternalChat', {}, function(res){
    console.log('getCurExternalChat: ', res)
});

会被禁止获取
image.png
比如我们还想调用会话、客户联系和微信客服相关能力和信息,则需要先通过[wx.agentConfig](https://developer.work.weixin.qq.com/document/path/94325)注入应用权限。调用wx.agentConfig需要引入jwxwork sdk。

<script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
wx.agentConfig({
    corpid: '', // 必填,企业微信的corpid,必须与当前登录的企业一致
    agentid: '', // 必填,企业微信的应用id (e.g. 1000247)
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名,见附录-JS-SDK使用权限签名算法
    jsApiList: ['selectExternalContact'], //必填,传入需要使用的接口名称
        success: function(res) {
        // 回调
    },
    fail: function(res) {
        if(res.errMsg.indexOf('function not exist') > -1){
            alert('版本过低请升级')
        }
    }
});

这里的signature签名和上面wx.config接口注入权限采用的是相同的算法获得,vite-plugin-ww-authww-auth-webpack-plugin 也支持获取该签名,注意,不同的是还需要agentid,也就是应用id,从后台应用管理打开应用既可看到。
获取群ID

2023-11-27 17-45-24.2023-11-27 17\_46\_00.gif

最后

到这里,我们已经跑通了整个企业微信内部应用的接入,剩下就是正常的业务开发已经部署发布了。


wuwhs
6k 声望2.5k 粉丝

Code for work, write for progress!