应用APP¶
1. 创建一个内置APP/子页面¶
内置APP通过注册宏定义在专属代码段,编译时整合到固件,系统启动时自动加载并管理生命周期,无需手动初始化。
1.1 内置APP¶
1.1.1 注册¶
根据应用是否在主菜单显示,分为「普通APP」和「隐藏APP」,二选一即可。
注册一个普通APP
// 注册普通APP的宏,参数说明:
// key_str: 应用显示标题(多语言字符串),仅用于界面显示
// img: 应用缩略图资源(在主菜单中显示)
// app_name: 应用唯一标识字符串(框架内部调度使用,必须保证唯一性)
// ptr_size: 应用全局内存大小(由框架自动申请和释放,页面可直接使用该内存区域)
APPLICATION_REGISTER(key_str, img, app_name, ptr_size)
注册一个隐藏APP
主菜单添加一个应用时是判断是否有相应的应用图标,没有图标则不在主菜单显示
// 注册隐藏APP的宏(不在主菜单显示):
// key_str: 应用显示标题(多语言字符串)
// app_name: 应用唯一标识字符串
// ptr_size: 应用全局内存大小
APPLICATION_REGISTER_HIDDEN(key_str, app_name, ptr_size)
注册说明: 每个应用注册时会默认注册一个’root’的子页面,以保证每个应用至少有一个子页面(子页面运行层级与注册的先后顺序无关)
#define APPLICATION_REGISTER(key_str, img, app_name, ptr_size) \
APP_PAGE_REGISTER(app_name, "root", ptr_size); \
APPLICATION_MAIN(app_name, ptr_size); \
BUILTIN_APP_EXPORT(key_str, APP_GET_IMG(img), app_name, app_main, 1); \
BUILTIN_APP_EXPORT(key_str, APP_GET_IMG(CONCAT_2(img, 2)), app_name, app_main, 2);
#define APPLICATION_REGISTER_HIDDEN(key_str, app_name, ptr_size) \
APP_PAGE_REGISTER(app_name, "root", ptr_size); \
APPLICATION_MAIN(app_name, ptr_size) \
BUILTIN_APP_EXPORT(key_str, NULL, app_name, app_main, 1); \
BUILTIN_APP_EXPORT(key_str, NULL, app_name, app_main, 2);
1.1.2 示例¶
注册一个普通APP(闹钟应用)
// 页面启动回调函数:框架发送START消息时调用
static void on_start(void)
{
/* 获取框架申请的内存,全局指针所对应的结构体大小一定要和申请的大小一致 */
// APP_GET_PAGE_MEM_PTR是框架提供的接口,用于获取预先申请的内存指针
p_alarm = (app_alarm_gui_t *)APP_GET_PAGE_MEM_PTR;
RT_ASSERT(p_alarm);
/* 在当前screen上面建立背景页面,包括基础数据读取以及页面标题栏 */
p_alarm->bg_page = app_alarm_gui_init(lv_scr_act());
/* 创建一个刷新timer,定时查询状态,亦可使用数据订阅 */
p_alarm->timer = lv_timer_create(alarm_task_cb, 1000, (void *)0);
/* 将timer设置pause状态,因为初始页面不需要刷新,暂时关闭timer */
lv_timer_pause(p_alarm->timer);
}
// 页面激活回调函数:页面显示到前台时调用
static void on_resume(void)
{
/* 收到resume消息后,将该页面的所有内容创建完成 */
app_alarm_main_bg_page(p_alarm->bg_page);
/* 页面创建完成后启动刷新timer */
lv_timer_resume(p_alarm->timer);
}
// 页面暂停回调函数:页面被隐藏时调用
static void on_pause(void)
{
/* 页面进入隐藏不可见,关闭刷新timer */
lv_timer_pause(p_alarm->timer);
}
// 页面销毁回调函数:页面即将被销毁时调用
static void on_stop(void)
{
/* 页面即将销毁,先删除刷新timer,因为该timer不属于当前screen的子控件,销毁当前页面时不会自动销毁 */
lv_timer_del(p_alarm->timer);
/* 将全局指针变量置空,防止其他地方使用时非空判断出现异常,该指针指向的内存会在框架执行完stop消息后释放 */
p_alarm_main = NULL;
}
/* 注册Alarm应用,并使用框架申请的大小为'sizeof(app_alarm_gui_t)' 的内存 */
// 应用标题使用多语言字符串,图标使用img_alarm,应用名为"Alarm",内存大小为app_alarm_gui_t结构体大小
APPLICATION_REGISTER(app_get_strid(key_alarm, "Alarm"), img_alarm, "Alarm", sizeof(app_alarm_gui_t));
具体例程可以参见solution\examples\watch\application\setting\setting_main\setting_main_gui.c。
注册一个隐藏APP
具体例程可以参见solution\examples\watch\application\guide。
1.2 内置子页面¶
1.2.1 注册¶
通过
APP_PAGE_REGISTER接口可以为一个应用创建子页面。
// 注册子页面的宏:
// app: 所属应用的名称(必须与APPLICATION_REGISTER中注册的应用名一致)
// subpage: 子页面唯一标识字符串
// ptr_size: 子页面全局内存大小
APP_PAGE_REGISTER(app, subpage, ptr_size)
注册说明: 为简化注册流程,框架消息注册以及入口注册均包含在应用注册接口以及页面注册接口内部,无需用户额外处理
#define APP_PAGE_REGISTER(app, subpage, ptr_size) \
APP_MSG_HANDLER(on_start, on_resume, on_pause, on_stop); \
SECTION_ITEM_REGISTER(APP_SUBPAGE_SECTION_NAME, static const app_subpage_desc_t app_subpage) = \
{ \
.app_id = app, \
.page_id = subpage, \
.handler = msg_handler, \
.mem_size = ptr_size \
}
1.2.2 运行¶
运行注册的子页面调用下面的接口。
// 运行指定应用的子页面:
// app_id: 应用名称(必须与注册时使用的应用名一致)
// sub_id: 子页面名称(必须与注册时使用的子页面名一致)
// user_data: 自定义数据指针(可通过APP_GET_PAGE_USERDATA_PTR接口获取,仅在msg_handle中有效)
gui_app_run_subpage(const char *app_id, const char *sub_id, void *user_data)
1.2.3 示例¶
在music APP中注册一个子页(PAGE)选择播放音乐的路径。
static void on_start(void)
{
fs_list_info_t *list = audio_file_list_get(APP_AUDIO_LOCAL_MUSIC);
lv_obj_t *fe = lv_file_explorer_create(lv_scr_act());
lv_file_explorer_set_filter(fe, LV_EXPLORER_FILTER_DIR, NULL);
if (list && list->target_dir && app_path_check_valid(list->target_dir))
lv_file_explorer_open_dir(fe, list->target_dir);
else
lv_file_explorer_open_dir(fe, "/");
lv_file_explorer_set_select_cb(fe, music_file_explorer_select_cb);
lv_file_explorer_set_backspace_cb(fe, music_file_explorer_backspace_cb);
}
static void on_resume(void)
{
}
static void on_pause(void)
{
}
static void on_stop(void)
{
}
#if PAGE_IMPLICIT_INVOCATION
APP_PAGE_REGISTER(MUSIC_APP_ID, MUSIC_PATH_ID, 0);
#else
APP_MSG_HANDLER(on_start, on_resume, on_pause, on_stop);
void music_path_main(void *user_data)
{
gui_app_create_page_for_app_ext(MUSIC_APP_ID, MUSIC_PATH_ID, msg_handler, user_data, 0);
}
#endif
具体例程可以参见solution\examples\_dynamic_app\c\app\music\src\music_path_gui.c。
2. 创建一个外置APP/子页面¶
外置APP也称动态应用或动态加载应用,可以通过外置APP功能实现应用市场。动态应用具体介绍
2.1 外置APP¶
2.1.1 注册¶
代码第一行定义DYN_APP宏,申明此APP是外置app,资源通过外置方式获取
// 定义此宏表明这是一个外置APP,资源将通过外置方式获取
#define DYN_APP
定义
on_start/on_resume/on_pause/on_stop调用宏注册应用 外置APP注册和内置APP注册一样,采用同一个宏APPLICATION_REGISTER。
APPLICATION_REGISTER(key_str, img, app_name, ptr_size)
2.1.2 示例¶
注册一个飞机APP的外置应用。
#define DYN_APP // 声明此为外置APP,资源通过外置方式获取
#include "global.h"
#include "dynamic_app.h"
// 定义模块名称(必须与动态应用APP_ID相同,模拟器调试使用)
#define _MODULE_NAME_ 'dyn_plane'
// 包含资源使用接口头文件
#include "app_module.h"
/**
* 用户逻辑代码
**/
// 页面生命周期回调函数
static void on_start(void)
{
/*user logic*/
}
static void on_resume(void)
{
/*user logic*/
}
static void on_pause(void)
{
/*user logic*/
}
static void on_stop(void)
{
/*user logic*/
}
APPLICATION_REGISTER(app_get_strid(key_plane, "Plane"), img_game_plane, "dyn_plane", sizeof(plane_play_t));
具体例程可以参见solution\examples\_dynamic_app\c\app\dyn_plane\src\game_plane_play.c。
2.2 外置子页面¶
2.2.1 注册¶
代码第一行定义DYN_APP宏,申明此页面是外置页面,资源通过外置方式获取
// 定义此宏表明这是一个外置页面
#define DYN_APP
消息处理函数定义
// 注册页面消息处理回调函数
APP_MSG_HANDLER(on_start, on_resume, on_pause, on_stop)
外置APP的子页面典型使用方式为显示调用子页面调用函数,函数内部通过注册接口注册子页面,注册函数如下:
// 为外置APP创建子页面:
// app_id: 所属应用ID
// page_id: 子页面ID
// handler: 消息处理函数(固定为msg_handler)
// user_data: 自定义数据指针(可通过APP_GET_PAGE_MEM_PTR获取,仅在handler中有效)
// mem_size: 子页面全局内存大小
gui_app_create_page_for_app_ext(const char* app_id, const char* page_id, gui_app_msg_cb_t handler,
void* user_data, uint32_t mem_size)
2.2.2 示例¶
为外置飞机 APP 创建一个子页面setting。
#define DYN_APP // // 声明此为外置页面,资源通过外置方式获取
#include "global.h"
#include "dynamic_app.h"
// 定义模块名称(必须与动态应用APP_ID相同,模拟器调试使用)
#define _MODULE_NAME_ 'dyn_plane'
// 包含资源使用接口头文件
#include "app_module.h"
// 定义子页面ID
#define PAGE_ID "setting"
/**
* 用户逻辑代码
**/
// 页面生命周期回调函数
static void on_start(void)
{
/*user logic*/
}
static void on_resume(void)
{
/*user logic*/
}
static void on_pause(void)
{
/*user logic*/
}
static void on_stop(void)
{
/*user logic*/
}
// 注册消息处理回调函数
APP_MSG_HANDLER(on_start, on_resume, on_pause, on_stop)
/*显示调用此函数创建子页面*/
int dyn_plane_subpage_create(void)
{
// 为外置APP"dyn_plane"创建子页面"setting"
// user_data和ptr_size根据实际情形填写(此处示例为NULL和0)
gui_app_create_page_for_app_ext("dyn_plane", PAGE_ID, msg_handler, NULL, 0)
}
具体例程可以参见solution\examples\_dynamic_app\c\app\activity\src\activity_target_gui.c。