App Package
This page describes the structure of a runtime app package, its manifest fields, the resource descriptor, and the scan and install rules.
Overview
An app package uses manifest.json to describe package metadata and the runtime entry; the profile.json under the runtime resource directory is the system_core resource descriptor, whose root points to the real JSON UI document and whose startup flow is written in screen_flows[]. It has two usage forms:
.bpk: a ZIP container, unpacked at runtime bysystem::core::unpack_app_package_to().unpacked package: deploy
manifest.json + app/ + res/directly, scanned and installed bySystem::init().
To run a .bpk, first call the system_core package API (optionally verify_app_package_release(), then unpack_app_package_to()) to obtain an AppManifest, then convert it with make_runtime_app_config() into a runtime::AppConfig.
Minimal Package Structure
brookesia.app.demo/
manifest.json
app/
app.lua
res/
profile.json
root.json
Example manifest.json:
{
"package": {
"id": "brookesia.app.demo",
"name": {"en": "Demo", "zh_CN": "演示"},
"version": "0.1.0",
"visible": true,
"systems": ["core", "super"]
},
"runtime": {
"type": "Lua",
"entry": "app/app.lua",
"resource_dir": "res",
"arguments": []
},
"services": [
{
"name": "Storage",
"version": "0.8.1"
}
]
}
Manifest Fields
The package object:
Field |
Description |
|---|---|
|
Unique app manifest id, required |
|
Localized display name object; |
|
App version, required |
|
Whether it appears in the launcher, defaults to |
|
Supported system type list, no restriction by default |
The runtime object:
Field |
Description |
|---|---|
|
Runtime backend type, for example |
|
Relative path of the entry script, required |
|
Relative path of the app resource directory |
|
String array of runtime startup arguments |
The optional top-level services array declares the service RPCs required by a runtime app:
Field |
Description |
|---|---|
|
Stable, case-sensitive RPC name, for example |
|
Minimum compatible service version in numeric |
A local service version is compatible only when its major and minor versions equal the declared values and its patch version is greater than or equal to the declared patch. For example, local versions 0.8.2 and 0.8.3 satisfy a requirement for 0.8.1, while 0.9.0 does not. All declared services are required dependencies.
The component field may be present as metadata for external tools, but system_core silently ignores it: the field is not parsed, validated, stored, reported, or used for matching. Core service matching uses only name and version.
When installing a .bpk or starting an app, system_core checks every declared service for registration and version compatibility. An undeclared service cannot be discovered before the app tries to use it, so the HostBridge also enforces declarations at call time. service_available() returns false for an undeclared service, and other named service operations return an error without invoking the service.
The exact RPC names SystemCore, SystemGui, and SystemTimer are implicitly allowed and do not need declarations. Matching is case-sensitive; variants such as systemcore are not implicitly allowed. A missing services field or an empty array means that a runtime app can call only these three implicit system RPCs.
This enforcement applies to runtime apps that access services through the HostBridge. Native apps are trusted firmware code and their direct C++ service access is not restricted by the manifest.
Resource Descriptor
<runtime.resource_dir>/profile.json is the system_core resource descriptor, not a JSON UI document:
{
"icon_id": "demo",
"root": "root.json",
"screen_flows": [
{"screen_flow": "main", "layer": "AppDefault", "mount_mode": "Replace", "z_order": 0}
]
}
icon_id locates the launcher icon within the package; root points to a standard JSON UI document; screen_flows[] specifies the startup flow. A regular app main screen should use AppDefault, and AppTop is only for an app's own header, floating layer, or toolbar; a runtime app can only use Replace with z_order within 0..100. root.json is a standard JSON UI document and should reference a screenFlow asset.
Scanning and Install
When install_package_apps = true, System::init() scans the apps directories of internal and external storage in the layout and loads each first-level directory that contains manifest.json, sorted by directory path. If the same manifest id appears under multiple volumes, internal and preferred external take priority, and later duplicates are skipped with a warning.
During install, the runtime root icon_id is used to find a matching imageSet descriptor in the resource directory; once found, it is registered as a runtime-global image resource and fills AppManifest.icon_path so the launcher can show the icon.
Safety Constraints
runtime.entryandruntime.resource_dirmust be safe relative paths, not absolute and not containing...A package whose
package.systemsdoes not match the current system type is skipped.A missing or wrongly typed
package.id,package.version,runtime.type, orruntime.entryfails manifest parsing.The runtime GUI startup flow must be written in
screen_flows[]ofprofile.json.
Packaging Tool
The repository provides tools/app_pack.py to pack an unpacked package into a .bpk and to validate manifest.json fields. When changing the package specification, keep the schema, tool validation, system_core parser, and example resources consistent.