跳转至

手搓开发 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(应用入口,必需)

参考 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(应用元数据,必需)

参考 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 运行原理介绍

八、API 接口说明