#!/usr/bin/env python3 """扫描本机安装的 Connect IQ 设备,重写 manifest 的机型列表和 monkey.jungle。 筛选条件(三条都要满足): 1. 支持 watchFace 类型 2. Connect IQ >= 4.2 —— Toybox.Complications 是这个版本引入的, 本表盘的日历/训练状态/第三方 App 字段依赖它 3. 圆屏(deviceFamily 以 round- 开头) python3 tools/gen_devices.py 改写两处: manifest.xml 整块 monkey.jungle 每台设备的 resourcePath(图标按屏宽、启动图标按各自要求的尺寸) ⚠️ 结果取决于本机 SDK 里**装了哪些设备**。如果某台机器上少装了几款, 跑一遍会把它们从 manifest 里删掉。所以脚本会打印找到的数量, 提交前确认一下数字对不对(当前应为 55 款)。 图标资源的尺寸集合由本脚本算出后交给 tools/gen_icons.py 使用, 两者的 WIDTHS / LAUNCHER 必须一致,所以改完这里要跟着跑一遍 gen_icons.py。 """ import json import os import re from collections import defaultdict HERE = os.path.dirname(os.path.abspath(__file__)) ROOT = os.path.dirname(HERE) DEV = os.path.expanduser( "~/Library/Application Support/Garmin/ConnectIQ/Devices") def eligible(): """返回 [(设备id, 屏宽, 启动图标尺寸, 是否支持alpha), ...],按 id 排序。""" out = [] if not os.path.isdir(DEV): raise SystemExit("找不到设备目录:%s" % DEV) for d in sorted(os.listdir(DEV)): p = os.path.join(DEV, d, "compiler.json") if not os.path.exists(p): continue try: c = json.load(open(p)) except Exception: continue types = {t["type"] for t in c.get("appTypes", []) if isinstance(t, dict)} if "watchFace" not in types: continue if not str(c.get("deviceFamily", "")).startswith("round"): continue vers = [str(pn.get("connectIQVersion", "0")) for pn in c.get("partNumbers", [])] if not any(_ciq_ok(v) for v in vers): continue li = c.get("launcherIcon", {}) out.append((d, c["resolution"]["width"], li.get("width"), bool(c.get("alphaBlendingSupport")))) return out def _ciq_ok(v): try: a = [int(x) for x in v.split(".")[:2]] return a[0] > 4 or (a[0] == 4 and a[1] >= 2) except Exception: return False def write_manifest(devs): p = os.path.join(ROOT, "manifest.xml") s = open(p).read() body = "\n".join(' ' % d for d, _, _, _ in devs) block = " \n%s\n " % body s = re.sub(r" .*?", block, s, flags=re.S) open(p, "w").write(s) print("manifest.xml: 写入 %d 款机型" % len(devs)) def write_jungle(devs): L = ["project.manifest = manifest.xml", "", "base.sourcePath = source", "", "# resources-chn 是简体中文文案;目录名的 -chn 后缀就是语言标记。", "base.resourcePath = resources;resources-chn", "", "# 下面每台设备再挂两棵资源树,都由 tools/gen_icons.py 生成:", "# resources-icons-<屏宽> 按该屏幕像素网格光栅化的日出/日落/天气图标", "# resources-launcher-<尺寸> 该机型要求尺寸的启动图标", "# 这一整段由 tools/gen_devices.py 生成,不要手改。", ""] for d, w, li, _ in devs: L.append("%s.resourcePath = $(base.resourcePath)" ";resources-icons-%d;resources-launcher-%d" % (d, w, li)) L += ["", "base.excludeAnnotations = release"] open(os.path.join(ROOT, "monkey.jungle"), "w").write("\n".join(L) + "\n") print("monkey.jungle: 写入 %d 条资源路径" % len(devs)) def main(): devs = eligible() if not devs: raise SystemExit("一款符合条件的机型都没找到,请检查 SDK 设备是否已安装") widths = defaultdict(set) for _, w, _, alpha in devs: widths[w].add(alpha) print("符合条件的机型:%d 款" % len(devs)) print("需要的图标屏宽:%s" % sorted(widths)) print("需要的启动图标尺寸:%s" % sorted({li for _, _, li, _ in devs})) for w in sorted(widths): if len(widths[w]) > 1: print(" ⚠️ %dpx 同时存在支持/不支持 alpha 的机型," "图标按硬边生成" % w) write_manifest(devs) write_jungle(devs) print("\n接着跑:python3 tools/gen_icons.py") if __name__ == "__main__": main()