手搓开发 APP
作者:马亚丹 | 最后修改:2026-05-24
概述
本文档为合宙引擎主机官方手写 APP 开发教程,面向开发者从零开始,通过最精简的 Hello World 应用,完整讲解基于 LuatOS 系统手动编写、调试、打包、安装、运行后装 APP 的全流程。
合宙引擎主机的 APP 开发,目前既可通过合宙智能体 AI 自动生成,也支持纯手写 Lua 代码开发。两种方式使用完全一致的项目文件结构、同一套底层固件、同一套应用框架,具备高度统一的兼容性与运行机制。
本文档聚焦纯手写开发,不依赖 AI 生成工具,完整拆解后装 APP 必需的文件组成、目录规范、核心 API、窗口生命周期、UI 自适应逻辑、模拟器调试与真机烧录流程,帮助开发者彻底掌握合宙引擎主机 APP 的底层运行逻辑、标准开发范式与工程规范。
通过本文档学习,开发者可清晰理解:
- 手写 APP 必须编写哪些文件、遵循哪些规范
- 应用如何被系统加载、启动、关闭与销毁
- 如何实现屏幕自适应、横竖屏切换、UI 交互与定时器刷新
- 如何在 PC 模拟器快速验证,并烧录到真机稳定运行
- 后装 APP 的底层运行原理与系统沙箱机制
本文档适用于 Air8000W、Air1602 5/7/10 寸全系列引擎主机,步骤可复现。
一、硬件环境
本章明确合宙引擎主机手写 APP 开发所需最低硬件配置、接线规范、设备选型,确保开发环境可稳定搭建。
1.1 PC 要求
- 操作系统:Windows 10 及以上操作系统 (不支持 Windows 7、XP、Linux、MacOS)
- 接口要求:至少 1 个可用 USB 接口,支持 USB 2.0/3.0
- 网络要求:可正常访问公网,用于下载工具、固件、源码
1.2 合宙引擎主机(必选其一)
合宙引擎主机为 APP 运行硬件载体,支持以下型号:
1.2.1 Air8000W 引擎主机
屏幕:4 英寸、竖屏 支持 wifi、SIM 卡(4G,网络功能可选,非运行必须) 接口:Type‑C(供电、烧录、调试)
1.2.2 Air1602 5 英寸 引擎主机
屏幕:5 英寸、竖屏
支持 wifi
接口:Type‑C(供电、烧录、调试)
1.2.3 Air1602 7 英寸 引擎主机
屏幕:7 英寸、横屏
支持 wifi
接口:Type‑C(供电、烧录、调试)
1.2.4 Air1602 10 英寸 引擎主机
屏幕:10.1 英寸、横屏
支持 wifi
接口:Type‑C(供电、烧录、调试)
官方说明:以上机型开发流程、API 调用、工程结构完全一致,仅屏幕分辨率与触摸驱动不同,本教程全机型通用。
1.3 数据线要求
- 规格:标准 Type‑C 数据线
- 该线主要承担给引擎主机供电功能
1.4 可选硬件
Micro SIM 卡:用于 Air8000W 4G 联网,非必须,Air8000W 支持 wifi 联网
二、软件环境
本章为合宙引擎主机手写 APP 开发软件环境清单,包含工具、固件、系统库、出厂应用、例程工程。
APP 开发软件包
下载地址:APP 开发软件包_1.0.0
下载后解压在本地,本文例程本地路径为:E:\APP 开发软件包_1.0.0
APP 开发软件包包含以下文件:
1、 PC 模拟器
- 示例版本:LuatOS-SoC_V2031_PC
- 用途:无需真机即可调试 UI、逻辑、分辨率适配
2、 引擎主机出厂应用 factory
- 作用:系统桌面、应用市场、分辨率管理、横竖屏管理、窗口管理、基础服务启动入口
- 说明:PC 模拟器与真机均依赖 factory 运行
3、引擎主机公共扩展库 libs
- 包含:airui、exwin、lcd、sys、log、timer、os 等核心依赖库
- 说明:所有后装 APP 必须依赖 libs 库运行,不可缺失
4、 Hello World APP 官方例程
- 包含:main.lua、meta.json、user/my_win.lua、icon.png
- 用途:本教程完整示例代码,可直接运行
三、模拟器和真机代码运行说明
本章操作流程,按步骤执行即可成功运行。
3.1 PC 模拟器运行(推荐先验证)
竖屏界面:

横屏界面:

