城市建筑贴纸
城市建筑贴纸根据用户识别或手选的城市提供一张本地建筑插画,再通过聊天服务登记成系统贴纸媒体。它与自定义图片贴纸分开管理,不占用户自定义贴纸数量。
目录与素材架构
源素材位于 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 可用性、跨网络发送与商店包仍须按测试和发布验收。