技术文档

城市建筑贴纸

城市建筑贴纸根据用户识别或手选的城市提供一张本地建筑插画,再通过聊天服务登记成系统贴纸媒体。它与自定义图片贴纸分开管理,不占用户自定义贴纸数量。

目录与素材架构

源素材位于 city-stickers:catalog.json 为版本 1 的城市白名单,svg 保存程序化矢量源,images 保存运行时 PNG,SHA256.json 为输出摘要,contact-sheet.png 供整体检查。当前目录共 44 城,包括北京、上海、香港、澳门、台北、东京、巴黎、伦敦、纽约等,覆盖以目录为准。

每个 CitySticker 含 id、countryCode、中文城市名、nameEn、aliases、landmark 和固定 asset 文件名。地标示例包括北京天坛祈年殿、成都安顺廊桥、济南超然楼、巴黎埃菲尔铁塔。素材是风格化建筑插画,不应当作测绘或地理证明。

build.py 定义城市、别名和独立建筑构图,使用 320×320 SVG 画布、统一色板和基础描边;构建时用 PyMuPDF 与 Pillow 导出 512×512 透明 RGBA PNG,并断言每张小于 512 KiB。客户端运行无需这些生成库。

城市识别与选择

贴纸面板第一格固定为城市入口,后面保持自定义贴纸顺序。打开面板会尝试设备城市解析与已登录服务的 /location/city IP 粗略城市。较快的 IP 可以先显示,设备城市成功后优先替换。界面分别标示“系统定位/城市级”“IP 粗略定位”与“手动选择”。

iOS 使用前台单次 CLLocationManager 请求,精度目标为三公里,经系统逆地理服务解析城市,十秒超时后结束。Android 在已有粗略定位权限时使用短时设备请求,在送系统 Geocoder 前将坐标量化到 0.02 度;未授权时保留 IP,并提供主动申请粗略定位入口。两端都可刷新或搜索手选,城市结果在进程内约缓存十分钟。

城市与别名匹配结合国家地区代码,香港、澳门的行政区域返回值有专门处理。不同国家的同名城市不应混用;未收录城市保持选择入口,不拿附近城市替代。两端名称规范化实现略有差异,新增别名应双端回归。

这条城市识别路径不会开启实时位置共享或后台定位,也不会把设备坐标发送给星线聊天服务;系统定位和逆地理服务按系统自身规则处理请求。实时共享属于用户明确开启的另一条数据流,见消息与媒体。

发送流程与竞态处理

用户选择城市后,客户端向 /stickers/city 发送 cityId,获得系统贴纸 media,再经正常单聊或群聊发送。iOS 校验媒体类型为 sticker、MIME 为 image/png 且大小在限制内;客户端只从打包目录加载预览,不接收任意素材路径。

准备请求绑定当前账号和目标聊天。用户离开原会话、退出账号、关闭面板或手动选择新城市时,旧请求的迟到结果应被取消或丢弃。iOS 使用操作 generation 与账号/会话复核,Android resolver 也使用 generation、协程取消和当前面板校验,防止把旧定位或旧媒体发入新会话。

新增城市与资产发布

新增城市时在 build.py 添加稳定 ID、国家地区码、别名、建筑名和对应构图,再执行素材构建。脚本会同步到 iOS Sources/CityStickers、Android assets/city-stickers 与聊天服务 assets/city-stickers。发布必须保持三端目录、ID 和 PNG 一致,并检查实际透明图与联系表;只改名称、复用不相关建筑不能算作新城市覆盖。

当前目录与跨端匹配差异

以下清单按2026-10-23工作区的版本1目录整理,城市ID是发送与资产去重使用的稳定标识。它不是覆盖所有城市的声明。

