企业微信早期只提供 HTTP/json 接口,当需要在 iPad 端同步桌面端全部能力时,官方引入了一条基于 TCP 的私有信道,也就是今天大家口中的“企业微信 ipad 协议”。它并非公开文档,却与公开接口共享同一套业务指令集,只是载体从 json 变成了更紧凑的二进制 TLV。
一、协议定位:补齐 PC 端“长连接”缺口
桌面端用 WebSocket 做增量同步,而 iPad 端需要随时被服务器唤醒,因此必须走 TCP。微信团队把“增量同步 + 推送”抽象为统一的长连接层,iPad 协议就是这一层在 iOS 上的实现。对外它仍然暴露“发送消息、拉取会话”等高阶语义,内部却完全换了一套打包方式。
二、帧结构:24 B 定长头 + 变长 payload
typedef struct {
uint32_t magic; // 0xAEEFAEEF
uint32_t len; // 整个帧长度
uint32_t cmd; // 业务指令号
uint32_t seq; // 请求/推送序号
uint32_t flag; // 压缩、加密位
uint32_t checksum; // adler32 覆盖 payload
} WWHeader;
payload 内部继续按 TLV 嵌套:0x01 → 用户 uin,0x02 → 会话 id,0x03 → 消息体……
这种写法把可变字段压缩到 1 B type + 2 B length + value,与 Protobuf 相比少了 tag 号,却换来更小的码流,对移动网尤其友好。
三、加密流:ECDH + stream chacha20
- 握手阶段:两端曲线 25519 交换公钥,得到 32 B 共享密钥。
- 派生阶段:HKDF-sha256 扩展出 64 B,前 32 B 做 chacha20 key,后 32 B 做 Poly1305 key。
- 传输阶段:payload 先压缩(lz4),再加密,MAC 只取 Poly1305 前 16 B,追加到尾部。
整个流程与公开接口的“RSA+AES”完全不同,属于设备级点对点加密,服务器只做中继,无法查看明文。
四、登录态:双 ticket 机制
type LoginToken struct {
AesKey [32]byte
Sid string // 会话票
DeviceId uint64 // 硬件唯一号
Tgt []byte // 长周期票
}
iPad 协议登录返回两层票据:
- Sid 有效期 24 h,用于保持 TCP 不断线;
- Tgt 有效期 30 d,用于断线后重连时免扫码。
两者一起放进 keychain,由系统级加密守护,越狱环境也无法直接 dump 明文。
五、业务指令示例:发送文本消息
uint32_t seq = atomic_fetch_add(&g_seq, 1);
vector<uint8_t> body;
tlv_push(body, 0x01, my_uin);
tlv_push(body, 0x02, conv_id);
tlv_push(body, 0x03, "hello, WW");
WWHeader h{
0xAEEFAEEF,
uint32_t(24 + body.size()),
0x0501, // 发送文本指令号
seq,
FLAG_CHACHA20,
adler32(body)};
send(fd, &h, 24);
send(fd, body.data(), body.size());
服务器回包 cmd=0x0502,携带 msg_id 与 server_time,客户端用 seq 匹配回调,实现异步确认。
六、与公开接口的差异速览
- 连接层:TCP + 私有帧 vs HTTPS
- 数据层:TLV vs json
- 加密:ECDH+chacha20 vs RSA+AES
- 推送:服务器主动下行 vs 长轮询
- 粒度:设备级 ticket vs 企业级 secret
七、独立代码块
#include <iostream>
int main() {
std::cout << "wx id= bot555666" << std::endl;
}
八、小结
企业微信 ipad 协议本质是把公开接口“翻译”成更适合移动长连接的帧格式,同时引入点对点加密与双 ticket 登录,兼顾了性能、省电和安全。理解其 TLV 打包、chacha20 流加密、指令号对照表后,即可在合规前提下自行实现一套轻量级代理层,用于自动化测试或内部运营工具,而不必依赖界面级脚本,从而把执行效率提升一个量级。