|
| 1 | +# CardputerZero App Submission Guide |
| 2 | + |
| 3 | +This guide describes the current path for publishing an app to the CardputerZero on-device AppStore. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The preferred publishing path is the `czdev` CLI from [CardputerZero-AppBuilder](https://github.com/m5stack/CardputerZero-AppBuilder). Developers publish an installable `.deb`; `czdev` validates the package, pushes it to `CardputerZero/packages` through Git LFS, and opens a Pull Request for maintainer review. After merge, the packages repository updates the APT index and this Hub syncs `generated/registry.json` from package metadata. |
| 8 | + |
| 9 | +Short flow: |
| 10 | + |
| 11 | +1. Develop the app in your own GitHub repository. |
| 12 | +2. Build an ARM64 Debian `.deb` with APPLaunch-compatible files. |
| 13 | +3. Validate the package and store assets locally. |
| 14 | +4. Run `czdev login` once. |
| 15 | +5. Run `czdev publish --deb <package>`. |
| 16 | +6. Review the generated Pull Request in `CardputerZero/packages`. |
| 17 | +7. Wait for maintainer approval, package-index rebuild, and Hub registry sync. |
| 18 | + |
| 19 | +Only apps whose registry review status is `approved` are installable from the on-device AppStore. |
| 20 | + |
| 21 | +## Install And Check `czdev` |
| 22 | + |
| 23 | +Install prerequisites before building or publishing. |
| 24 | + |
| 25 | +macOS: |
| 26 | + |
| 27 | +```bash |
| 28 | +brew install cmake pkg-config sdl2 sdl2_image sdl2_mixer freetype git-lfs dpkg |
| 29 | +``` |
| 30 | + |
| 31 | +Debian or Ubuntu: |
| 32 | + |
| 33 | +```bash |
| 34 | +sudo apt install -y build-essential cmake pkg-config \ |
| 35 | + libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libfreetype-dev \ |
| 36 | + git-lfs dpkg |
| 37 | +``` |
| 38 | + |
| 39 | +Build `czdev` from source: |
| 40 | + |
| 41 | +```bash |
| 42 | +git clone --recursive git@github.com:m5stack/CardputerZero-AppBuilder.git |
| 43 | +cd CardputerZero-AppBuilder |
| 44 | +cargo build --release -p czdev |
| 45 | +./target/release/czdev doctor |
| 46 | +``` |
| 47 | + |
| 48 | +If the repository was cloned without submodules: |
| 49 | + |
| 50 | +```bash |
| 51 | +git submodule update --init --recursive |
| 52 | +``` |
| 53 | + |
| 54 | +You can also download a prebuilt `czdev` from the AppBuilder GitHub Releases page and put it on `PATH`. After installation, run: |
| 55 | + |
| 56 | +```bash |
| 57 | +czdev doctor |
| 58 | +``` |
| 59 | + |
| 60 | +The doctor output is the source of truth for missing local desktop-development dependencies. |
| 61 | + |
| 62 | +Useful development commands: |
| 63 | + |
| 64 | +```bash |
| 65 | +czdev list . |
| 66 | +czdev run examples/hello_cz |
| 67 | +czdev watch examples/hello_cz |
| 68 | +czdev deploy --host pi@<device-ip> --deb build/my_app_1.0.0_arm64.deb |
| 69 | +``` |
| 70 | + |
| 71 | +## Package Requirements |
| 72 | + |
| 73 | +The `.deb` must install an APPLaunch application under `/usr/share/APPLaunch`. |
| 74 | + |
| 75 | +Required package content: |
| 76 | + |
| 77 | +- `usr/share/APPLaunch/applications/<app>.desktop` |
| 78 | +- an executable or wrapper under `usr/share/APPLaunch/bin/` |
| 79 | +- a square PNG icon under `usr/share/APPLaunch/share/images/` |
| 80 | +- any required fonts or assets under `usr/share/APPLaunch/share/` |
| 81 | + |
| 82 | +The `.desktop` entry must include at least: |
| 83 | + |
| 84 | +```ini |
| 85 | +[Desktop Entry] |
| 86 | +Name=MyApp |
| 87 | +Exec=bin/myapp |
| 88 | +Terminal=false |
| 89 | +Icon=share/images/myapp.png |
| 90 | +Type=Application |
| 91 | +``` |
| 92 | + |
| 93 | +Use `Terminal=false` for GUI apps. Put arguments, working-directory changes, and framebuffer environment setup in a wrapper script rather than in `Exec`. |
| 94 | + |
| 95 | +## Store Metadata And Assets |
| 96 | + |
| 97 | +Your app source repository should include an `app-builder.json` with a `store` section: |
| 98 | + |
| 99 | +```json |
| 100 | +{ |
| 101 | + "package_name": "my-app", |
| 102 | + "app_name": "My App", |
| 103 | + "store": { |
| 104 | + "summary": "Short user-facing summary.", |
| 105 | + "categories": ["Utilities"], |
| 106 | + "icon": "share/images/my-app.png", |
| 107 | + "screenshots": [ |
| 108 | + "store/screenshots/main.png", |
| 109 | + "store/screenshots/detail.png", |
| 110 | + "store/screenshots/settings.png", |
| 111 | + "store/screenshots/confirm.png" |
| 112 | + ], |
| 113 | + "locales": { |
| 114 | + "zh-CN": { |
| 115 | + "title": "我的应用", |
| 116 | + "summary": "简短中文简介。", |
| 117 | + "description": "面向中文用户的说明。" |
| 118 | + }, |
| 119 | + "en": { |
| 120 | + "title": "My App", |
| 121 | + "summary": "Short English summary.", |
| 122 | + "description": "English description for users." |
| 123 | + }, |
| 124 | + "ja": { |
| 125 | + "title": "マイアプリ", |
| 126 | + "summary": "短い日本語の説明。", |
| 127 | + "description": "日本語ユーザー向けの説明。" |
| 128 | + } |
| 129 | + } |
| 130 | + } |
| 131 | +} |
| 132 | +``` |
| 133 | + |
| 134 | +Screenshots submitted to AppStore should be exactly four clean 320 x 170 images of the app framebuffer. Do not include emulator chrome, device frames, desktop background, black padding, or scaled margins. |
| 135 | + |
| 136 | +Package metadata copied into `CardputerZero/packages` must use paths relative to `pool/main/<package>/`, such as: |
| 137 | + |
| 138 | +```json |
| 139 | +{ |
| 140 | + "icon": "my-app.png", |
| 141 | + "screenshots": [ |
| 142 | + "screenshots/main.png", |
| 143 | + "screenshots/detail.png", |
| 144 | + "screenshots/settings.png", |
| 145 | + "screenshots/confirm.png" |
| 146 | + ], |
| 147 | + "author": { |
| 148 | + "github": "developer-github-id", |
| 149 | + "display_name": "Developer Name", |
| 150 | + "website": "https://example.com" |
| 151 | + }, |
| 152 | + "published_at": "2026-05-14T23:20:55+08:00", |
| 153 | + "updated_at": "2026-05-14T23:20:55+08:00" |
| 154 | +} |
| 155 | +``` |
| 156 | + |
| 157 | +`published_at` and `updated_at` must be ISO 8601 timestamps with seconds and an explicit timezone. Keep `published_at` stable after first release. Update `updated_at` when the package, screenshots, icon, description, permissions, or review status changes. |
| 158 | + |
| 159 | +## Mandatory Prepublish Check |
| 160 | + |
| 161 | +Before publishing, run the strict prepublish check from the `cardputer-app-publish` skill checkout: |
| 162 | + |
| 163 | +```bash |
| 164 | +python3 /path/to/cardputer-app-publish/scripts/prepublish_check.py \ |
| 165 | + --deb build/my_app_1.0.1_arm64.deb \ |
| 166 | + --app-dir . |
| 167 | +``` |
| 168 | + |
| 169 | +Treat every `ERROR` as a blocker. The check verifies: |
| 170 | + |
| 171 | +- `app-builder.json` exists and has a `store` section. |
| 172 | +- `store.summary`, `store.categories`, `store.icon`, and screenshots are present. |
| 173 | +- source icon and screenshots exist; the icon is a square PNG. |
| 174 | +- `.deb` control fields include `Package`, `Version`, `Architecture=arm64`, and `Maintainer`. |
| 175 | +- the `.deb` contains an APPLaunch `.desktop` entry with `Name`, `Exec`, and `Icon`. |
| 176 | +- the desktop `Icon` resolves to a square PNG inside the package. |
| 177 | +- the desktop `Exec` target exists inside the package when it is absolute or APPLaunch-relative. |
| 178 | + |
| 179 | +If the source icon is missing during a non-interactive publish handoff, generate one, rebuild the package, and rerun the check. Do not publish a `.deb` whose APPLaunch icon is missing. |
| 180 | + |
| 181 | +## Publish With `czdev` |
| 182 | + |
| 183 | +Login once: |
| 184 | + |
| 185 | +```bash |
| 186 | +czdev login |
| 187 | +``` |
| 188 | + |
| 189 | +This uses GitHub OAuth Device Flow and stores the token at `~/.config/czdev/token`. |
| 190 | + |
| 191 | +Check the next version when updating an existing package: |
| 192 | + |
| 193 | +```bash |
| 194 | +czdev bump --deb build/my_app_1.0.0_arm64.deb |
| 195 | +``` |
| 196 | + |
| 197 | +Publish: |
| 198 | + |
| 199 | +```bash |
| 200 | +czdev publish --deb build/my_app_1.0.1_arm64.deb |
| 201 | +``` |
| 202 | + |
| 203 | +`czdev publish` performs preflight checks, verifies that the package version is newer than the published version, pushes the `.deb`, `meta.json`, icon, and screenshots through Git LFS, and opens a Pull Request against `CardputerZero/packages`. |
| 204 | + |
| 205 | +To remove one of your own package versions: |
| 206 | + |
| 207 | +```bash |
| 208 | +czdev unpublish my-app --version 1.0.1 |
| 209 | +``` |
| 210 | + |
| 211 | +## Device Validation |
| 212 | + |
| 213 | +Before opening or merging the package Pull Request, test on a real CardputerZero: |
| 214 | + |
| 215 | +- the package installs with `dpkg -i` or APT. |
| 216 | +- the app appears in APPLaunch with the expected icon and title. |
| 217 | +- the app launches from APPLaunch and returns cleanly. |
| 218 | +- GUI fits the 320 x 170 screen. |
| 219 | +- CJK text uses CJK-capable fonts and shows no missing-glyph boxes. |
| 220 | +- short Esc returns one level or closes a modal; long Esc or Home exits safely. |
| 221 | +- framebuffer code respects `LV_LINUX_FBDEV_DEVICE` and does not hard-code `/dev/fb0`. |
| 222 | +- permissions, network behavior, external hardware, and background services match the submitted metadata. |
| 223 | +- uninstall removes the APPLaunch entry. |
| 224 | + |
| 225 | +## Pull Request Review |
| 226 | + |
| 227 | +The Pull Request should explain: |
| 228 | + |
| 229 | +- what the app does. |
| 230 | +- which device and OS image were tested. |
| 231 | +- whether it was installed from the submitted `.deb`. |
| 232 | +- permissions, network behavior, external hardware, and background services. |
| 233 | +- privacy behavior and data retention. |
| 234 | +- known limitations. |
| 235 | +- links to source, release, package, screenshots, and test logs when available. |
| 236 | + |
| 237 | +CI passing does not guarantee listing. Maintainers still review policy, risk, device safety, user experience, and metadata quality. After approval and merge, the package repository rebuilds the APT index. This website then syncs package `meta.json` into `generated/registry.json`; the device AppStore sees the app after refresh. |
| 238 | + |
| 239 | +## Troubleshooting |
| 240 | + |
| 241 | +| Problem | Fix | |
| 242 | +| --- | --- | |
| 243 | +| `czdev` not found | Build it from AppBuilder or download a release binary, then put it on `PATH`. | |
| 244 | +| `czdev doctor` reports missing packages | Install the packages it reports for your OS, then rerun `czdev doctor`. | |
| 245 | +| `git-lfs not installed` | Install Git LFS and run `git lfs install`. | |
| 246 | +| `dpkg-deb` missing | macOS: `brew install dpkg`; Debian/Ubuntu: `sudo apt install dpkg`. | |
| 247 | +| `email_mismatch` | Set the `.deb` `Maintainer` email to match your GitHub account or noreply address. | |
| 248 | +| `version_not_newer` | Bump the package version, rebuild the `.deb`, and rerun the prepublish check. | |
| 249 | +| `store.icon is required` | Add or generate a square PNG icon, rebuild the `.deb`, and rerun the strict check. | |
| 250 | +| App appears online but cannot install | Confirm registry `review.status` is `approved`, package URL is reachable, package name is correct, and MD5 matches the `.deb`. | |
| 251 | + |
| 252 | +See [Developer Submission Policy](#/documents/developer-submission-policy), [Registry And Web UI Requirements](#/documents/appstore-registry-requirements), and [User And Developer Agreement](#/documents/user-agreement) for the policy rules behind these decisions. |
0 commit comments