接入系统 Complication,补齐倒计时/自定义格式/28天累计/空气质量

字段 125 → 156 项。

Toybox.Complications(source/Comp.mc)
  这条路推翻了我之前几个「表盘做不到」的判断 —— 当时只查了 ActivityMonitor /
  UserProfile / Weather,漏了系统把这些作为 complication 发布出来:
    - 下一个日程(CIQ 确实没有日历 API,但有 CALENDAR_EVENTS complication)
    - 训练状态、完赛预测 ×4、配速预测 ×4、最近高尔夫得分
    - 本周跑步 / 骑行距离(按运动分类的,按天历史做不出来)
    - 第三方 App 1–5(CGM、补水、行情这类 App 发布的)
  需要 ComplicationSubscriber 权限。

其余补齐
  - 近 28 天累计:步数 / 卡路里 / 距离 / 楼层
  - 事件倒计时:设置里填 YYYY-MM-DD,显示还剩几天
  - 自定义时间格式、日期格式 1/2:单字母占位符(h/H/m/s/a/D/M/N/Y/y/w)
  - OWM 空气质量:AQI 等级 + 描述 + PM2.5 + PM10 + CO,走
    /data/2.5/air_pollution —— 那个接口在免费档就开放,不需要 One Call 订阅

运行时踩的坑
  - Complication.unit 不保证是 String(周跑步距离返回的就不是),直接调
    .length() 抛 Symbol Not Found。unit 和 shortLabel 都改成先 instanceof 判型。
  - 浮点 value 直接 toString 印成 "0.000000",统一格式化成一位小数。
  - 第三方 App 槽位每取一次就要走完整个迭代器,四个格子都选 App 时会走四遍。
    改成每帧只枚举一次,由 view 在绘制开始时调 Comp.beginFrame() 失效。

测试
  全字段验证的 harness 本身会触发看门狗(一次 onUpdate 里算 156 个字段),
  改成分批每帧 12 个。实际使用一帧只算 4 个,不受影响。
  156 项全部可渲染,零运行时错误;17 款设备全部编译通过。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-10 09:03:21 +08:00
parent 4d96ab0912
commit d9d45d983b
14 changed files with 651 additions and 19 deletions

View File