3.1.1 准备工作
1、打开 E:\APP开发软件包_1.0.0\factory\main.lua
2、找到 PC 模拟器分辨率配置项:
local pc_lcd = "Air1601_5in"
3、pc_lcd 参数可修改为:
- Air8000W_4in
- Air8101_5in
- Air1601_5in
- Air1601_7in
- Air1601_9in
- Air1601_10in
3.1.2 部署 APP 到模拟器
1、进入 PC 模拟器目录:E:\APP开发软件包_1.0.0\LuatOS-SoC_V2031_PC
2、新建文件夹:app_store
3、将手写好的 app_hello 文件夹复制到 app_store
4、目录结构:
LuatOS-SoC_V2031_PC/
└── app_store/
└── app_hello/
├── main.lua
├── meta.json
├── icon.png
└── user/my_win.lua
3.1.3 启动模拟器
1、在模拟器目录下双击 cmd 快捷方式
2、输入启动命令(路径 E:\ 替换为自己本地路径):
luatos-pc-64bit.exe E:\APP开发软件包_1.0.0\factory E:\APP开发软件包_1.0.0\libs\
3、回车启动,自动加载系统桌面
4、鼠标左滑屏幕 → 找到【基础入门】APP → 单击运行
5、显示 背景图片 +Hello World + 实时时间,即运行成功
3.2 真机下载与运行
运行界面应和 PC 模拟器界面一致
3.2.1 APP 打包
1、找到 E:\APP开发软件包_1.0.0\LuatOS-SoC_V2031_PC\app_store\app_hello 文件夹
2、直接压缩 app_hello 文件夹为 app_hello.zip
3.2.2 应用上传(合宙 IoT 平台)
1、打开:iot.luatos.com
2、登录 → 进入【应用市场】→【我的应用】→【应用上传】→【添加 app_hello.zip】
3、填写信息:
4、 提交成功
3.2.3 真机安装并运行 APP
1、主机上电开机进入系统桌面
2、打开【设置】→【wifi 设置】→ 接入 wifi 联网
3、打开【应用市场】→【全部】
4、找到【基础入门】→ 点击安装
5、返回桌面 → 点击【基础入门】图标
6、显示图片 + Hello World + 实时时间,运行成功
四、完整代码解释
本 Hello World APP 基于 exwin 窗口 + airui UI 框架 + lcd 显示 + sys 定时器实现。
4.1 整体运行流程
1、main.lua 启动 → 加载 my_win 窗口模块
2、发布 OPEN_MY_WIN 消息
3、订阅 OPEN_MY_WIN 消息触发 open_handler()
4、exwin.open () 创建窗口
5、点击关闭按钮 → exwin.close ()
6、on_destroy () → 停止定时器 → 销毁 UI → 退出应用
4.2 main.lua(应用入口,必需)
1、require 加载功能模块文件
2、发布消息"OPEN_MY_WIN",触发 my_win.lua 中回调函数 open_handler()打开窗口
3、sys.run () 为应用死循环,无此行则应用直接退出。
-- 工程名称
PROJECT = "MY_APP_HELLO"
-- 工程版本 :aaa.bbb.ccc
VERSION = "001.000.000"
-- 日志输出
log.info("main", PROJECT, VERSION)
-- 加载自定义窗口模块
require "my_win"
-- 发布消息,打开窗口
sys.publish("OPEN_MY_WIN")
-- 必需:启动LuatOS事件循环
sys.run()
4.3 meta.json(应用元数据,必需)
本文件是后装应用的核心配置文件。关于分辨率和显示方向的概念详见 4.2 横竖屏与分辨率概念。
{
"app_name_cn": "基础入门",
"app_name_en": "Hello_World",
"version": "1.0.0",
"publish_time": "2026-05-17 12:00:00",
"category": "工具",
"description": "这是一个简单的Hello World应用",
"resolution": "480x800",
"display_zoom": "adaptive",
"supported_models": {
"Air8101": [
{
"firmware_id": 104,
"min_firmware_version": 2010
},
{
"firmware_id": 105,
"min_firmware_version": 2010
}
]
},
"zip_size_kb": 100,
"origin_size_kb": 300
}
关键字段说明:
- app_name_cn:应用中文名称,桌面显示名称,在应用商店内展示,字母间使用_连接,不可使用-连接。
- app_name_en:应用英文名称,用作安装目录名。
- publish_time:发布时间,格式 YYYY-MM-DD HH:MM:SS。
- description:应用描述文本,在应用商店内展示。
- zip_size_kb:安装包大小(KB),可随意填写值,上传应用压缩包时服务器会写入正确的值,用于设备端判断 /ram 目录剩余空间是否足够下载。空间不足时提示用户,不发起下载。
- origin_size_kb:解压后大小(KB),可随意填写值,上传应用压缩包时服务器会写入正确的值,用于设备端判断根目录剩余空间是否足够解压。空间不足时提示用户,不进行下载和解压。
- supported_models:适用设备型号。填写具体型号(如 "Air8101"、"Air780EHM")表示只有该型号可用;目前服务端未启用此字段的校验复制 demo 中的内容即可,暂不影响应用分发。
- min_firmware_version:最低固件版本要求。目前服务端未启用此字段的校验,暂不影响应用分发。
- firmware_id:固件 ID。填写具体 ID 表示只有匹配此 ID 的固件可用;填写 "all" 表示不限制。目前服务端未启用此字段的校验,暂不影响应用分发。
- resolution:推荐分辨率,格式 宽 x 高(如 "320x480")。宽 > 高为横屏应用,宽 < 高为竖屏应用。exapp 启动应用时如果 display_zoom 参数不是 "adaptive" 则读取此字段,与显示设备分辨率对比计算缩放系数(详见 4.2.3 固定分辨率应用的缩放机制)。
- category:应用类别(中文),分为:全部、游戏、工具、学习、通信、工业。用于应用市场分类筛选。
- version:应用版本号,格式 1.0.0(不带 V 前缀)。设备端已安装版本低于服务端版本时,提示更新。
- display_zoom:显示缩放模式,adaptive 表示自适应;不填或填其他值,exapp 计算 resolution 参数进行自动缩放,缩放机制详见 4.2.3 固定分辨率应用的缩放机制;填写"adaptive"时,exapp 跳过计算 resolution 参数进行自动缩放,按应用实际参数进行显示。
4.4 my_win.lua(窗口与 UI 核心)
app 应用窗口模块,在 main.lua 中 require 运行
4.4.1 全局变量
local win_id = nil -- 窗口ID
local main_container = nil -- 根容器
local update_timer_id = nil -- 定时器ID
local title_label = nil -- 标题控件
local current_time = nil -- 当前时间
local width, height = lcd.getSize() -- 屏幕真实分辨率
local airui_size = nil -- airui适配信息
4.4.2 create_ui () —— 界面构建(自适应)
1、创建全屏主容器 main_container,方便退出 app 时一次性销毁窗口
2、横竖屏自动切换背景图
3、自适应居中显示标题 title_label
4、右下角放置关闭按钮
5、可在本函数内添加其他组件实现不同效果
-- 构建 UI
local function create_ui()
-- 创建主容器作为最底层,所有子组件都加到主容器
main_container = airui.container({
parent = airui.screen,
x = 0,
y = 0,
-- w = 720, h = 1280, --根据屏幕分辨率自定义调整
w = width, --自适应分辨率宽度
h = height, --自适应分辨率高度
color = 0x110f27
})
-- 获取屏幕自适应分辨率信息
airui_size = airui.status()
--判断当前是横屏还是竖屏,分别显示不同的图片
if airui_size.w < airui_size.h then
-- 图片背景(parent 指向 main_container)
airui.image({
parent = main_container,
src = "/luadb/caoyuan.jpg",
-- src = "/luadb/fengjing.jpg",
x = 0,
y = 0,
w = width,
h = height,
})
else
-- 图片背景(parent 指向 main_container)
airui.image({
parent = main_container,
src = "/luadb/fengjing.jpg",
x = 0,
y = 0,
w = width,
h = height,
})
end
-- 标题文字(parent 指向 main_container)
title_label = airui.label({
parent = main_container,
text = "Hello World! 一起来看大好河山",
--x = 60, --根据屏幕分辨率自定义调整
--y = 120, --根据屏幕分辨率自定义调整
x = airui_size.w / 3, --根据屏幕分辨率自适应
y = airui_size.h / 6, --根据屏幕分辨率自适应
w = 300, --显示区域的宽度
h = 300, --显示区域的高度
font_size = 24,
color = 0xD81CEF
})
-- 关闭按钮(parent 指向 main_container)
airui.button({
parent = main_container,
x = airui_size.w - 100, --根据屏幕分辨率自适应
y = airui_size.h - 50, --根据屏幕分辨率自适应
w = 100,
h = 40,
text = "关闭应用",
font_size = 14,
style = { bg_color = 0x2563EB, text_color = 0xFFFFFF, radius = 8, border_width = 0 },
on_click = function()
-- 关闭当前窗口
exwin.close(win_id)
end
})
end
4.4.3 update_tick () —— 定时器刷新
1、os.date()将时间转换为指定格式的字符串或时间表
2、title_label:set_text()更新标签文本
-- 定时器回调函数,定时刷新 UI
local function update_tick()
-- 定时器回调中的逻辑...
current_time = os.date("%Y-%m-%d %H:%M:%S")
if title_label then
title_label:set_text("Hello World 当前时间 " .. current_time)
end
log.info("my_win", "当前时间: " .. current_time)
end
4.4.4 窗口生命周期
1、on_create()创建窗口,启动循环定时器
2、on_destroy()销毁窗口
3、订阅"OPEN_MY_WIN"消息,触发启动 open_handler()打开窗口
-- 窗口创建回调:初始化UI和定时器
local function on_create()
create_ui()
-- 启动定时器,每秒更新时间显示
update_timer_id = sys.timerLoopStart(update_tick, 1000)
log.info("my_win", "窗口创建")
end
-- 窗口销毁回调:先停止定时器,再销毁主容器
local function on_destroy()
-- 1. 停止定时器(必须手动停止,destroy 不会自动停止)
if update_timer_id then
sys.timerStop(update_timer_id)
update_timer_id = nil
end
-- 2. 销毁主容器(自动递归销毁内部所有子组件)
if main_container then
main_container:destroy()
main_container = nil
end
win_id = nil
log.info("my_win", "窗口销毁")
end
-- 打开窗口的处理函数
local function open_handler()
win_id = exwin.open({
on_create = on_create,
on_destroy = on_destroy,
on_get_focus = function() end,
on_lose_focus = function() end,
})
end
sys.subscribe("OPEN_MY_WIN", open_handler)
五、修改代码做出不一样的界面显示
本文第四章介绍可以看出,决定界面显示效果的是 app 应用窗口模块 my_win.lua,所以我们可以通过修改 my_win.lua 文件代码来呈现不同的界面效果,本文提供以下修改示例抛砖引玉,更多好玩好用的应用可自行举一反三测试。
5.1 修改 Hello World!的字体大小或者颜色
把 create_ui()中 title_label 变量的参数 font_size = 24, color = 0xD81CEF,修改即可,此处把字体大小修改为 30,颜色修改为 0xD81000,对应的显示区域高度调大为 300,修改后代码:
-- 标题文字(parent 指向 main_container)
title_label = airui.label({
parent = main_container,
text = "Hello World! 一起来看大好河山",
--x = 60, --根据屏幕分辨率自定义调整
--y = 120, --根据屏幕分辨率自定义调整
x = airui_size.w / 3, --根据屏幕分辨率自适应
y = airui_size.h / 6, --根据屏幕分辨率自适应
w = 300, --显示区域的宽度
h = 300, --显示区域的高度
font_size = 30,
color = 0xD81000
})
修改后保存代码,重新运行,可以看到字体大小和颜色较修改代码之前都发生了变化:

