前言
在私域运营和客户服务场景中,向微信好友或群组发送位置消息是一个高频需求——门店导航、上门服务确认、物流取货点通知,都离不开精确的位置共享。然而微信官方并未对个人号开放位置消息接口,开发者若想通过程序化方式实现这一功能,往往无从下手。本文将系统讲解个人微信发送位置消息的接口调用原理、参数结构、代码示例及常见踩坑,并以 WechatApi 作为实现方案进行全程演示。
位置消息在微信生态中的应用场景
位置消息不同于文本或图片,它携带了经纬度坐标、地点名称和详细地址三类结构化数据,接收方点击后可直接在地图 App 导航。这种富媒体特性让它在以下场景中具有不可替代的价值:
门店与上门服务:外卖、家政、快递等 O2O 业务,派单时将服务地点以位置消息推送给服务人员或客户,避免文字地址描述不清造成的导航失败。
活动与会议通知:线下展览、沙龙、培训,主办方通过机器人将活动地点自动群发给报名用户,比发一张截图更准确,也减少客服答疑量。
私域获客与 SCRM:销售在跟进客户时,自动推送最近门店位置,提升到店转化率。结合 微信 SCRM 系统,可以按客户所在城市动态匹配并发送对应门店坐标。
群机器人播报:社区团购群、同城生活群,每天定时推送自提点位置,让群成员无需翻记录就能找到取货地点,这是 微信群管理机器人 的典型用法。
物流与供应链:货运、仓储系统对接微信通知,将仓库或中转站坐标随订单状态变更一并推送,减少电话沟通成本。
上述场景的共同特点是:发送方是个人微信号(非公众号/小程序),需要通过 API 程序化触发,且消息内容是结构化的地理坐标而非普通文本。这正是 WechatApi 所解决的核心问题——基于 微信 iPad 协议 模拟真实客户端行为,使个人微信号具备完整的消息收发能力,包括位置消息。
接口原理:iPad 协议如何承载位置消息
要理解位置消息的接口实现,需要先了解微信客户端与服务器之间的通信机制。微信消息在底层使用 Protobuf 编码,不同消息类型由 MsgType 字段区分:文本为 1,图片为 3,位置消息为 48。
位置消息的 XML 载荷大致如下结构(已简化):
xml<msg>
<location x="31.2304" y="121.4737"
scale="15"
label="上海市黄浦区人民广场"
poiname="人民广场"
poiid=""
/>
</msg>
字段说明:
x:纬度(latitude),WGS84 坐标系y:经度(longitude),WGS84 坐标系scale:地图缩放级别,通常 15 左右表示街道级视图label:完整地址描述,显示在消息气泡下方poiname:兴趣点(POI)名称,显示在消息气泡主标题
iPad 协议层将上述 XML 连同 MsgType=48 一起封装进微信私有协议包发出,服务端收到后会原样分发给对方。WechatApi 在云端托管了完整的 iPad 协议实现,开发者只需通过 HTTP POST 提交结构化 JSON 参数,无需关心底层协议细节,这也是 微信二次开发 最高效的路径。
接口调用参数详解
WechatApi 发送位置消息接口采用标准的 HTTP POST + JSON Body 方式,鉴权通过请求头 VideosApi-token 传入。以下是完整的参数说明表:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
appId | string | 是 | 设备 ID,即已登录的微信号实例标识,在控制台获取 |
toWxId | string | 是 | 接收方的微信 ID,个人号填 wxid_xxx,群聊填 xxx@chatroom |
latitude | float | 是 | 纬度,WGS84 坐标系,精度建议保留 4-6 位小数 |
longitude | float | 是 | 经度,WGS84 坐标系,精度建议保留 4-6 位小数 |
locationName | string | 是 | POI 名称,即消息气泡的主标题,如"人民广场" |
locationAddress | string | 否 | 详细地址,显示在气泡副标题,建议填写以提升用户体验 |
scale | int | 否 | 地图缩放级别,默认 15,范围 10-18 |
返回体结构(标准格式):
json{
"ret": 200,
"msg": "操作成功",
"data": {
"msgId": "1234567890123456789",
"clientMsgId": "987654321"
}
}
ret=200表示接口层调用成功,消息已投递至微信服务器msgId是微信侧分配的消息 ID,可用于后续消息撤回或日志追踪- 若
ret非 200,msg字段会给出具体错误描述,常见如"设备未登录"或"目标用户不存在"
Python 完整调用示例
下面以 Python requests 库为例,展示从坐标获取到消息发送的完整流程。实际使用时将 YOUR_TOKEN、YOUR_APP_ID、RECEIVER_WXID 替换为控制台中的真实值。
pythonimport requests
import json
# 接口配置
API_BASE = "https://api.wechatapi.net" # 示意地址,以控制台下发为准
ENDPOINT = "/message/sendLocation"
TOKEN = "YOUR_TOKEN" # VideosApi-token,控制台获取
APP_ID = "YOUR_APP_ID" # 设备 ID,控制台获取
def send_location(to_wxid: str, lat: float, lng: float,
name: str, address: str = "", scale: int = 15):
"""
向指定微信用户/群发送位置消息
:param to_wxid: 接收方 wxid 或群 chatroom id
:param lat: 纬度 (WGS84)
:param lng: 经度 (WGS84)
:param name: 地点名称
:param address: 详细地址(可选)
:param scale: 地图缩放级别,默认 15
"""
headers = {
"Content-Type": "application/json",
"VideosApi-token": TOKEN
}
payload = {
"appId": APP_ID,
"toWxId": to_wxid,
"latitude": lat,
"longitude": lng,
"locationName": name,
"locationAddress": address,
"scale": scale
}
resp = requests.post(
f"{API_BASE}{ENDPOINT}",
headers=headers,
json=payload,
timeout=10
)
result = resp.json()
if result.get("ret") == 200:
print(f"[OK] 消息已发送,msgId={result['data']['msgId']}")
else:
print(f"[ERR] 发送失败:{result.get('msg')}")
return result
# 示例:向某个好友发送"上海人民广场"位置
if __name__ == "__main__":
send_location(
to_wxid="wxid_xxxxxxxxxx",
lat=31.2304,
lng=121.4737,
name="人民广场",
address="上海市黄浦区人民大道 100 号",
scale=15
)
代码要点说明:
VideosApi-token放在请求头而非 URL 参数,避免 token 泄漏在访问日志中。appId对应控制台中某个已扫码登录的微信设备,一个 token 下可管理多个设备,通过appId区分。timeout=10是必要的防御措施,网络抖动时避免请求无限挂起阻塞业务主流程。- 返回体统一用
ret字段判断业务状态,不要仅依赖 HTTP 状态码(接口层 500 以下错误也会返回 HTTP 200)。
批量发送与自动化脚本示例
在门店通知、活动邀请等场景,往往需要向数百人批量发送位置消息。直接并发会触发微信的频控策略,正确做法是加入随机间隔:
bash# 使用 curl 快速验证单次调用(调试用)
curl -X POST "https://api.wechatapi.net/message/sendLocation" \
-H "Content-Type: application/json" \
-H "VideosApi-token: YOUR_TOKEN" \
-d '{
"appId": "YOUR_APP_ID",
"toWxId": "wxid_xxxxxxxxxx",
"latitude": 31.2304,
"longitude": 121.4737,
"locationName": "人民广场",
"locationAddress": "上海市黄浦区人民大道100号",
"scale": 15
}'
批量场景建议的 Python 控制逻辑:
pythonimport time
import random
# 待发送的用户列表(实际从数据库或 CRM 系统获取)
target_list = [
{"wxid": "wxid_aaa", "name": "张三"},
{"wxid": "wxid_bbb", "name": "李四"},
# ...更多用户
]
LOCATION = {
"lat": 31.2304,
"lng": 121.4737,
"name": "人民广场自提点",
"address": "上海市黄浦区人民大道100号B出口",
"scale": 15
}
for user in target_list:
result = send_location(
to_wxid=user["wxid"],
**LOCATION
)
if result.get("ret") == 200:
print(f"已发送给 {user['name']}")
# 随机等待 3-8 秒,模拟人工操作节奏,降低封号风险
time.sleep(random.uniform(3, 8))
这种"随机间隔"策略是 微信机器人开发 的基本规范:频率控制不仅是合规要求,也是保护设备账号长期稳定运行的必要措施。WechatApi 控制台还提供了设备健康度监控,可以实时查看当前设备的发送频率和风控状态。
坐标系选择与地址解析实操
这是开发者最容易踩坑的环节。微信位置消息使用 WGS84 坐标系(即 GPS 原始坐标),而国内地图服务(高德、百度)均使用偏移坐标系:
| 坐标系 | 来源 | 使用场景 |
|---|---|---|
| WGS84 | GPS 卫星原始 | 微信位置消息、国际标准 |
| GCJ-02(火星坐标) | 国家测绘局加密 | 高德地图、腾讯地图、Google 中国 |
| BD-09 | 百度二次加密 | 百度地图 |
实际操作建议:
- 如果坐标来自高德 API(如逆地理编码),需先将 GCJ-02 转换为 WGS84 再传入接口。网上有成熟的
coordTransform库可直接使用,无需手写转换公式。 - 如果坐标来自用户上传的带 GPS 信息的照片(EXIF),那已经是 WGS84,可直接使用。
- 腾讯地图 JavaScript API 返回的经纬度是 GCJ-02,同样需要转换。
- 若你的业务系统已存储了百度地图坐标,需经过 BD-09 → GCJ-02 → WGS84 两次转换。
locationName 和 locationAddress 字段建议从权威数据源获取,而不是让运营人员手工填写。推荐通过高德或腾讯地图的 POI 搜索 API 拿到地点名称和格式化地址,转换坐标后一并写入,这样接收方点击位置后看到的标注与周边地物名称一致,体验最佳。
常见问题与注意事项
1. 发送后对方收到的是文本而非位置气泡
这通常是 MsgType 参数被忽略或接口版本不对导致的协议降级。使用 WechatApi 无需手动指定 MsgType,接口内部会自动处理,如果出现此问题请检查是否调用了正确的位置消息专用端点,而非通用文本端点。
2. ret 返回 200 但对方没有收到消息
可能原因:接收方将你的账号拉黑,或你的账号被临时限制发送。可通过控制台的"消息回执"功能确认实际送达状态。WechatApi 支持 webhook 回调,可以监听消息状态变化。
3. 经纬度精度问题
纬度/经度建议保留至少 4 位小数(精度约 11 米),6 位小数可精确到约 0.1 米。过低的精度(如只有 2 位小数,误差约 1 公里)会导致接收方导航到错误位置,在物流和上门服务场景中尤为严重。
4. 群聊发送位置消息
toWxId 填群聊的 xxx@chatroom ID 即可,其他参数与单聊完全相同。群 ID 可通过 WechatApi 的群列表接口获取,也可以通过监听群消息的 webhook 回调中获得。
5. 设备登录态维护
位置消息发送依赖设备保持在线。WechatApi 提供了设备心跳保活机制和掉线自动通知(webhook),建议在业务系统中实现掉线告警和任务重试逻辑,避免因设备意外下线导致批量任务中断。生产环境可参考 微信 API 对接 文档中的高可用架构方案。
6. 账号安全与合规
通过 iPad 协议操作个人微信账号存在一定风险,建议遵循以下原则:发送频率不超过每分钟 10 条,避免在深夜(23:00-08:00)高频操作,消息内容与接收对象需有真实业务关联,避免发送无差别营销内容。WechatApi 控制台提供了频率限制配置项,可统一设置发送速率上限。
小结
微信发送位置消息接口的核心在于:正确使用 WGS84 坐标系、通过 HTTP POST + VideosApi-token 鉴权完成调用、以 appId 区分设备实例,并在批量场景中加入合理的随机间隔控制频率。WechatApi 基于 iPad 协议封装了完整的位置消息能力,开发者无需逆向微信协议或维护客户端实例,通过标准 REST 接口即可将位置消息能力集成到任何业务系统中。如需接入,可前往 控制台 注册设备、获取 token,详细接口文档见 开发文档。
