ZeppOS Development Skill File
1. Runtime Architecture
ZeppOS runs on a high-constraint embedded environment (QuickJS). The runtime is Not Node.js and Not a Browser.
Critical Constraints
- No Standard Library:
window,document,navigator,fs,path, andhttpmodules do not exist. - Memory Strictness: The runtime has a hard memory limit. Efficient memory management is mandatory.
- Event Loop: The runtime is single-threaded. Blocking the main thread (heavy loops) will freeze the watch UI and cause a crash (Watchdog Timeout).
API Level Targeting
- Always check
deviceInfofor screen shape (round/rect) and API level. - Use feature detection (
if (hmSensor...)) rather than assuming API availability.
2. Project Configuration (app.json)
Every project must define boundaries in app.json:
appType: Eitherapp(general application) orwatchface.permissions: Explicitly request access (e.g.,gps,heartrate). If not declared, the API will returnundefinedor fail.config: Define settings screens here if the app requires user configuration.
3. Application Lifecycle (Strict Pattern)
ZeppOS apps are lifecycle-driven. You must initialize resources in onInit and destroy them in onDestroy to prevent memory leaks.
Standard Boilerplate (ES6 Class Pattern)
App({
globalData: {}, // Share data between pages (use sparingly)
onCreate(options) {
// Called once when the app process starts.
// Initialize global non-UI resources here.
},
onDestroy(options) {
// CRITICAL: Release all resources, stop timers, close files.
// Failing to do this drains the watch battery.
}
});
Page Lifecycle
Page({
build() {
// Called when the page is created.
// Construct UI layout here.
// Note: Heavy computation here will delay screen appearance.
},
onShow() {
// Called when the page becomes visible.
},
onHide() {
// Pause animations or sensors here.
},
onDestroy() {
// Clean up page-specific widgets and listeners.
}
});
4. UI Development Standards
Coordinate System
- Origin (0,0) is typically the Top-Left corner.
- Screen Adaptation:
- Use
hmSetting.getDeviceInfo()to getwidthandheight. - Handle round screens (calculating center points for circular progress bars).
- Do not hardcode positions for the bottom of the screen; use
deviceInfo.height - offset.
- Use
Widget Management
- Creation:
const widget = hmUI.createWidget(widgetId, params) - Properties: Properties are set via a configuration object during creation.
- Cleanup: Always nullify widget references in
onDestroy.
Drawing & Refresh
- No Auto-Repaint: Unlike the web, changing a variable does not update the UI. You must explicitly call
setPropertyor manually redraw. - Canvas: If using
WIDGET_CANVAS, you must triggerredraw()manually.
5. Sensors & Async Handling
Sensor Reading
- Sensors are hardware resources. Use
registerlisteners to get data streams. - Rule: Never leave a sensor listener running in the background. Unregister it in
onDestroyoronHide.
Timers
- Use
timer.createTimer(interval, repeat, callback)instead ofsetInterval. setTimeoutis available but ZeppOS timers are optimized for the low-power state management.
6. Linting & Syntax (ESLint Config)
Strict linting prevents runtime crashes on the device.
module.exports = {
env: {
es6: true,
},
extends: "eslint:recommended",
parserOptions: {
ecmaVersion: 2020,
},
globals: {
// System
App: "readonly",
Page: "readonly",
deviceInfo: "readonly",
// Modules
hmUI: "readonly",
hmSensor: "readonly",
hmApp: "readonly",
hmBle: "readonly",
hmFS: "readonly",
hmSetting: "readonly",
// Utils
gettext: "readonly", // i18n
timer: "readonly",
// Config
__app_preset__dirname: "readonly",
},
rules: {
// Prevent memory leaks
"no-global-assign": "error",
"no-implicit-globals": "error",
// Enforce clean code
"no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
"prefer-const": "error",
// Browser globals that crash ZeppOS
"no-restricted-globals": [
"error",
"window",
"document",
"fetch",
"XMLHttpRequest",
"localStorage"
],
},
};
7. Common Pitfalls (Anti-Patterns)
- The Infinite Loop: Do not use
while(true)loops. Usetimeror event callbacks. - The Asset Oversize: Do not bundle large images. Compress assets. The app package size limit is strict (often < 1MB - 2MB depending on device).
- String Concatenation in Render: Avoid complex string manipulation inside the
build()method or animation loops; pre-calculate data. - Ignored Destroy: Assuming the OS cleans up. It does not. You must manually stop sensors and timers.