# 城市建筑贴纸

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

## 目录与素材架构

源素材位于 `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，并提供主动申请粗略定位入口。两端都可刷新或搜索手选，城市结果在进程内约缓存十分钟。

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

这条城市识别路径不会开启实时位置共享或后台定位，也不会把设备坐标发送给星线聊天服务；系统定位和逆地理服务按系统自身规则处理请求。实时共享属于用户明确开启的另一条数据流，见[消息与媒体](https://document.thestarline.cn/app/messaging-and-media.md)。

## 发送流程与竞态处理

用户选择城市后，客户端向 `/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`。发送媒体与消息引用的边界另见[消息与媒体](https://document.thestarline.cn/app/messaging-and-media.md)。

## 验证范围

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

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