chore(sdk): 公开 SDK 仓初始化 — docs/ + LICENSE(MIT) + .gitignore + README
This commit is contained in:
commit
17a972d46f
5 files changed
+1702
No files matched your search
+31
@@ -0,0 +1,31 @@
|
|||||||
|
# ---- 构建产物 ----
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
|
||||||
|
# ---- 宿主测试二进制(SDK test_*.c 编译出的可执行;源码 .c 仍跟踪)----
|
||||||
|
test_ime_fix
|
||||||
|
test_meow_ui_config
|
||||||
|
test_meow_ui_theme
|
||||||
|
test_meow_ui_vol
|
||||||
|
test_meow_ui_widgets
|
||||||
|
test_notif_gesture
|
||||||
|
test_notif_open
|
||||||
|
test_notify_integration
|
||||||
|
test_notify_ipc
|
||||||
|
test_overlay_suppress
|
||||||
|
test_p1p2p3_repro
|
||||||
|
test_pinyin
|
||||||
|
test_sb_collapse
|
||||||
|
test_sdk_fixes
|
||||||
|
test_sdk_input_keys
|
||||||
|
test_ui_audio_host
|
||||||
|
test_umbrella
|
||||||
|
|
||||||
|
# ---- 示例 App 交叉二进制/生成物 ----
|
||||||
|
examples/hello/hello
|
||||||
|
examples/hello/render_test*.png
|
||||||
|
|
||||||
|
# ---- 杂项 ----
|
||||||
|
*.orig
|
||||||
|
*.log
|
||||||
|
*.tmp
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 MeowOS contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
# MeowOS SDK for HiBy R3 Pro II
|
||||||
|
|
||||||
|
MeowOS 应用框架 SDK 的**公开仓库**——面向第三方开发者,让你为运行 MeowOS 的 **HiBy R3 Pro II** 写自己的 App。
|
||||||
|
|
||||||
|
本仓库把 MeowOS 的 App 框架(`meow_ui`)与相关开发文档独立发布出来,自带示例与构建脚本,**自包含、开箱即构建**,不依赖 MeowOS 主仓。
|
||||||
|
|
||||||
|
> 快速上手见 [docs/APP_DEV_GUIDE.md](docs/APP_DEV_GUIDE.md);SDK 设计全量见 [docs/MEOW_APP_SDK.md](docs/MEOW_APP_SDK.md)。
|
||||||
|
|
||||||
|
## 设备与平台
|
||||||
|
|
||||||
|
| 项 | 值 |
|
||||||
|
|---|---|
|
||||||
|
| 设备 | HiBy(海贝)R3 Pro II |
|
||||||
|
| 架构 | MIPS32r2(**mipsel**,little-endian,soft-float) |
|
||||||
|
| 屏幕 | 480×720,RGB565(代码里颜色统一 24-bit `0xRRGGBB`,SDK 内部转 RGB565) |
|
||||||
|
| 可执行格式 | **静态** MIPS32r2 ELF(编译 `-Os -static`) |
|
||||||
|
| 底层系统 | MeowOS(Linux 系,非 Android) |
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
MeowOS-SDK/
|
||||||
|
├── sdk/ # meow_ui 应用框架静态库源码(自包含,可交叉 → sdk/meow_ui.a)
|
||||||
|
│ ├── meow_ui.h # 伞头(#include 聚合 include/ 子头;App 只 include 这个)
|
||||||
|
│ ├── include/ # 16 个模块子头 + meow_ipc.h / meow_font.h / meow_notif.h(协议/字体)
|
||||||
|
│ ├── meow_font.c # 预渲染位图字体运行时(meow_font.a 源码,自包含)
|
||||||
|
│ ├── build_sdk.sh # 交叉编译 meow_ui.a(mipsel 静态库,内含 meow_font.o)
|
||||||
|
│ └── test_*.c # SDK 宿主逻辑测试(test_host_stub.c 打桩,无硬件可跑)
|
||||||
|
├── examples/hello/ # 最小示例 App(meow_view 框架,多文件分层)
|
||||||
|
│ ├── app.c # main + 装配 + 事件分发(把 meow_ui_run 回调路由到各页)
|
||||||
|
│ ├── ui/ # 每页一个 view 文件(home/demo/list/full/chrome)
|
||||||
|
│ ├── logic/ # 纯 C 业务逻辑(不依赖 meow_ui.h,宿主可裸测)
|
||||||
|
│ └── build_hello.sh # 构建 hello(链 meow_ui.a + libz.a + -lpthread)
|
||||||
|
└── docs/
|
||||||
|
├── APP_DEV_GUIDE.md # 第三方开发上手指南(环境 → 最小 App → 构建打包 → 签名安装 → 调试)
|
||||||
|
└── MEOW_APP_SDK.md # SDK 设计全量规范
|
||||||
|
```
|
||||||
|
|
||||||
|
## 快速上手
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# 1) 构建 meow_ui.a(交叉)
|
||||||
|
cd sdk
|
||||||
|
./build_sdk.sh # 产出 sdk/meow_ui.a
|
||||||
|
|
||||||
|
# 2) 构建示例 App hello
|
||||||
|
cd ../examples/hello
|
||||||
|
./build_hello.sh # 产出 examples/hello/hello(静态 MIPS32r2 ELF)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 构建要求
|
||||||
|
|
||||||
|
- **交叉工具链**(mipsel musl 静态):MeowOS 开发机默认路径
|
||||||
|
`$HOME/Project/R3ProII/.tools/zig-mipsel-cc`(zig 包装,`--target=mipsel-linux-musleabi` soft-float)
|
||||||
|
与对应 sysroot(含 `libz.a`)。可用环境变量覆盖:`MEOW_CC` / `MEOW_SYSROOT`。
|
||||||
|
- GNU `ar`(归档 mipsel 对象,架构无关)。
|
||||||
|
- 宿主逻辑测试(无硬件,`gcc` + `test_host_stub.c` 打桩):
|
||||||
|
```sh
|
||||||
|
cd sdk
|
||||||
|
gcc -I. -Iinclude test_umbrella.c <各 sdk 源 .c> test_host_stub.c -lpthread -o test_umbrella
|
||||||
|
./test_umbrella
|
||||||
|
```
|
||||||
|
参考 [docs/APP_DEV_GUIDE.md §1.2](docs/APP_DEV_GUIDE.md)。
|
||||||
|
- 注意:改 SDK 源码(尤其 `meow_ui_theme`/`meow_widget` 结构)即 ABI 变化,**必须同步重编 `meow_ui.a` 与你的 App**。
|
||||||
|
|
||||||
|
## 与 MeowOS 主仓的关系
|
||||||
|
|
||||||
|
本仓库由 MeowOS 主仓(`MeowOS-For-R3P2`)经 `git subtree split` 拆出,只含公开的 SDK / 示例 / 文档:
|
||||||
|
|
||||||
|
- `sdk/` 对应主仓 `patch_v2/sdk/`,`examples/hello/` 对应主仓 `patch_v2/hello_app/`,`docs/` 对应主仓 `docs/APP_DEV_GUIDE.md` + `MEOW_APP_SDK.md`。
|
||||||
|
- **不含**主仓的系统组件(launcher / amsd / audiod / svc_* / netmgrd 等)、固件、签名工具、**密钥**。
|
||||||
|
- 本仓库中的 `build_sdk.sh` / `build_hello.sh` 已改造为**自包含**(`meow_ipc.h`/`meow_font.h`/`meow_notif.h`/`meow_font.c` 一律在 `sdk/` 内 vendored,不再依赖主仓 `meow_launcherd/`),与主仓内的同名脚本存在差异。
|
||||||
|
- SDK 增量同步(主仓 `patch_v2/sdk` 更新后再推本仓)的方法见主仓 `devdocs/` 与 `scripts/` 中的拆分记录。
|
||||||
|
|
||||||
|
## 许可证
|
||||||
|
|
||||||
|
MIT License——版权 **"MeowOS contributors"**,见 [LICENSE](LICENSE)。
|
||||||
@@ -0,0 +1,467 @@
|
|||||||
|
# MeowOS 第三方 App 开发指南(APP_DEV_GUIDE)
|
||||||
|
|
||||||
|
> 受众:想在 R3 Pro II / MeowOS 上发布自己 App 的第三方开发者(非 MeowOS 系统组)。
|
||||||
|
> 从零到上架动线:**环境 → 最小 App → 工程结构 → 构建打包 → 签名安装 → 部署调试 → SDK 能力 → 红线 → FAQ**。
|
||||||
|
> 权威口径:本文所有 API 以 `sdk/meow_ui.h` 为准;规范以 `MEOW_APP_SDK.md` 为准。凡与 `meow_ui.h` 不一致,以头文件为准。
|
||||||
|
> 配套文档(本公开 SDK 仓内):`docs/MEOW_APP_SDK.md`(SDK 设计全量)。
|
||||||
|
> 说明:本文为 **MeowOS-SDK 公开仓** 的开发者指南。文中引入但**未随本仓发布**的主仓内部文档/组件(`APPS.md`、`docs/MEOWOS_SPEC_REF.md`、`NOTIFICATION_SYSTEM.md`、`SYSTEM_SETTINGS.md`、`FRAMEWORK_DESIGN.md`、`devdocs/`、`qemu_env/`,以及签名工具 `patch_v2/meow_sign/meow_sign`、`patch_v2/meow_verify/meow_verify_host` 等)均位于 MeowOS 主仓 `MeowOS-For-R3P2`(内部)或设备固件内,仅用于说明系统行为与约定;本公开仓不含这些文件,也不含任何密钥。签名请走你自己生成的密钥对(见 §5)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. 一图看懂:App 是什么
|
||||||
|
|
||||||
|
一个 MeowOS App = **一个静态 MIPS32r2 ELF 二进制** + 一份 `app.json` 描述 + 若干资源,打包成 `.mpk`(= tar.gz),装到 TF 卡 `MeowAPPs/<package>/` 下。二进制**链接 `meow_ui.a` 静态库**,通过 `meow_ui.h` 声明的一套 API 拿屏幕、输入、控件、主题、字体、通知、音频——**绝不**自己 `open("/dev/fb0")` / `mmap` / `ioctl` / `open("/dev/input/event*")`。
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────┐
|
||||||
|
│ MeowAPP(你的业务,只调 meow_ui API)│
|
||||||
|
├──────────────────────────────┤
|
||||||
|
│ meow_ui.a(静态库,含 meow_font) │
|
||||||
|
│ 绘制/控件/图片/输入/主题/字体/通知/音频│
|
||||||
|
├──────────────────────────────┤
|
||||||
|
│ MeowOS 系统(launcher/amsd/audiod)│
|
||||||
|
└──────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
设备:480×720、RGB565(代码里颜色统一 24-bit `0xRRGGBB`,SDK 内部转 RGB565);文本字号约定 **28**(标题/状态栏)/ **20**(正文/按钮)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 开发环境准备
|
||||||
|
|
||||||
|
### 1.1 交叉工具链
|
||||||
|
|
||||||
|
需要一台 MeowOS 开发机(装好 mipsel musl 静态交叉工具链)。工具链**不随本公开仓分发**;以下为 MeowOS 开发机上现成的路径(可经 `MEOW_CC` / `MEOW_SYSROOT` 覆盖,或用你自己装好的 zig 交叉工具链):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$HOME/Project/R3ProII/.tools/zig-mipsel-cc # zig cc 包装(--target=mipsel-linux-musleabi, soft-float)
|
||||||
|
$HOME/Project/R3ProII/.tools/mipsel-linux-muslsf-cross/mipsel-linux-muslsf/ # sysroot(含 libz.a 等)
|
||||||
|
```
|
||||||
|
|
||||||
|
编译一个静态 MIPS 二进制(参考 `examples/hello/build_hello.sh`;`examples/hello/` 即本仓的 SDK 示例工程):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
MEOW_CC="$HOME/Project/R3ProII/.tools/zig-mipsel-cc" # 可覆盖;用你装好的 zig 交叉 cc
|
||||||
|
MEOW_SYSROOT="$HOME/Project/R3ProII/.tools/mipsel-linux-muslsf-cross/mipsel-linux-muslsf"
|
||||||
|
"$MEOW_CC" -Os -static -Wall -Wextra -I"<本仓>/sdk" -I. \
|
||||||
|
app.c ui/*.c logic/*.c \
|
||||||
|
"<本仓>/sdk/meow_ui.a" "$MEOW_SYSROOT/lib/libz.a" -lpthread -o myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
要点:
|
||||||
|
- 必须 `-static`(加载器只跑静态 MIPS32r2 ELF;软/硬浮点均可,见 `APPS.md §2.1`)。
|
||||||
|
- 链 `meow_ui.a`(`sdk/build_sdk.sh` 已把 `meow_font.o` 打进库里)+ `libz.a`(meow_font 的 inflate 依赖)+ `-lpthread`。
|
||||||
|
- `-I"<本仓>/sdk"` 引 `meow_ui.h`/`meow_ui_view.h` 等公共头(伞头 + `include/` 子头已在 `sdk/` 内);`-I.` 引你自己工程的头。
|
||||||
|
- 期望 `-Wall -Wextra` 零警告(参照 hello)。
|
||||||
|
|
||||||
|
### 1.2 宿主编译(离屏逻辑测试)
|
||||||
|
|
||||||
|
SDK 依赖板载 `/dev/fb0` 与字库,宿主机没有——但你可以**链真实 SDK 目标文件 + 打桩**来跑逻辑单测(参考 `sdk/test_host_stub.c`):
|
||||||
|
|
||||||
|
- `test_host_stub.c` 提供了 `meow_font_*` / `meow_ui_global_render` 等宿主桩(无 fb → 5×7 点阵回退;无字库 → `meow_font_load` 返回 -1)。
|
||||||
|
- 宿主可 `gcc` 直接编译 SDK 各 `.c` + 你的逻辑,跑纯 C 断言,**不碰硬件**(`hello` 的 `test_p1p2p3_repro` / `test_meow_ui_widgets` / `test_pinyin` 等都是这么跑的,宿主宿主验证全 PASS)。
|
||||||
|
- 注意:`logic/` 层要写**纯 C**(不依赖 `meow_ui.h`),才能裸宿主单测;`ui/` 层才碰 SDK。
|
||||||
|
|
||||||
|
### 1.3 qemu-mipsel 全系统仿真
|
||||||
|
|
||||||
|
需要跑全链路(含内核/fb)时可用 `qemu_env/scripts/run_halley6.sh`(Ingenic X1600E 全系统仿真):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
qemu_env/scripts/run_halley6.sh # 引导内核到串口控制台(默认)
|
||||||
|
qemu_env/scripts/run_halley6.sh -usbrootfs # 附加 USB rootfs 镜像
|
||||||
|
```
|
||||||
|
|
||||||
|
注意:必须带 `mem=64M`(脚本已内置,去掉会 early hang);`-usbrootfs` 的 USB 数据通路在 QEMU 里仍不完整(设备未枚举),rootfs 引导会失败——多数情况下它在宿主编译 + 真机验证之间用不上,**不是常规提交流水线**。
|
||||||
|
|
||||||
|
### 1.4 真机前置
|
||||||
|
|
||||||
|
- 出站靠 TF 卡;确保卡上至少有 `MeowAPPs/`(放 App)与 `MeowData/`(App 数据,首启自动建)。
|
||||||
|
- 设备跑 MeowOS 模式(默认)。看 `MEOWOS_SPEC_REF.md §5.4` 确认固件版本单点 `/etc/meowos_version`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 五分钟最小 App(以 hello 为模板)
|
||||||
|
|
||||||
|
最快路径:拷贝 `examples/hello/` 改包名与文案。逐文件讲。
|
||||||
|
|
||||||
|
### 2.1 app.json 全字段表
|
||||||
|
|
||||||
|
`app.json` **必填**,放 `MeowAPPs/<package>/` 根目录。示例(`examples/hello/` 示例工程的 `app.json` 在 MeowOS 主仓 `apps_assets/` 下,本公开仓未附带;下面给出可直接照抄的完整示例):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"name":"Hello App","exec":"/usr/data/mnt/sd_0/MeowAPPs/os.meow.hello/hello",
|
||||||
|
"package":"os.meow.hello","version":"0.1","framework":1,"immersive":1,"depends":"curl:optional"}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 字段 | 必填 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `name` | ✓ | 列表显示名。**当前仅 ASCII**(UTF-8 中文留待 v3,需完整 UTF-8→UTF-16 转换) |
|
||||||
|
| `exec` | ✓ | 可执行文件**绝对路径**,必须是**静态** MIPS32r2 ELF(指向 `MeowAPPs/<package>/` 内二进制) |
|
||||||
|
| `package` | — | 反域名权威标识(= app_id = 目录名 = `.mpk` 文件名茎,三者必须一致)。**`os.meow.*` 为系统保留前缀**(见 §5),第三方用自有前缀(如 `dev.*`)。缺失回退目录名;两者存在且不同 → WARN |
|
||||||
|
| `version` | — | 显示字符串(versionName 角色,如 `1.2.3-beta`,**不参与比较**) |
|
||||||
|
| `version_code` | — | **纯数字,安装/升级比较的唯一依据**;缺失 → 拒装;新版 < 已装 → 拒装(防降级),相等 → 允许重装。见 §5 |
|
||||||
|
| `author` | — | 保留字段 |
|
||||||
|
| `framework` | — | `1`=SDK 框架 App(用 `meow_ui.a`;**推荐**)。`0`/不写=裸自绘(不推荐,见红线) |
|
||||||
|
| `immersive` | — | `1`=沉浸。**注意(M2.89+)**:看门狗 `SIGUSR1` 只发给「**裸沉浸**」App(非 `framework=1`);SDK 框架 App 的返回走 `on_swipe`,别把 `SIGUSR1` 当返回键 |
|
||||||
|
| `background` | — | M4:无头后台服务注册权限(`service.<svc>` 服务二进制 = App 同目录 `<svc>` 文件) |
|
||||||
|
| `background_audio` | — | M4:后台播放保活(进程不冻结 + UI 冻结复用 §10.5 自抑);播放类 App 声明。如 `dev.player.music` 可声明 `background_audio=1` |
|
||||||
|
| `fullscreen` | — | app 级全屏:状态栏**收合至提示线** + 保留左缘返回/顶部提示线/下滑通知中心。activity 级用 `route.<id>.fullscreen` |
|
||||||
|
| `fonts` | — | 字库档位声明:`"full"` / `"gbk"` / `"common"`(默认 `common`≈4k;需大字库声明 `"full"`)。**注意**与 `"fonts":["<handle>"]`(应用自带字库句柄)同名二义,见 `MEOWOS_SPEC_REF §7 A-14` |
|
||||||
|
| `depends` | — | **二进制依赖声明**:`"curl,jq:optional,ffmpeg:required"`(JSON 值串)或行式 `depends=curl,jq:optional,ffmpeg:required`。逗号分项,每项 `<name>[:<mod>]`;无标注默认 required,也接受 `:opt`/`:req`;未知修饰符按 required 并 WARN。启动前查板载 `/usr/bin/<name>` 或卡上 `/usr/data/mnt/sd_0/MeowOS/opt/bin/<name>`(X_OK,命一即可)。required 缺失 → **不启动**(toast「缺依赖: <name>」);optional 缺失 → 仅 WARN 放行 |
|
||||||
|
| `icon` | — | 预留:应用列表图标 |
|
||||||
|
|
||||||
|
> ⚠️ 解析器极简(launcher/nyai 内实现):只匹配 `"name":`/`"exec":`/`"package":`/`framework`/`immersive`/`route.*`/`awake.*`/`service.*`/`background`/`background_audio`/`fullscreen`/`fonts`/`depends`,**不做 JSON 校验**(多行/单行均可),但字段名和引号写法要规范。
|
||||||
|
|
||||||
|
### 2.2 main 入口:SDK 初始化 + 事件循环 + 退出约定
|
||||||
|
|
||||||
|
看 `examples/hello/app.c`,核心骨架如下:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "meow_ui.h"
|
||||||
|
#include "meow_ui_nav.h"
|
||||||
|
#include "meow_ui_media.h"
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
static void on_sigterm(int s) { (void)s; meow_ui_request_exit(); } /* 干净退出:不画 BYE 直接退 */
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
meow_log(MEOW_LOG_INFO, "start");
|
||||||
|
|
||||||
|
/* ① SDk 初始化:开 fb / 读几何 / 载字库 / 建 back_buf。opts 宽高 0=自动读,宿主导跑用 480x720 */
|
||||||
|
meow_ui_opts o = { 480, 720 };
|
||||||
|
if (meow_ui_init(&o) != 0) { meow_log(MEOW_LOG_ERROR, "init failed"); return 1; }
|
||||||
|
|
||||||
|
/* ② 主题监听 + M3 导航上报 + 媒体会话(可选,但推荐接线) */
|
||||||
|
meow_theme_add_listener(NULL);
|
||||||
|
meow_ui_nav_init(); /* 读 MEOW_ACTIVITY / MEOW_CHAIN 初始化导航栈 */
|
||||||
|
meow_ui_media_init(NULL); /* app_id = env MEOW_LOG_APP */
|
||||||
|
meow_ui_media_on_playctl(demo_media_playctl);
|
||||||
|
|
||||||
|
signal(SIGTERM, on_sigterm); /* 退出兜底:SIGTERM → request_exit */
|
||||||
|
|
||||||
|
/* ③ 建各页 view(on_create 建控件/状态)+ 弹层实例(dialog/sheet 建一次,复用)*/
|
||||||
|
meow_view *home = home_view_create();
|
||||||
|
meow_view *full = full_view_create();
|
||||||
|
meow_view *demo = demo_view_create();
|
||||||
|
|
||||||
|
/* ④ 进入根页:activity_push + home on_enter → home_redraw */
|
||||||
|
meow_view_page_push(ACT_HOME);
|
||||||
|
|
||||||
|
/* ⑤ 事件循环回调表(on_key 物理键是系统语义,SDK 不下发业务确认/exit)*/
|
||||||
|
meow_ui_events ev = { app_on_key, app_on_tap, app_on_swipe, app_on_tick,
|
||||||
|
app_on_swipe_progress, app_on_touch_down, app_on_touch_move };
|
||||||
|
meow_ui_run(&ev); /* 阻塞,直到 meow_ui_request_exit() */
|
||||||
|
|
||||||
|
/* ⑥ 清理:释放 view(触发各页 on_destroy)+ 弹层 + shutdown */
|
||||||
|
meow_view_free(full); meow_view_free(demo); meow_view_free(home);
|
||||||
|
meow_dialog_free(g_dlg); meow_sheet_free(g_sheet);
|
||||||
|
meow_ui_shutdown();
|
||||||
|
meow_log(MEOW_LOG_INFO, "exit");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**退出约定**(`APPS.md §3.3`):
|
||||||
|
- 任意退出码均可,`exit(0/1)` 即可,**不要 `abort()` 留僵尸**——守护进程 `waitpid` 立即返回并恢复播放器。
|
||||||
|
- 用 `meow_ui_request_exit()` 或**根页左缘左滑**退出;**绝不监听物理键映射 exit**(见 §8 红线)。
|
||||||
|
- 不需要「恢复/清屏」——应用退出后系统恢复原界面,你清屏反而闪一下。
|
||||||
|
|
||||||
|
### 2.3 事件分发
|
||||||
|
|
||||||
|
`meow_ui_run` 给的平铺回调,在 `app.c` 里路由到当前页(见 `app.c` 的 `app_on_tap`/`app_on_swipe`/`app_on_tick`/`app_on_touch_*`)。典型分法:
|
||||||
|
|
||||||
|
- `on_tap` → 命中当前页控件(`meow_widget_hit` / `meow_listview_hit` / `meow_topappbar_hit` 等)。
|
||||||
|
- `on_swipe` → `LEFT`=返回(`meow_view_page_pop`,根页则 `meow_ui_request_exit`);`UP/DOWN`=滚动。
|
||||||
|
- `on_touch_down`/`on_touch_move` → 跟手拖动(slider / 列表 / 页面滚动)。
|
||||||
|
- `on_tick` → 动画/时钟(如进度条步进)。
|
||||||
|
- **`on_key` 仅供 SDK 内部状态,不含电源/音量/播放的确认/exit 语义**——别把它当输入。
|
||||||
|
- 左缘返回手势:边沿上报 `on_swipe_progress`,SDK 自动画顶部进度条(`meow_ui_swipe_hint`)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 工程结构约定
|
||||||
|
|
||||||
|
hello 的分层(`hello_internal.h` 里写得很清楚),建议照抄:
|
||||||
|
|
||||||
|
```
|
||||||
|
myapp/
|
||||||
|
├── app.c # main + 装配 + 事件分发(把 meow_ui_run 回调路由到各页)
|
||||||
|
├── myapp_internal.h # 跨 TU 共享声明(只 extern 声明,不定义)
|
||||||
|
├── ui/
|
||||||
|
│ ├── home/home.c # 每页一个 view 文件(持本页视图态)
|
||||||
|
│ ├── home/home.h
|
||||||
|
│ ├── demo/demo.c
|
||||||
|
│ ├── list/list.c # 页面内 CONTAINER 子视图(列表区块)
|
||||||
|
│ ├── full.c
|
||||||
|
│ └── common/chrome.c # 共享 chrome(TopAppBar / NavigationBar / FAB)
|
||||||
|
└── logic/
|
||||||
|
├── logic.h # 纯 C 接口(不依赖 meow_ui.h)
|
||||||
|
├── state.c # 计数/状态业务 + getter/setter
|
||||||
|
└── notify.c # 通知业务(此处才 include meow_ui.h 用 SDK 通知 API)
|
||||||
|
```
|
||||||
|
|
||||||
|
**分层契约**(`logic/logic.h`):
|
||||||
|
- ① UI→业务:只调 `logic_*` / `notify_*` 纯函数命令/getter,业务**不回调 UI**。
|
||||||
|
- ② 业务→UI:业务态变化经 `logic_set_listener(cb, ctx)` 的**可选 push 监听器**通知 UI 刷新(`home_state_listener` 示例)。
|
||||||
|
- ③ 每页 `meow_view` 的 `ctx` = **视图控制器**(biz-UI 绑定点),页面后续可把这层状态吸进控制器。
|
||||||
|
|
||||||
|
**视图框架 `meow_view`**(`sdk/meow_ui_view.h`):
|
||||||
|
- 生命周期钩子:`on_create → on_enter → (事件循环) → on_leave → on_destroy`,另有 `on_layout`/`on_draw`/`on_event`。均可 NULL。
|
||||||
|
- **页面即文件**:每页一个 `meow_view_create(id, MEOW_VIEW_ACTIVITY, &hooks, &ctrl)`,`id` 是你命名的稳定值(`ACT_HOME=0`/`ACT_FULL=1`/`ACT_DEMO=2`)。
|
||||||
|
- 页面切换统一走 `meow_view_page_push/pop/replace`(包装 activity 栈,**on_enter/on_leave 唯一入口**),App 不再分别调 `activity_push/pop`。
|
||||||
|
- 子视图嵌套:`meow_view_add_child` 挂 CONTAINER 子 view(如 demo 页的列表区块 `list.c`),嵌套生命周期由 SDK 递归驱动(随父页进出),无需 App 显式接管。
|
||||||
|
- `on_draw` 为回调、view 不缓存像素(非保留);重绘由 `meow_ui_invalidate` 触发。
|
||||||
|
- `meow_view_dispatch_event` 是「把语义事件注入当前页谓词子树路由」的入口(先子>父按 z 降序,命中即消费);未接线于 `meow_ui_run`,你可在 `on_tap`/`on_swipe` 里改用它做 SDK 原生路由。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 构建与打包
|
||||||
|
|
||||||
|
### 4.1 链接 meow_ui.a
|
||||||
|
|
||||||
|
见 §1.1 命令。`meow_ui.a` 由 `sdk/build_sdk.sh` 构建(内含 `meow_font.o`),改 SDK 源码后**重编 meow_ui.a 必须同步重编你的 App**(结构变化即 ABI 变化,见 `MEOWOS_SPEC_REF §3.4`)。
|
||||||
|
|
||||||
|
### 4.2 `.mpk` = tar.gz
|
||||||
|
|
||||||
|
`.mpk` 内容 = `app.json` + 二进制 + 资源(**不含 data/cache**,运行时按设备生成)。包名 = `.mpk` 文件名茎 = `app.json.package`(如 `os.meow.hello` → `os.meow.hello.mpk`)。
|
||||||
|
|
||||||
|
> **nyai 无独立 `pack` 命令**。两种出包:
|
||||||
|
> 1. **手工打包**(从 staging 目录,`meow_sign/README §2.2` 的口径):
|
||||||
|
> ```sh
|
||||||
|
> mkdir -p build/os.meow.xxx
|
||||||
|
> # 放 app.json + meow 二进制 + 资源;app.json.package == 目录名
|
||||||
|
> tar czf os.meow.xxx.mpk os.meow.xxx # .mpk 须在 tar 根(无 <pkg>/ 包裹 → 换包时注意)
|
||||||
|
> ```
|
||||||
|
> 2. **导出已装应用**:设备上 `nyai export <pkg> [out.mpk]`(打 `MeowAPPs/<pkg>/`,排掉 `*.pre_*`/`*.bak_*`/`logs/` 等运行残留)。
|
||||||
|
|
||||||
|
`.mpk` 内部结构:
|
||||||
|
|
||||||
|
```
|
||||||
|
os.meow.xxx.mpk (tar.gz)
|
||||||
|
├── app.json # package/exec/version(+version_code)/framework/immersive/background_audio/...
|
||||||
|
├── meow # 静态 MIPS32r2 ELF(exec 指向)
|
||||||
|
├── <资源文件> # 只读程序资源
|
||||||
|
└── <signature footer> # 仅签名过的包有(Ed25519 v2 184B;尾部追加)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 签名与安装分级
|
||||||
|
|
||||||
|
### 5.1 分级规则(`APPS.md 附录 §3` / 签名设计)
|
||||||
|
|
||||||
|
| 包 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| **`os.meow.*`(系统保留前缀)** | **必须有有效签名**;无签 / 验签失败 → 一律拒装(防伪造系统包名) |
|
||||||
|
| 第三方(自有前缀如 `dev.*`) | 无签可**直接装**(安装时告警);**有签必须验签**(失败拒装) |
|
||||||
|
| 所有包 | 验签 + **三重绑定** + **防降级**(见下) |
|
||||||
|
|
||||||
|
**防降级**:只看 `version_code`(纯数字)。新版 code < 已装 → 拒装;相等 → 允许重装;**code 缺失 → 拒装**(提示缺 version_code)。`version` 仅显示,不比较。
|
||||||
|
|
||||||
|
**三重绑定**(三方各司其职):
|
||||||
|
1. 签名 footer 的 `package` == `.mpk` 文件名茎(`meow_verify` 校验)——防改名。
|
||||||
|
2. 签名 footer 的 `package` == 解包 `app.json.package`(nyai / launcher 安装流校验)——防改 app.json。
|
||||||
|
3. `os.meow.*` 前缀 + 必须验签通过(nyai / launcher 安装流)——防无签冒充系统包。
|
||||||
|
|
||||||
|
### 5.2 开发者自签名流程(不泄露任何密钥材料)
|
||||||
|
|
||||||
|
> 工具:签名用 `meow_sign`(MeowOS 打包工具链成员,**宿主端、离线维护机**运行,不落设备、设备只持公钥;随 MeowOS 主仓打包工具分发,**本公开 SDK 仓不含**)。私钥**永不入库、永不落设备**。设备侧把关的是固件 `/usr/bin/meow_verify`(内嵌公钥数组,任一公钥通过即放行)。
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# ① 首次:生成/备份你自己的密钥对(仅一次;重复生成会令旧包全部失效)
|
||||||
|
./meow_sign keygen myapp.key # myapp.key 为你的私钥(0600,离线备份);myapp.key.pub 公钥
|
||||||
|
# 私钥离线备份、永不入库/不落设备;公钥 myapp.key.pub 可提交设备厂商固化进 meow_verify 公钥数组
|
||||||
|
|
||||||
|
# ② 打包(不含签名,纯 tar.gz;app.json.package 必须 == 目录名 == .mpk 文件名茎;version_code 单调递增)
|
||||||
|
tar czf os.meow.xxx.mpk os.meow.xxx
|
||||||
|
|
||||||
|
# ③ 签名(默认 v2 含被签时间戳)
|
||||||
|
./meow_sign sign os.meow.xxx.mpk myapp.key
|
||||||
|
|
||||||
|
# ④ 产签后自测(推荐)
|
||||||
|
./meow_sign verify os.meow.xxx.mpk myapp.key.pub
|
||||||
|
# 设备侧用 meow_verify_host 复验:与固件内嵌公钥同口径(主仓打包工具提供,未随本仓分发)
|
||||||
|
|
||||||
|
# ⑤ 装到设备:把 .mpk 放卡上 → nyai install
|
||||||
|
```
|
||||||
|
|
||||||
|
要点:
|
||||||
|
- `sign` 的 `.mpk` 文件名茎**必须等于包名**(否则 `meow_verify` 二次校验拒)。
|
||||||
|
- v2 块(184B,含时间戳)需 **2B+ 固件**;`--v1` 产物(180B)兼容旧 2A 固件——固件与工具链同版本发布即可避免兼容坑。
|
||||||
|
- 签名是**防误装 / 防伪造包名 / 防沿途篡改**,不是安全边界(见 `meow_sign/README §0`,诚实标注)。
|
||||||
|
- **MeowOS 系统主钥不随本公开 SDK 仓分发**。第三方开发者请**用自己的密钥对**(否则无法区分来源;用自己的私钥离线备份,公钥按需提交给设备厂商固化进 `meow_verify` 公钥数组)。泄露私钥即等于放弃对应包名的信任。
|
||||||
|
|
||||||
|
### 5.3 安装
|
||||||
|
|
||||||
|
- 设备端:`nyai install <pkg或文件.mpk>`(固件内置 `/usr/bin/nyai` 优先,或卡上 `MeowOS/opt/bin/nyai`)。同名 = 更新(旧目录备份 `.bak_<pid>`,`MeowData/<pkg>/{data,cache}` 保留,成功自清 `.bak`)。
|
||||||
|
- `nyai list` / `nyai info <pkg>` / `nyai remove <pkg>`(数据默认保留,`--purge` 连 MeowData 删)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 部署与调试
|
||||||
|
|
||||||
|
### 6.1 TF 卡目录
|
||||||
|
|
||||||
|
```
|
||||||
|
/usr/data/mnt/sd_0/
|
||||||
|
├── MeowAPPs/<package>/ # app.json + meow 二进制 + 资源(目录名 = app.json.package)
|
||||||
|
├── MeowData/<package>/{data,cache} # App 数据(首启自动建;exFAT 无软链,用 env 注入)
|
||||||
|
└── MeowOS/logs/<package>/ # App 日志(每次启动新文件 <ts>_<pid>.log)
|
||||||
|
```
|
||||||
|
|
||||||
|
启动时注入 env(SDK `meow_config_*`/`meow_ui_nav_init`/日志都读它):
|
||||||
|
`MEOW_DATA_DIR` / `MEOW_CACHE_DIR` / `MEOW_LOG_DIR` / `MEOW_LOG_APP`(=package) / `MEOW_LOG_LEVEL` / `MEOW_ACTIVITY` / `MEOW_CHAIN`(+ `MEOW_FONT_PNG`/`MEOW_FONT_IDX` 当前生效字体、`MEOW_FULLSCREEN`)。
|
||||||
|
|
||||||
|
### 6.2 面板上传
|
||||||
|
|
||||||
|
MeowPanel(外置 TF 卡 Web 面板,8080)可 `nyai install/export/remove`。**⚠️ 面板鉴权默认关**(内网信任模型)——`reboot/shutdown/ota/apps/删除/上传` 危险端点勿暴露公网。
|
||||||
|
|
||||||
|
### 6.3 am CLI(活动管理器)
|
||||||
|
|
||||||
|
`am` 是 amsd 的用户侧 CLI(固件 `/usr/bin/am`),连 `/usr/data/meow_ams.sock`(`--sock` / `env MEOW_AMS_SOCK` 覆盖):
|
||||||
|
|
||||||
|
```
|
||||||
|
am status # 在跑 App 表(pkg/状态/pid/运行时长/activity)
|
||||||
|
am list # 注册表 + 状态(pkg/name/state/pid/launches/crashes)
|
||||||
|
am history [pkg] # 事件历史(每 App 最近 8 条)
|
||||||
|
am start <pkg>[/<act>] # 拉起(root)
|
||||||
|
am kill <pkg> # 终止(SIGTERM 语义,root)
|
||||||
|
am rescan # 手动触发注册表重扫(卡刚挂载/热装后立即可见)
|
||||||
|
am resolve <pkg> <activity> # 路由决策(返回 CHAIN)
|
||||||
|
```
|
||||||
|
|
||||||
|
写操作(start/kill)**仅 root**。**已知坑(agent-250)**:开机早于卡挂载 → amsd 注册表扫空 + 永不重扫 → `am start` 报 `not registered`——用 `am rescan` 或等 3s 自愈/30s 合并重扫。
|
||||||
|
|
||||||
|
### 6.4 日志
|
||||||
|
|
||||||
|
- **App 日志**:`meow_log(lvl, fmt, ...)` 一行;SDK 写 `MeowOS/logs/<package>/<ts>_<pid>.log`(每次启动新文件,单文件 ≥2MB 自动续新,每 App 总量上限,无卡降级 stderr 不崩)。级别:`MEOW_LOG_DEBUG/INFO/WARN/ERROR`;`meow_log_set_level` 可选,默认 `INFO`。
|
||||||
|
- **崩溃日志**:系统级 `meow_crash` 捕获 + App 崩溃直报。真机看 `/usr/data/meow_*` 与 `MeowOS/logs/`。
|
||||||
|
- **离线跑**:`meow_launcherd --scan` 列应用;宿主跑逻辑单测看 stdout。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. SDK 能力速查表
|
||||||
|
|
||||||
|
(完整签名以 `sdk/meow_ui.h` 为准——下面每行都可交叉印证。)
|
||||||
|
|
||||||
|
### 7.1 控件库清单(一句话)
|
||||||
|
|
||||||
|
| 控件 | 一句 |
|
||||||
|
|---|---|
|
||||||
|
| `meow_btn_create`(Filled)/ `meow_btn_create_variant`(五型:FILLED/TONAL/OUTLINED/TEXT/ELEVATED) | 按钮;命中用 `meow_widget_hit`,选中/禁用走状态机 |
|
||||||
|
| `meow_slider_create` / `meow_switch_create` | 滑条/开关;`set/get` 取值 |
|
||||||
|
| `meow_list_create`(label-only)/ `meow_lazycolumn_create`/`meow_lazyrow_create` | 数据源回调 + 可见区虚拟化;`on_swipe` 里 `meow_list_scroll_by` 驱动滚动 |
|
||||||
|
| `meow_listview_create`(`W_LISTVIEW` 结构化列表) | 行=图标+标题+副标题+右侧操作+选中;`meow_listview_hit`/`meow_listview_tap_at` |
|
||||||
|
| `meow_textfield_create`(接 IME)+ `meow_textfield_activate` | 单行文本输入(阻塞 IME) |
|
||||||
|
| `meow_card_create` + `meow_card_set_content` / `meow_divider_create` / `meow_badge_create` | 卡片/分隔线/角标 |
|
||||||
|
| `meow_checkbox_create` / `meow_radio_create` | 勾选/单选(走 set_selected) |
|
||||||
|
| `meow_progress_create`(线性)/ `meow_progress_circular_create`(圆形) | 进度条(0-100,`-1`=不定) |
|
||||||
|
| `meow_fab_create` | 悬浮按钮 |
|
||||||
|
| `meow_topappbar_create`(标题+返回+动作)/ `meow_navigationbar_create`(底部导航)/ `meow_tabbar_create`(顶部分页) | 标题栏/导航栏/页签 |
|
||||||
|
| `meow_dialog_create`(CONFIRM/SELECT/INPUT/INFO)/ `meow_sheet_create`(BottomSheet) | 阻塞模态;点外/左缘返回=取消 |
|
||||||
|
| `meow_row_create`/`meow_column_create`/`meow_box_create` + `meow_layout_add`/`arrange` + `meow_layout_spacer` | 组合布局(固定尺寸子项) |
|
||||||
|
| `meow_widget_custom_create` | 自定义画布:App 给 render/hit 回调(同 `meow_widget`) |
|
||||||
|
| 通用 | `meow_widget_set_opts`(Modifier 式 Options)、状态机 `meow_widget_set_state`(ENABLED/SELECTED/FOCUSED/PRESSED)、`meow_widget_set_z(999)` 置顶、`meow_draw_custom_register` 注册非控件直绘 |
|
||||||
|
|
||||||
|
### 7.2 主题(MD3 / MIUIx × 明暗——适配义务)
|
||||||
|
|
||||||
|
- 主题 = **顶级风格族 `ui.style`(`MEOW_STYLE_MD3`/`MEOW_STYLE_MIUIx`)× 明暗 `display.theme`(light/dark/auto)**。
|
||||||
|
- **适配义务**:用 `meow_theme_get()` 取的**语义色**(`primary`/`surface`/`surfaceContainer`/`outline`/`bg`/`fg`/`accent`/`dim`…),**不要硬编码颜色**;明暗都要能看(`AUTO` 会来回切)。当前 MIUIx 仅换配色(状态栏图标未 per-style 换表,是已知缺口)。
|
||||||
|
- 字号约定:`font_title=28` / `font_body=20`(`meow_theme` 给默认)。
|
||||||
|
- 界面底 `meow_ui_set_page_bg(th->bg)`;状态栏高度 `meow_ui_statusbar_height()`(非全屏=28,全屏=0)用于内容 inset。
|
||||||
|
|
||||||
|
### 7.3 字体档位声明 + 应用字库接口
|
||||||
|
|
||||||
|
- 档位:`MEOW_FONT_TIER_COMMON`(默认 ≈4k)/ `GBK`(≈20k+)/ `FULL`(全字符集)。App 需大字库时 `app.json "fonts":"full"`,launcher 为你加载大字库。
|
||||||
|
- SDK:`meow_font_set_tier` / `meow_font_tier`;`meow_font_get_available_count` / `meow_font_enumerate`(读 `MeowOS/config/fonts/index`)/ `meow_font_select_by_id`(App 会话内固定用某套;丢失降级默认 + WARN)。
|
||||||
|
- **判缺字**:`meow_font_has_glyph(cp)` 预判当前字库是否含该码位——缺字自行回退/提示。
|
||||||
|
- 注意:App **未自带字库**则跟随系统 `font.file`(launcher 以 `MEOW_FONT_PNG`/`MEOW_FONT_IDX` env 注入);应用自带字库(`load_handle`)为**草案/未实现**。
|
||||||
|
|
||||||
|
### 7.4 IME(输入法)
|
||||||
|
|
||||||
|
- 模式:`MEOW_IME_ASCII` / `MEOW_IME_NUM` / `MEOW_IME_PINYIN`(中文拼音)。
|
||||||
|
- 阻塞:`meow_ui_text_input(ctx)`(回车=提交+关闭、ESC/点背景=取消);`meow_textfield_activate` 聚焦并打开阻塞 IME。
|
||||||
|
- 非阻塞:`meow_ui_text_input_async` + `meow_ime_active()`/`meow_ime_text()`/`meow_ime_composition()`(App 在 `on_tick` 里轮询)。
|
||||||
|
- **坑**:阻塞 IME 的内层轮询必须喂 `meow_ui_activity_ping`(SDK 已做)否则进度条/息屏卡死;键盘区背景快照/恢复(防残影);回显条是**实时输入回显**非候选,候选框留中文。
|
||||||
|
|
||||||
|
### 7.5 音频(meow_audio_*,独占 audiod)
|
||||||
|
|
||||||
|
- 链路:`meow_audio_open(rate, ch, fmt)` → 返回 `stream_id > 0` → `meow_audio_write(pcm, frames)`(**阻塞**,socket 背压)→ `meow_audio_pause(sid, paused)` → `meow_audio_close(sid)`。
|
||||||
|
- audiod 独占 `hw:0,0`;**后开流赢**,旧流收 `MSG_AUDIO_PREEMPTED` → 你的 `on_preempt` 回调 → 之后 `write` 返回负值,应重新 `open`。
|
||||||
|
- **audiod 不在 → `open` 返回 `MEOW_ERR_NOENT`(负值),不做隐式直开回退**;`MEOW_AUDIO_DIRECT=1` 仅调试用别依赖。
|
||||||
|
- `meow_audio_query(&state)` 读快照(活跃流/采样率/underrun/路由口/音量);`meow_audio_on_preempt(cb, ctx)` 注册被抢占回调。
|
||||||
|
- DAC 原生率跟随、无 SRC;格式归一(S16 直通 / S32 升位 / mono 复制);4.4/3.5 路由随插孔。
|
||||||
|
- 播放类 App 记得 `background_audio=1` + 媒体会话上报(见 §7.7)。
|
||||||
|
|
||||||
|
### 7.6 通知(meow_notify_* / MSG_NOTIFY)
|
||||||
|
|
||||||
|
- 声明:`meow_notify_register_type(cat)`(每 App ≤4 类型);发:`meow_notify_send(&n)`(返回 id);消:`meow_notify_cancel(id)`;进度:`meow_notify_update_progress(id, p)`。
|
||||||
|
- 配额:**每 App ≤4 类型;每类型活动 ≤4(满丢最旧);媒体单例(每 App 1 条,重发替换)**。
|
||||||
|
- `timeout_ms`:`>0`=过期毫秒数;`0`=不过期(直到 cancel);`-1`(ONGOING)=常驻。
|
||||||
|
- 负载 `meow_notify{n}`:`category`/`urgency`/`title`/`body`/`icon`/`timeout_ms`/`target_activity`(点击跳转 Activity 名,M3 导航预留)/`progress`。字段对齐 freedesktop `Notify()`。
|
||||||
|
- 走 IPC `MSG_NOTIFY`;10s 后自动转储到 TF `MeowOS/notifications/`(ring 10MB)。当前 SDK 内部维护活动表 + 日志落点;真实投递到通知中心 UI(launcher 渲染)为已落地链路。
|
||||||
|
|
||||||
|
### 7.7 媒体会话(meow_ui_media_*)
|
||||||
|
|
||||||
|
- `meow_ui_media_init(app_id)` / `meow_ui_media_on_playctl(cb)`(注册播放控制并启动后台接收线程)/ `meow_ui_media_meta(state, pos_ms, dur_ms, title, artist, album, artwork, lyric)`(上报元数据)/ `meow_ui_media_stop()`。
|
||||||
|
- 控制回调 `playctl(cmd, seek_ms)`:cmd `1`=播放 `2`=暂停 `3`=上一首 `4`=下一首 `5`=seek `6`=播放/暂停 toggle(物理播放键 164 恒发 6,由你对当前态翻转——**源是状态权威**)。物理上下曲:`meow_ui_media_sys_key(code)`。
|
||||||
|
- 声明 `MF_PLAYBACK` 的 App 首次上报 → 注册为媒体源;通知中心媒体卡片 / 主界面 Now Playing 据此显示。
|
||||||
|
- best-effort:无 launcher/socket 静默降级,绝不崩。
|
||||||
|
|
||||||
|
### 7.8 后台播放声明
|
||||||
|
|
||||||
|
- `app.json "background_audio":1`(M4 已落地):进程**不解冻** + **UI 冻结**复用 `§10.5 自抑`(比任务书 SIGSTOP 方案优)。launcher 有 `meow_bgplay` 保活表(退避 1/2/4/10s + 熔断 + 广播);应用列表标注「·后台」。依赖 `background` 字段 + `service.<svc>`。
|
||||||
|
- 声明后台播放后:无头时仍喂媒体会话 + 可继续 `meow_audio_*` 出声;退出时停线程/关流。
|
||||||
|
|
||||||
|
### 7.9 应用配置(meow_config_*)
|
||||||
|
|
||||||
|
- App 自有键值偏好,落 TF 数据目录(`MEOW_DATA_DIR`,无卡回退 `/tmp/meowcfg_<pid>`),**不占板载、无 schema**(与系统 `meow_settings_*` 区分)。
|
||||||
|
- `meow_config_set/get/int/bool/remove`;写 `<data>/<sanitized_key>.cfg`(key 只允许 `[A-Za-z0-9._-]`,上限 64)。返回码 `MEOW_CFG_OK(0)` / `NOENT(-2)` 等。
|
||||||
|
|
||||||
|
### 7.10 网络注意事项
|
||||||
|
|
||||||
|
- App 一般不需要联网;确需联网时**克制请求**(见 §8 风控式节制)。
|
||||||
|
- 系统层面(`netmgrd` 期 0/1):无 iptables 用户态 / 无 cgroup / 无 conntrack → **内核级每应用管控不可行**;主杠杆 = DNS 代理(域名级)+ 连接普查(inet_diag)+ **SDK 自愿通道**。App 走 SDK 自愿通道配合管控是后续方向;当前 App 如联网,请自律、尊重断网降级。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 规范与红线
|
||||||
|
|
||||||
|
> 详见 `APPS.md §1.3 / §3.3 / §3.4.1`、`MEOWOS_SPEC_REF §2.4 / §5.1`。以下为最要紧的违约原因。
|
||||||
|
|
||||||
|
1. **物理键禁映射返回/确认/OK/翻页**。物理键是系统资源:电源=息屏/亮屏/长按菜单/8s 强关,音量=调音量,播放/上下曲=媒体控制,返回=**触屏左滑**(`MEOW_SWIPE_LEFT`)/虚拟返回(非物理键)。**绝不用 `on_key(POWER)→exit` 这类映射**;`on_key` 仅供 SDK 内部状态。界面导航一律走触摸(返回钮/左缘左滑)。
|
||||||
|
2. **局部脏区刷新,别整屏重画**。控件/区域变化用 `meow_ui_invalidate(x,y,w,h)`(清底 + 按 z 重画相交绘制物 + 原子上屏),别 `meow_ui_flush`/整帧重画。**非控件直绘内容**(`meow_ui_text`/`meow_ui_fill_rect` 等)**必须 `meow_draw_custom_register` 注册**(声明 bbox + 绘制回调 + z),否则区域重画清底后会漏画(hello demo 的分区标题/slider 值文本就是典型注册示例)。滚动列表的视口裁剪由 SDK 全局负责(`W_LIST` 只画视口内行),别在 App 侧再做整屏。
|
||||||
|
3. **内存预算**。设备内存很紧(QEMU `mem=64M` 参考,rootfs ≤45MB)。避免大块分配、避免大字库双驻留(大字库按档装载、卸载旧 atlas)、别把卡上大文件 mmap 当运行必需——**运行期别依赖卡上资源**(见 §9 卡移除)。
|
||||||
|
4. **板载存储别乱写**。板载 `/usr/data` 只剩 ~10MB,是稳定框架 + KB 级设置。**App 数据一律写 `MeowData/<pkg>/`(TF,经 `MEOW_DATA_DIR`/`MEOW_CACHE_DIR` env)**;绝**不碰 NAND 分区 / mtd / `/data/recovery_all`**(恢复出厂,红线)。
|
||||||
|
5. **系统动作经专项服务**。App/组件不直连 `sys_do_reboot`、不写 NAND/mtd5;关机/重启/升级/回 HiBy 一律经 `meow_svc_power`(IPC)。App 一般无需做,但别绕过。
|
||||||
|
6. **风控式网络请求节制**。避免高频轮询/无限重试/后台自灌;尊重断网/弱网(优雅降级而非死循环/崩溃);与系统 netmgrd 管控共存(域名级,非内核 per-app)。
|
||||||
|
7. **别 destroy 别占用播放器/声卡**。不要 `killall hiby_player`(触发看门狗整机重启);不要 fork 长驻后台进程(退出要「真正退出」,否则 SIGCONT 后仍占屏抢输入)。
|
||||||
|
8. **`app.json` 别缺失 `version_code`**(拒装);别用 `os.meow.*` 前缀(除非你是系统签名 App)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. FAQ / 常见坑(真踩过的)
|
||||||
|
|
||||||
|
1. **脏区透传:局部刷新抹掉上层 chrome**。症状:拖动/点某个控件后,上层 FAB/标题栏被抹掉。根因:App 侧旧的「清底 + 只画单个控件」刷新。**修法**:改走 SDK `meow_ui_invalidate`(z 栈重画下层+上层),非控件直绘**注册 CUSTOM**(`meow_draw_custom_register`),否则清底后漏画。`meow_ui_paint_full()` 整帧按 z 重画兜底。
|
||||||
|
2. **IME 阻塞不喂 on_tick → 进度条/息屏卡死**。阻塞 `meow_ui_text_input`/`meow_textfield_activate` 的内层轮询必须喂 `meow_ui_activity_ping`(SDK 已做);键盘区用背景快照/恢复防残影;回显条是实时输入回显非候选。
|
||||||
|
3. **字体声明丢失 → 降级小字库**。`app.json "fonts":"full"` 丢了 / 大写不符 / 该档没生成 → 按 `common` 装载,生僻字缺字(`meow_font_has_glyph` 预判,回退或提示)。字体三件套(`font.png`+`font.idx`+`font.json`)缺一件 → 该套不进列表。
|
||||||
|
4. **热更新 `.new` + `mv` / 覆盖运行中程序的坑**。程序主体在卡上、运行中被覆盖/替换 → 访问旧代码页可能 **SIGBUS**。**修法**:升级用 `nyai install`(同包名 = 更新:旧目录备份 `.bak_<pid>` → 重启后替换 → 数据保留 → 成功自清 `.bak`);别自己 rm/mv 运行中的可执行文件。导出时 `*.pre_*`(热更备份)、`*.bak_*` 会被过滤。
|
||||||
|
5. **开机早于卡挂载 → amsd 注册表扫空**。`am start/list` 报 `not registered`(agent-250)。**修法**:`am rescan` 手动触发,或等 3s 快重试 / 30s 合并重扫自愈。
|
||||||
|
6. **`SIGUSR1` 误当返回键**。M2.89 起看门狗只对「**裸沉浸**」App(非 `framework=1`)发 `SIGUSR1`;SDK 框架 App 收到会被 SDK 的 `sigusr1_guard` 护栏记日志+吞掉。**别**为「返回」装 `SIGUSR1` handler;SDK 框架 App 返回走 `on_swipe`。
|
||||||
|
7. **goodix 幽灵触摸**。真机启动触摸尾部会发一段幽灵触摸(启动后 1.2–2.25s,见 `APPS.md §3.5`)。框架 App 走 `on_tap`/`on_swipe` 语义事件,launcher/SDK 已做 drain + 冷却;裸自绘 App 要自己加启动冷却(如 `COOLDOWN_MS`),否则会把幽灵当下按立即退出。
|
||||||
|
8. **音频:audiod 不在 / 被抢占**。`meow_audio_open` 返回负值(`MEOW_ERR_NOENT`)→ audiod 不在,**别隐式直开**(`MEOW_AUDIO_DIRECT=1` 仅调试)。被抢占后 `write` 返回负值 → 重新 `open`。长流卡死(~12s 停摆)是早期驱动/ring 问题,已由 audiod 加固(`period=1024×4` + 长流护栏)修掉;App 侧 `write` 阻塞背压,别一 flood 灌。
|
||||||
|
9. **物理键映射 exit**。旧 hello 曾 `on_key(KEY_POWER)→request_exit()`,违反红线——已要求删除。规范:电力键=息屏/亮屏,播放键=媒体控制,返回=左缘左滑。你的 App 别重蹈。
|
||||||
|
10. **`meow_ui.a` ABI 变化**。改 SDK(`meow_ui_theme`/`meow_widget` 结构)即 ABI 变化 → **必须同步重编 App**。本公开 SDK 仓把共享协议头 `meow_ipc.h`、`meow_font.h`、`meow_notif.h` 与 `meow_font.c` 一并在 `sdk/` 内 vendored(不依赖主仓 `meow_launcherd/`),`build_sdk.sh` 已是自包含独立库;运行时 App 只链 `meow_ui.a`,不含任何 launcher 符号。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. 上架检查单
|
||||||
|
|
||||||
|
- [ ] `app.json`:`package`(自有前缀)/`exec`(静态路径)/`version`+**`version_code`(单调递增)**/`framework:1`;需大字库加 `fonts`;播放类加 `background_audio`;依赖外部二进制加 `depends`。
|
||||||
|
- [ ] 二进制是**静态** MIPS32r2 ELF;链 `meow_ui.a` + `libz.a` + `-lpthread`;`-Wall -Wextra` 零警告。
|
||||||
|
- [ ] 颜色用主题语义色不硬编码;明暗都能看。
|
||||||
|
- [ ] 控件/区域刷新走 `meow_ui_invalidate`;直绘内容已 `meow_draw_custom_register`。
|
||||||
|
- [ ] 数据写 `MeowData/<pkg>/`,不写板载/NAND;退出干净 `exit(0)`;根页左滑 `meow_ui_request_exit`。
|
||||||
|
- [ ] `os.meow.*`(系统签名)vs 第三方(自有前缀,建议也签名防篡改)。打包 `tar czf`(或 `nyai export`,文件名茎=包名)→ `meow_sign sign` → 自测 `verify`/`meow_verify_host`。
|
||||||
|
- [ ] 真机冒烟:`am start`/`am status`/日志 `MeowOS/logs/<pkg>/`,卡移除/无网/断流降级不崩。
|
||||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user