- SKILL.md: toolchain, project structure, round-screen layout, TDD harness, input/crown findings, per-app notes - references: gitea-publish workflow, S4 session log, historical nyan-watch notes - README: overview + key facts
7.3 KiB
nyan-watch build log (2026-09-07, Watch S4 41mm)
Minimal resource-light app: one page, ASCII nyan cat on black, no permissions, no images besides icon.
Project at ~/nyan-watch/ (user's machine). As of this log the app is NOT yet verified launching on device — this file is the debugging record, not a proven example.
Status: v0.8 built (aiot release --enable-jsc --enable-protobuf, own release cert in sign/). STILL black-flashes (~0.02s, nothing visible). Remaining suspects: (1) release-cert trust on international S4 firmware — diff META-INF/CERT (ours 2.4KB self-signed vs HyperBili's 18KB); (2) designWidth "device-width" vs 466 in config; (3) S4 real-device-debugging OTA requirement (docs say partner-only); (4) watch quick-app partition state. Control experiment queued: sideload HyperBili's S4 rpk (~/hyperbili-s4.rpk, downloaded from hyperbili.astralsight.space) — if IT also fails, the watch/runtime is at fault, not our build.
src/manifest.json (v0.6+ shape — pages/index layout, aiot-toolkit)
{
"package": "com.ilias.nyanwatch",
"name": "NYAN",
"icon": "/common/icon.png",
"versionName": "0.7",
"versionCode": 7,
"minPlatformVersion": 1000,
"features": [{ "name": "system.router" }],
"config": { "logLevel": "log", "designWidth": "device-width" },
"deviceTypeList": ["watch"],
"display": { "backgroundColor": "#000000" },
"router": { "entry": "pages/index", "pages": { "pages/index": { "component": "index" } } }
}
src/common/icon.png — REQUIRED
192x192 png (rainbow stripes + cat box, drawn with PIL). Without this file the watch installer rejects the rpk with a generic "install failed" even though hap build succeeds.
src/app.ux
export default { onCreate() {}, onDestroy() {} }
src/Index/index.ux (page dir at src/Index/, NOT src/pages/Index/)
Static variant that actually launches on device (animation removed while bisecting a launch crash — the setInterval-with-arrow-closure version installed fine but black-flashed back to the selector):
<template>
<div class="page">
<text class="nyan">{{ frame }}</text>
<text class="hello">{{ title }}</text>
</div>
</template>
<script>
export default {
private: { frame: ",----,\n| |\n| o |\n|____|", title: "NYAN" }
}
</script>
<style>
.page { flex-direction: column; background-color: #000000; align-items: center; justify-content: center; }
.nyan { font-size: 16px; color: #ff7f00; font-weight: bold; }
.hello { font-size: 24px; color: #ffffff; font-weight: bold; margin-top: 10px; }
</style>
Animated variant (installs fine; launches unverified on device — suspect):
onInit() {
let i = 0;
this._timer = setInterval(() => { i = (i + 1) % FRAMES.length; this.frame = FRAMES[i]; }, 300);
},
onDestroy() { if (this._timer) clearInterval(this._timer); }
Chronology of this debugging session (read before repeating these steps)
- v1 (hap-toolkit 2.1.1, animated, missing icon): install rejected — missing
/common/icon.png. Fix: generate 192x192 png with PIL. (Real fix, verified.) - v2 (hap-toolkit, static cat+text, icon present, versionCode 2): installs, icon shows in app list, but launch = black flash ~0.2s then back to app selector.
- v3: removed
setIntervalarrow-closure animation, kept staticprivatedata → same crash. - v0.4 (user asked for incrementing 0.1/0.2-style versions on every fix): stripped page to ONE
<text>, NO<script>at all, addeddisplay.designWidth: 466→ same crash; this build briefly crashed the whole watch UI (watch self-restored, no reboot). Since even script-less pages crash, page code is exonerated — the package format/runtime is the suspect. - v0.5: migrated to
aiot-toolkit2.0.5 (Xiaomi's real toolchain; bundled official debug certs; jsc bytecode pipeline). Manifest restructured to the Songbird known-good shape:deviceTypeList:["watch"],features:[system.router],config:{logLevel:"log", designWidth:466}. Device verification pending. - In parallel, two research subagents swept English (GitHub/Reddit/XDA/mibandnotify) + Chinese sources (米坛社区 bandbbs.cn, luming.cool, CSDN) for anyone with a VERIFIED self-built quick app running on Watch S4/S3 hardware, known 黑屏闪退 causes, and example projects. Result: found two verified-real-device projects (see SKILL.md "Verified proven-real-device manifests"): CheongSzesuen/B2048 (AstroBox-published, designWidth "device-width", aiot release --enable-jsc --enable-protobuf) and hrk666666/tgwear-quickapp (minPlatformVersion 1100, aiot build --enable-custom-component). Neither uses hap-toolkit.
- v0.6 (aiot-toolkit 2.0.5, pages/index layout, static page, designWidth 466): STILL the same ~0.02s black flash with nothing visible. So layout+toolchain alone were not sufficient.
- v0.7: config.designWidth changed to
"device-width"(B2048 style). SAME crash. - v0.8:
aiot release --enable-jsc --enable-protobufwith own openssl cert (sign/private.pem + certificate.pem). Package now structurally identical to a proven-working S4 rpk (jsc, .style.bin/.template.bin, manifest-watch.json, same CERT/hash.json scheme — verified by diffing against HyperBili's circle_com.searchstars.hyperbilibili.rpk, cached at ~/hyperbili-s4.rpk). STILL the same ~0.02s black flash. This exonerates the package format entirely; next diagnostic is the HyperBili control install, then watch runtime/partition state or cert trust.
Also mined from the research: oryonatan repo has known install-error codes from community PRs/issues — error code 3 = storage full, error -6 = pre-installation failed (Redmi Watch 5); INJECT_EVENTS permission needed on Xiaomi/Redmi/POCO phones for the ADB deploy path.
Standing hypotheses for the flash (in order to try): (1) build with aiot release --enable-jsc --enable-protobuf (bytecode+protobuf format may be required by the S4 engine); (2) bump minPlatformVersion to 1100; (3) debug-signature rejection on international S4 firmware — diff META-INF/CERT against a community rpk that DOES run (download a B2048 AstroBox release rpk and compare); (4) Watch S4 may require the real-device-debugging firmware upgrade for third-party apps (official docs: partner-only OTA).
Tooling notes from this session
- Compiler error
编译失败:请确认manifest.json中配置的文件路径存在:Index/indexmeans the page dir is in the wrong place — it must besrc/Index/index.ux(both toolkits). resolveFilein@hap-toolkit/packageraccepts.mix,.ux,.tsextensions.- Watch for escaped newlines (
\\nvs\n) in multi-line ASCII strings — a doubled backslash renders art on one line. - aiot-toolkit prints output path as
~/.temp_nyan-watch/dist/...but actually writes to the project's owndist/— checkls dist/. - aiot build output is plain JS (not jsc) for pages in default
aiot build; B2048 usesaiot release --enable-jsc --enable-protobuf— if a plainbuildrpk black-flashes, try the release flags before suspecting page code. - Symptom guide: install rejected = manifest/icon validation (missing icon file); icon shows but app black-flashes on launch = see chronology above (with hap-toolkit: package format, not page code).
- Sideload path: drag
.rpkinto AstroBox (user has it installed). - AstroBox inspects the rpk zip tail for the string "toolkit" (build.txt JSON) to classify it as a quickapp — never strip META-INF/build.txt.