5.2 添加文字显示
同理,我们可以添加其他 label 标签显示,比如添加显示:“我的第一个 APP 应用”,变量名 add_label 与前面的 title_label 变量名注意区分,下面代码示例中 add_label:
-- 标题文字(parent 指向 main_container)
title_label = airui.label({
parent = main_container,
text = "Hello World! 一起来看大好河山",
--x = 60, --根据屏幕分辨率自定义调整
--y = 120, --根据屏幕分辨率自定义调整
x = airui_size.w / 3, --根据屏幕分辨率自适应
y = airui_size.h / 6, --根据屏幕分辨率自适应
w = 300, --显示区域的宽度
h = 300, --显示区域的高度
font_size = 30,
color = 0xD81000
})
-- 添加文字显示(parent 指向 main_container)
add_label = airui.label({
parent = main_container,
text = "我的第一个APP应用",
--x = 60, --根据屏幕分辨率自定义调整
--y = 120, --根据屏幕分辨率自定义调整
x = airui_size.w / 3, --根据屏幕分辨率自适应
y = airui_size.h / 2, --根据屏幕分辨率自适应
w = 300, --显示区域的宽度
h = 300, --显示区域的高度
font_size = 30,
color = 0xD810EE
})
-- 关闭按钮(parent 指向 main_container)
airui.button({
parent = main_container,
x = airui_size.w - 100, --根据屏幕分辨率自适应
y = airui_size.h - 50, --根据屏幕分辨率自适应
w = 100,
h = 40,
text = "关闭应用",
font_size = 14,
style = { bg_color = 0x2563EB, text_color = 0xFFFFFF, radius = 8, border_width = 0 },
on_click = function()
-- 关闭当前窗口
exwin.close(win_id)
end
})
添加代码后保存,重新运行,页面显示如下:看到新添加的文字显示“我的第一个 APP 应用”

