Vela quick-app dev skill + knowledge base (S4 41mm)
- 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
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
# 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)
|
||||
```json
|
||||
{
|
||||
"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
|
||||
```js
|
||||
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):
|
||||
```js
|
||||
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)
|
||||
|
||||
1. **v1 (hap-toolkit 2.1.1, animated, missing icon):** install rejected — missing `/common/icon.png`. Fix: generate 192x192 png with PIL. (Real fix, verified.)
|
||||
2. **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.
|
||||
3. **v3:** removed `setInterval` arrow-closure animation, kept static `private` data → **same crash**.
|
||||
4. **v0.4 (user asked for incrementing 0.1/0.2-style versions on every fix):** stripped page to ONE `<text>`, NO `<script>` at all, added `display.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.
|
||||
5. **v0.5:** migrated to `aiot-toolkit` 2.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.**
|
||||
6. 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.
|
||||
7. **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.
|
||||
8. **v0.7:** config.designWidth changed to `"device-width"` (B2048 style). SAME crash.
|
||||
9. **v0.8:** `aiot release --enable-jsc --enable-protobuf` with 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/index` means the page dir is in the wrong place — it must be `src/Index/index.ux` (both toolkits).
|
||||
- `resolveFile` in `@hap-toolkit/packager` accepts `.mix`, `.ux`, `.ts` extensions.
|
||||
- Watch for escaped newlines (`\\n` vs `\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 own `dist/` — check `ls dist/`.
|
||||
- aiot build output is plain JS (not jsc) for pages in default `aiot build`; B2048 uses `aiot release --enable-jsc --enable-protobuf` — if a plain `build` rpk 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 `.rpk` into 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.
|
||||
Reference in New Issue
Block a user