@@ -18,6 +18,10 @@
<string id="FldSeconds">Seconds</string>
<string id="FldSeconds0">Seconds (09)</string>
<string id="FldWeekCal">Week Number</string>
<string id="FldCustomTime">Custom Time Format</string>
<string id="FldDateFmt1">Date Format 1</string>
<string id="FldDateFmt2">Date Format 2</string>
<string id="FldCountdown">Event Countdown</string>
<string id="FldSteps">Steps</string>
<string id="FldStepsRound">Steps Rounded</string>
<string id="FldStepsToGo">Steps to Go</string>
@@ -42,6 +46,10 @@
<string id="FldFloorsWeek">Floors (Week to Date)</string>
<string id="FldFloors7d">Floors (Last 7 Days)</string>
<string id="FldActiveMin7d">Active Minutes (7 Days)</string>
<string id="FldSteps28d">Steps (28 Days)</string>
<string id="FldCal28d">Calories (28 Days)</string>
<string id="FldDist28d">Distance (28 Days)</string>
<string id="FldFloors28d">Floors (28 Days)</string>
<string id="FldHeartRate">Heart Rate</string>
<string id="FldRestingHr">Resting Heart Rate</string>
<string id="FldStress">Stress Score</string>
@@ -97,6 +105,24 @@
<string id="FldUvi">UV Index</string>
<string id="FldVisibility">Visibility</string>
<string id="FldDewPoint">Dew Point</string>
<string id="FldNextCal">Next Calendar Event</string>
<string id="FldTrainStatus">Training Status</string>
<string id="FldRace5k">Race Time (5k)</string>
<string id="FldRace10k">Race Time (10k)</string>
<string id="FldRaceHalf">Race Time (Half)</string>
<string id="FldRaceFull">Race Time (Marathon)</string>
<string id="FldPace5k">Pace (5k)</string>
<string id="FldPace10k">Pace (10k)</string>
<string id="FldPaceHalf">Pace (Half)</string>
<string id="FldPaceFull">Pace (Marathon)</string>
<string id="FldGolfScore">Last Golf Round Score</string>
<string id="FldRunWeek">Run Distance (Week)</string>
<string id="FldBikeWeek">Bike Distance (Week)</string>
<string id="FldApp1">App 1 (on watch)</string>
<string id="FldApp2">App 2 (on watch)</string>
<string id="FldApp3">App 3 (on watch)</string>
<string id="FldApp4">App 4 (on watch)</string>
<string id="FldApp5">App 5 (on watch)</string>
<string id="FldOwmTemp">OWM Temperature</string>
<string id="FldOwmMinMax">OWM Max/Min Temp</string>
<string id="FldOwmFeels">OWM Feels Like</string>
@@ -120,6 +146,11 @@
<string id="FldOwmMinMaxTmrw">OWM Min/Max Tomorrow</string>
<string id="FldOwmDayAfter">OWM Temp Day After</string>
<string id="FldOwmMinMaxD2">OWM Min/Max Day After</string>
<string id="FldOwmAqi">OWM Air Quality (AQI)</string>
<string id="FldOwmAqiText">OWM AQI Description</string>
<string id="FldOwmPm25">OWM PM2.5</string>
<string id="FldOwmPm10">OWM PM10</string>
<string id="FldOwmCo">OWM CO</string>
<string id="FldOwmCity">OWM City Name</string>
<string id="FldOwmUpdated">OWM Update Time</string>
<string id="FldCustom1">Custom Text 1</string>
@@ -127,7 +158,7 @@
<string id="FldCustom3">Custom Text 3</string>
<!-- On-face captions, in FieldTable.IDS order. -->
<string id="FieldLabels">,TIME,UTC,TZ1,TZ2,DATE,DATE,DATE,DAY,DAY,DAY,MON,MON,,WEEK,SEC,SEC,WEEK,STEP,STEP,TO GO,KCAL,ACAL,MIN,MOD,VIG,WEEK,DST,FLR,DESC,ASC,PUSH,PUSH,WEEK,7D,WEEK,7D,WEEK,7D,WEEK,7D,7D,HR,RHR,STRS,SPO2,RESP,BODY,MOVE,MOVE,WT,BMI,RCVR,VO2,VO2,BATT,DAYS,BATT,ALRM,MSG,DND,BT,SOLR,ALT,hPa,hPa,RISE,SET,SUN,SUN,MOON,MOON,CIVIL,NAUT,ASTR,BLUE,GOLD,GOLD,BLUE,CIVIL,NAUT,ASTR,TEMP,HI/LO,FEEL,HIGH,LOW,HUM,RAIN,WIND,WIND,WIND,WX,hPa,UVI,VIS,DEW,TEMP,HI/LO,FEEL,HIGH,LOW,WX,WX,HUM,hPa,VIS,WIND,WIND,WIND,GUST,RAIN,SNOW,CLD,RAIN,DEW,TMRW,TMRW,D+2,D+2,CITY,OWM,,,</string>
<string id="FieldLabels">,TIME,UTC,TZ1,TZ2,DATE,DATE,DATE,DAY,DAY,DAY,MON,MON,,WEEK,SEC,SEC,WEEK,TIME,DATE,DATE,DAYS,STEP,STEP,TO GO,KCAL,ACAL,MIN,MOD,VIG,WEEK,DST,FLR,DESC,ASC,PUSH,PUSH,WEEK,7D,WEEK,7D,WEEK,7D,WEEK,7D,7D,28D,28D,28D,28D,HR,RHR,STRS,SPO2,RESP,BODY,MOVE,MOVE,WT,BMI,RCVR,VO2,VO2,BATT,DAYS,BATT,ALRM,MSG,DND,BT,SOLR,ALT,hPa,hPa,RISE,SET,SUN,SUN,MOON,MOON,CIVIL,NAUT,ASTR,BLUE,GOLD,GOLD,BLUE,CIVIL,NAUT,ASTR,TEMP,HI/LO,FEEL,HIGH,LOW,HUM,RAIN,WIND,WIND,WIND,WX,hPa,UVI,VIS,DEW,CAL,TRN,5K,10K,HM,FM,5K,10K,HM,FM,GOLF,RUN,BIKE,APP1,APP2,APP3,APP4,APP5,TEMP,HI/LO,FEEL,HIGH,LOW,WX,WX,HUM,hPa,VIS,WIND,WIND,WIND,GUST,RAIN,SNOW,CLD,RAIN,DEW,TMRW,TMRW,D+2,D+2,AQI,AQI,PM2.5,PM10,CO,CITY,OWM,,,</string>
<string id="MetricSteps">Steps</string>
<string id="MetricCalories">Calories</string>