cityId 城市 国家或地区代码 建筑
beijing 北京 CN 天坛祈年殿
shanghai 上海 CN 东方明珠
guangzhou 广州 CN 广州塔
shenzhen 深圳 CN 平安金融中心
chengdu 成都 CN 安顺廊桥
chongqing 重庆 CN 洪崖洞
hangzhou 杭州 CN 雷峰塔
nanjing 南京 CN 中华门
suzhou 苏州 CN 虎丘塔
wuhan 武汉 CN 黄鹤楼
xian 西安 CN 钟楼
tianjin 天津 CN 天津之眼
qingdao 青岛 CN 圣弥厄尔教堂
xiamen 厦门 CN 世茂双子塔
changsha 长沙 CN 天心阁
harbin 哈尔滨 CN 圣索菲亚教堂
zhengzhou 郑州 CN 二七纪念塔
jinan 济南 CN 超然楼
lhasa 拉萨 CN 布达拉宫
fuzhou 福州 CN 三坊七巷
quanzhou 泉州 CN 开元寺双塔
dali 大理 CN 崇圣寺三塔
guilin 桂林 CN 日月双塔
guiyang 贵阳 CN 甲秀楼
hongkong 香港 HK 中银大厦
macau 澳门 MO 大三巴牌坊
taipei 台北 TW 台北101
tokyo 东京 JP 东京塔
osaka 大阪 JP 大阪城
kyoto 京都 JP 清水寺
seoul 首尔 KR N首尔塔
singapore 新加坡 SG 滨海湾金沙
kualalumpur 吉隆坡 MY 双子塔
bangkok 曼谷 TH 郑王庙
paris 巴黎 FR 埃菲尔铁塔
london 伦敦 GB 伊丽莎白塔
newyork 纽约 US 帝国大厦
sydney 悉尼 AU 悉尼歌剧院
dubai 迪拜 AE 哈利法塔
sanfrancisco 旧金山 US 金门大桥
seattle 西雅图 US 太空针塔
toronto 多伦多 CA 加拿大国家电视塔
rome 罗马 IT 斗兽场
istanbul 伊斯坦布尔 TR 加拉塔塔

iOS 对名称执行大小写、变音符和全半角折叠,再去空格,主要依靠目录中的明确别名;Android 另会移除空白及标点、末尾的 city/市,并要求最终只匹配一项。相同国家地区内的歧义别名可能使 Android 返回空,而 iOS 采用首先匹配的条目,新增素材时应在目录层避免歧义,不用修改匹配器去猜用户位置。

香港、澳门可由国家地区代码直接归入对应行政城市,也兼容系统返回CN且城市为明确已知别名的情况;“香港路”或“澳门附近”不应算香港澳门。国家地区代码缺失时仅靠名称可能不足以确认现实位置,UI保留来源提示和手选。系统城市更准确也不意味着其城市一定已收录。

城市结果只保留在进程内,账号退出会重置当前选择;Android 还按账号键及权限状态检查缓存,手选可使待完成定位失效。十分钟是复用选择的条件,不是持续采集位置的间隔。关面板、切账号、切聊天和点击刷新分别改变请求的当前性,扩展时应测试较慢设备结果和较快IP结果的相反到达顺序。

源码入口包括 city-stickers/build.py、iOS CitySticker/CityStickerSelection/CityStickerDeviceLocator/ChatEmojiPicker 以及 Android CitySticker/CityStickerLocation/CityStickerSheet。发送媒体与消息引用的边界另见消息与媒体。

验证范围

本次文档编写做了只读资产核验:主目录为 44 城,PNG 均为 512×512,文件范围为 15,043–36,569 字节,三端目录和全部 PNG 与源目录逐字节一致。这只证明工作区素材一致,不能证明线上服务或商店安装包已同步。

仓库测试还覆盖国家匹配、行政区域、设备优先、IP 回退、未知城市、缓存、取消和发送目标变化。本轮未运行这些测试,真实卫星定位、系统 Geocoder 可用性、跨网络发送与商店包仍须按测试和发布验收。

Markdown 原文完整文档文本