跳转至

Hello World 与工程解析

快速跑通 Hello World

本章参考《Hello World 应用开发入门指南》,用于在修改 Native Slice 代码前先跑通仓内已提供的 helloworldpage 示例。完成本章后,应能确认源码路径、编译命令、应用入口和页面显示链路均正常。

编译 Hello World

完成一站式 CLI 环境配置后执行完整打包命令:

fbb set-target pack_diting_community
fbb build

构建成功后,使用一站式 CLI 烧写固件并打开 UART2 串口监视器。以下为 Windows USB DFU 示例;将 COM3 替换为实际日志串口,其他平台和串口烧写参数参见一站式 CLI 开发环境使用指南

fbb flash -f "$env:FBB_SDK_DIR\output\3322\fwpkg\diting-community.fwpkg" --chip 3322 -d --timeout 180
fbb monitor --port COM3 --baud 750000

-c 会执行清理动作,适合首次验证或新增 .cpp 后排除 CMake 缓存影响。若仅做日常增量编译,可按工程实际编译脚本选择对应目标;本文档以可烧录固件验证为准。

编译通过后,应生成可用于设备烧录的固件产物。若命令在依赖检查阶段失败,先按工程编译环境要求补齐 Python 模块、交叉编译工具链和平台构建依赖,再重新执行。

运行验收

烧录固件并启动设备后,按以下项目验收:

  • 应用列表中出现 HelloWorld
  • 点击 HelloWorld 后进入 Native 页面。
  • 页面中央显示 Hello World 文本。
  • 串口日志可看到 HelloWorldPage OnStart,日志级别为 WEARABLE_LOGD

若以上结果均符合,说明 NativeAbility、菜单注册、SlicePage 注册和页面渲染的基础链路已跑通,可以继续阅读下一章的代码走读。

跑通失败排查

现象 排查点
编译未包含新增 .cpp 确认源码放在 src/application/wearable/nativeapp/nativeui/ 下,并重新执行带 -c 的打包命令。
应用列表没有 HelloWorld 检查 HelloWorldPresenter.cppREGIST_MENU 是否受 SDK_DITING_COMMUNITY 宏控制且当前目标已打开该宏。
点击后页面为空 检查 HelloWorldPage::OnStart 是否调用 AddViewToPageContainer(container_)
页面进入后异常退出 检查动态创建的控件是否判空,析构中是否按控件树顺序释放资源。

工程代码的文件结构和代码走读

本章围绕 HelloWorld Native Demo 的工程文件、注册链路、页面实现和进阶参考进行代码走读。HelloWorld 示例本身较简单,开发者可以结合 nativeui 目录下其他 Native 应用继续扩展多页面、页面跳转、共享片段和生命周期处理。

HelloWorld Demo目录

HelloWorld Demo 是最小可用 Native Slice Demo,目录结构如下:

nativeui/

├── helloworldpage/

│   ├── HelloWorldPage.cpp

│   └── HelloWorldPresenter.cpp

└── include/

    └── helloworldpage/

        ├── HelloWorldPage.h

        ├── HelloWorldPresenter.h

        └── HelloWorldView.h

各文件职责如下:

文件 职责
HelloWorldView.h 定义 View 类型,用于 Slice 注册和 Presenter 绑定。
HelloWorldPresenter.h 定义 Presenter 类型,可承载业务逻辑。
HelloWorldPresenter.cpp 使用 REGIST_MENU 注册应用菜单入口。
HelloWorldPage.h 定义 SlicePage 页面类和页面持有的 UI 控件。
HelloWorldPage.cpp 使用 REGIST_SLICE_PAGE 注册页面,并在 OnStart 中创建页面内容。

Demo注册流程

定义应用View ID

nativelauncher/include/AppViewIDs.h 中定义应用 ID:

VIEW_HELLOWORLD,

新增 Demo 时应新增唯一的 VIEW_XXX,并放在 VIEW_MAX_INTER_ARRY_APP 之前。菜单注册、Slice 注册和页面注册必须使用同一个 View ID,否则点击菜单后无法进入预期页面。

注册菜单入口

HelloWorldPresenter.cpp 中使用 REGIST_MENU 注册应用列表入口:

#include "NativeRegisterManager.h"

#include "helloworldpage/HelloWorldView.h"

#include "helloworldpage/HelloWorldPresenter.h"



namespace OHOS {

#ifdef SDK_DITING_COMMUNITY

REGIST_MENU(VIEW_HELLOWORLD, HelloWorldView, HelloWorldPresenter, EMPTY_ICON, EMPTY_ICON, "HelloWorld");

#endif

}

REGIST_MENU 的参数依次表示 View ID、View 类型、Presenter 类型、普通图标、六边形图标和应用名称。最小 Demo 可以先使用 EMPTY_ICON,后续再替换为自定义资源。