5.3 更换背景图
在 app_hello\res 下添加新的图片,把 airui.image 中 src 参数中图片名称换成新的图片名称即可。本示例添加新的图片,图片名称是 add_image.jpg

代码修改如下:
-- 图片背景(parent 指向 main_container)
airui.image({
parent = main_container,
-- src = "/luadb/fengjing.jpg",
--更换新的图片背景显示
src = "/luadb/add_image.jpg",
x = 0,
y = 0,
w = width,
h = height,
})
添加代码后保存,重新运行,页面显示如下:看到背景图已经是新的图片

......
更多好玩的应用,自行解锁开发
六、典型的后装 APP 目录介绍
合宙引擎主机所有后装 APP 必须遵循统一目录结构,否则无法安装、运行。
6.1 标准压缩包结构
应用名.zip
└── 应用名/ 【必需】与zip同名文件夹
├── main.lua 【必需】应用入口
├── icon.png 【必需】应用图标
├── meta.json 【必需】应用配置
├── libs/xxx.lua 【可选】扩展库脚本(不能包含子目录)
├── user/xxx.lua 【必需】用户自定义脚本(不能包含子目录)
├── res/ 【可选】图片/字体资源(不能包含子目录)
│ ├── enemy1.png
│ ├── player.png
│ └── win.png
└── data/ 【运行时自动创建】运行时数据存储
6.2 目录强制规范
1、zip 压缩包内必须有且仅有一个同名文件夹
2、文件夹名称必须与 zip 文件名一致
3、libs、user、res 不允许嵌套子目录
4、只支持字母、数字、下划线,不支持中文、空格、特殊符号
5、图片仅支持 jpg/ png 格式
6.3 文件作用说明
1、main.lua:应用唯一入口,必须包含 sys.run ()
2、meta.json:系统识别应用的配置文件
3、icon.png:桌面与应用市场显示图标(必须 32*32 分辨率)
4、libs 文件夹:包括应用私有 Lua 库,扩展库
5、user 文件夹:包括业务逻辑脚本
6、res 文件夹:放置图片、音频等资源
7、data 文件夹:日志、配置、缓存等运行时自动生成的文件
七、APP 后装原理介绍
本章用于理解合宙引擎主机后装 APP 的加载、启动、运行、卸载完整机制,是高级开发必备基础。
7.1 统一底层架构
1、手写 APP、AI 生成 APP、应用市场 APP 共用同一套 LuatOS 内核固件
2、内核提供:虚拟机、内存管理、驱动、文件系统、UI 框架、窗口系统
3、上层 APP 基于 LuatOS‑Lua API 开发,无底层差异
7.2 后装 APP 加载机制
1、系统启动 → 加载 factory 出厂应用 → 启动应用市场服务
2、用户安装 APP → 系统校验 zip 结构、meta.json 合法性
3、校验通过 → 解压到 /app_store/应用名/ 路径
4、写入应用注册表:名称、版本、路径、权限、分辨率
7.3 启动运行原理
1、点击桌面图标 → 系统发送启动命令
2、内核沙箱创建独立运行环境
3、加载公共 libs 库 → 加载应用 main.lua
4、执行 Lua 虚拟机 → 进入 sys.run () 事件循环
5、加载 UI、创建窗口、运行业务逻辑
7.4 应用生命周期管理
1、创建:exwin.open () → on_create () → UI 初始化
2、运行:事件循环、定时器、触摸响应、消息订阅
3、关闭:exwin.close () → on_destroy () → 释放定时器、UI、内存
4、退出:虚拟机停止、沙箱关闭、资源回收、返回桌面
7.5 沙箱安全机制
1、每个后装 APP 运行在独立沙箱中
2、仅允许访问自身目录:/app_store/应用名/*
3、禁止越权访问系统文件、其他应用数据
4、崩溃不影响系统与其他应用
7.6 分辨率适配原理
1、系统启动获取 lcd 真实宽高
2、应用通过 lcd.getSize()、airui.status() 获取分辨率
3、自动计算坐标、尺寸,实现横竖屏 / 多机型自适应
4、display_zoom=adaptive 开启系统级缩放适配
7.7 后装 APP 运行原理
点击查看 后装 APP 运行原理,解锁更多关于后装 APP 运行原理介绍