如果某个 Slice 只作为内部跳转目标,不需要出现在应用列表中,可使用 REGIST_SLICE(id, V, P) 只注册 Slice,不注册菜单。switch_slice_demo 中只有入口 Slice 通过 REGIST_MENU 展示在应用列表,其余 Slice 通过内部跳转进入。

注册SlicePage页面

HelloWorldPage.cpp 中使用 REGIST_SLICE_PAGE 注册页面:

static constexpr uint16_t HELLOWORLD_PAGE = 1;



#ifdef SDK_DITING_COMMUNITY

REGIST_SLICE_PAGE(VIEW_HELLOWORLD, HELLOWORLD_PAGE, HelloWorldPage, true);

#endif

参数说明如下:

参数 说明
VIEW_HELLOWORLD 归属的 Slice ID,需要和 REGIST_MENU 保持一致。
HELLOWORLD_PAGE 页面 ID。同一个 Slice 下多个页面需要使用不同 ID。
HelloWorldPage 页面类型。
true 是否为主页面。应用入口页应设置为 true

Demo页面实现

HelloWorldPage 继承自 SlicePage<HelloWorldPresenter>,在 OnStart 中创建根容器和文本控件:

void HelloWorldPage::OnStart(void *data)

{

    container_ = new UIViewGroup();

    container_->SetPosition(0, 0, HORIZONTAL_RESOLUTION, VERTICAL_RESOLUTION);

    container_->SetDraggable(true);

    container_->SetTouchable(true);



    helloWorldLabel_ = new UILabel();

    helloWorldLabel_->SetPosition(121, 161, 193, 40);

    helloWorldLabel_->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);

    helloWorldLabel_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 30);

    helloWorldLabel_->SetText("Hello World");



    container_->Add(helloWorldLabel_);

    AddViewToPageContainer(container_);

}

页面实现要点如下:

  1. 使用 UIViewGroup 作为根容器,尺寸优先使用 HORIZONTAL_RESOLUTIONVERTICAL_RESOLUTION

  2. 子控件通过 SetPosition 设置位置和尺寸。

  3. 文本控件通过 SetFontSetAlignSetText 设置显示效果。

  4. 子控件通过 container_->Add() 加入根容器。

  5. 根容器通过 AddViewToPageContainer() 加入 SlicePage 页面容器。

页面退出时需要释放动态创建的控件:

HelloWorldPage::~HelloWorldPage()

{

    if (container_ != nullptr) {

        container_->RemoveAll();

        delete container_;

        container_ = nullptr;

    }

    if (helloWorldLabel_ != nullptr) {

        delete helloWorldLabel_;

        helloWorldLabel_ = nullptr;

    }

}

如果页面使用图片缓存、定时器或业务资源,也需要在析构函数或 OnStop 中释放,避免重复进入页面后产生内存泄漏或野指针。

进阶能力参考

HelloWorld 只体现最小页面。开发实际 Demo 时,可继续参考 nativeui 下已有应用扩展能力:

参考目录 可学习能力
nativeui/switch_slice_demo 多 Slice 注册、多页面注册、页面切换、返回栈、点击事件和 UIFragment 复用。
nativeui/alarm 点击事件、拖拽事件、弹窗 Slice、定时器、数字时钟、业务 Model 和 Presenter 事件分发。
nativeui/applist UIListAbstractAdapter、列表项复用、应用列表点击进入应用。
nativeui/settings 多级设置页面、Model 驱动列表、页面内跳转、蓝牙设备列表等复杂业务状态管理。
nativeui/activity 图片缓存、样式设置、动态图表、数据变化后刷新控件。
nativeui/timersnativeui/stopwatch 计时、倒计时、周期刷新、页面暂停和恢复处理。

常用能力和接口如下:

能力 关键接口或类 说明
点击事件 UIView::OnClickListenerSetOnClickListener 控件需设置 SetTouchable(true) 后绑定监听。
拖拽事件 UIView::OnDragListenerSetOnDragListener 适合页面滑动、弹窗拖拽、返回手势等场景。
页面内跳转 SwitchPageInSliceBackToPrevSlicePage 用于同一个 Slice 内多个 SlicePage 间跳转。
Slice间跳转 SwitchSliceSwitchSliceWithCacheBackToPreSlice 用于不同 Native 应用之间切换。
列表 UIListAbstractAdapterGetView 适合动态数据列表,列表项应支持复用。
图片 UIImageViewImageCacheManagerSetSrc 大图或频繁使用图片建议走缓存管理。
异步刷新 GraphicTimerPostGraphicEvent 定时器回调中操作 UI 时,应投递到图形事件队列。
分层 PagePresenterModel 页面负责 UI,Presenter 处理交互,Model 保存业务数据。