HarmonyOS 应用开发 Skills
快速掌握规范开发流程,减少隐性 Bug;复用高频场景代码,提升开发效率;搭建可扩展、可维护的项目架构,降低后期维护成本;适配 HarmonyOS 最新特性,确保应用兼容性。后续开发中,也可以结合官方提供的参考文档,深入学习 HarmonyOS 开发细节,打造更高质量的应用。> (注:文档部分内容可能由 AI 生成)
在 HarmonyOS 应用开发过程中,你是否曾遇到过这些痛点?类型混乱导致的隐性 Bug、状态更新不触发 UI 刷新、项目结构杂乱难以维护、多设备适配兼容性差……这些问题不仅拖慢开发效率,更会影响应用的稳定性与用户体验。
一、开发基石:必须恪守的核心原则
-
ArkTS 优先:作为 HarmonyOS 首选开发语言,使用 ArkTS 时必须严格保证类型安全,坚决杜绝无类型 any 或动态类型,从源头避免类型相关的隐性 Bug。
-
声明式 UI:基于 ArkUI 的声明式组件和状态管理构建界面,摒弃传统命令式写法,让 UI 描述更直观、更易维护。
-
阶段模型:全面采用现代阶段模型(UIAbility),彻底放弃已弃用的 FA 模型(PageAbility),适配 HarmonyOS 最新架构规范。
-
分布式设计:开发初期就需考虑跨设备功能,充分利用 HarmonyOS 分布式能力,实现多设备协同体验。
-
原子服务:优先考虑使用原子服务和卡片,打造轻量级、免安装的用户体验,贴合 HarmonyOS 生态特色。
-
一次性开发:设计时兼顾多设备适配,确保应用能在手机、平板电脑、手表、电视等不同终端流畅运行。
二、红线不可碰:4 条硬性开发规定
1. 无动态类型,坚守类型安全
ArkTS 的核心优势之一就是强类型校验,动态类型会破坏这种校验机制,导致代码可读性、可维护性大幅下降,还容易出现难以排查的 Bug。
// ❌ 禁止:动态类型写法
let data: any = fetchData();
let obj: object = {};
obj['dynamicKey'] = value; // 动态属性访问
(someVar as SomeType).method(); // 类型断言
// ✅ 必须:严格类型写法
interface UserData {
id: string;
name: string;
}
let data: UserData = fetchData();
// 有动态键需求时,使用 Record 类型
let obj: Record<string, string> = {};
obj['key'] = value; // Record 类型下合法
2. 无直接状态突变,采用不可变更新
在 HarmonyOS 声明式 UI 中,直接修改 @State/@Prop 变量(尤其是嵌套对象)不会触发 UI 刷新,这是很多开发者都会踩的坑。必须通过创建新对象/新数组的方式,实现不可变更新,才能确保 UI 同步刷新。
// ❌ 禁止:直接修改状态
@State user: User = { name: 'John', age: 25 };
updateAge() {
this.user.age = 26; // UI 不会更新!
}
// ✅ 必须:不可变更新
updateAge() {
this.user = { ...this.user, age: 26 }; // 创建新对象,触发 UI 刷新
}
// 数组更新示例
@State items: string[] = ['a', 'b'];
// ❌ 禁止
this.items.push('c'); // UI 不会更新
// ✅ 必须
this.items = [...this.items, 'c'];
3. 仅限阶段模型,摒弃 FA 模型
FA 模型(PageAbility)已被 HarmonyOS 官方弃用,阶段模型(UIAbility)是当前唯一推荐的应用能力模型,具备更灵活的生命周期管理和更好的扩展性。
// ❌ 禁止:已弃用的 FA 模型
// config.json 中包含 "pages" 数组
export default {
onCreate() { ... } // PageAbility 生命周期
}
// ✅ 必须:阶段模型
// module.json5 中配置 abilities
import { UIAbility } from '@kit.AbilityKit';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 现代阶段模型生命周期
}
onWindowStageCreate(windowStage: window.WindowStage): void {
windowStage.loadContent('pages/Index');
}
}
4. 组件重用性,拆分复杂 UI
将可复用的 UI 逻辑提取到独立的 @Component 组件中,避免在 build() 方法中编写冗长的内联 UI,既能提高代码复用率,也能让页面结构更清晰。
// ❌ 禁止:单一冗长的 build 方法
@Entry
@Component
struct MainPage {
build() {
Column() {
// 200+ 行内联 UI...
Row() {
Image($r('app.media.avatar'))
Column() {
Text(this.user.name)
Text(this.user.email)
}
}
// 更多内联 UI...
}
}
}
// ✅ 必须:提取可复用组件
@Component
struct UserCard {
@Prop user: User;
build() {
Row() {
Image($r('app.media.avatar'))
Column() {
Text(this.user.name)
Text(this.user.email)
}
}
}
}
@Entry
@Component
struct MainPage {
@State user: User = { name: 'John', email: 'john@example.com' };
build() {
Column() {
UserCard({ user: this.user })
}
}
}
三、实战必备:核心能力快速参考
1. 状态管理:选对装饰器,避免踩坑
状态管理是声明式 UI 开发的核心,不同场景对应不同的状态装饰器,选对装饰器能大幅提升开发效率。以下是高频场景的装饰器选型参考:
| 设想场景 | 推荐装饰器/图案 | 示例说明 |
|---|---|---|
| 组件局部状态 | @State | 计数器、表单输入等组件内部维护的状态 |
| 父母与子女的数据传递 | @Prop | 父组件向子组件传递只读数据,子组件仅使用不修改 |
| 双向绑定 | @Link | 父组件与子组件共享可变状态,子组件修改同步回父组件 |
| 跨组件状态(多级传递) | @Provide/@Consume | 主题配置、用户上下文等需要多级组件共享的状态 |
| 持久状态(应用重启保留) | PersistentStorage | 用户偏好设置、登录状态等需要持久化存储的数据 |
| 应用范围全局状态 | AppStorage | 全局配置、应用级状态,可跨组件、跨页面访问 |
| 复杂状态逻辑(嵌套对象) | @Observed/@ObjectLink | 嵌套对象的状态更新,确保深层属性变化触发 UI 刷新 |
2. 项目结构:规范化架构,降低维护成本
混乱的项目结构会导致后期维护成本激增,推荐采用模块化、分层的架构设计,适用于中大型 HarmonyOS 应用开发,结构清晰且可扩展性强。
MyApp/
├── entry/ # 主入口模块
│ ├── src/main/
│ │ ├── ets/
│ │ │ ├── entryability/ # UIAbility 定义(应用入口)
│ │ │ │ └── EntryAbility.ets
│ │ │ ├── pages/ # 页面组件(页面级 UI)
│ │ │ │ ├── Index.ets
│ │ │ │ └── Detail.ets
│ │ │ ├── components/ # 可复用 UI 组件
│ │ │ │ ├── common/ # 通用组件(按钮、输入框等)
│ │ │ │ └── business/ # 业务组件(用户卡片、商品列表等)
│ │ │ ├── viewmodel/ # 视图模型(MVVM 架构,处理 UI 逻辑)
│ │ │ ├── model/ # 数据模型(定义数据结构)
│ │ │ ├── service/ # 服务层(封装业务逻辑)
│ │ │ ├── repository/ # 仓库层(数据访问抽象,隔离数据源)
│ │ │ ├── utils/ # 工具函数(通用工具、辅助方法)
│ │ │ └── constants/ # 常量配置(接口地址、枚举等)
│ │ ├── resources/ # 资源文件(字符串、图片、样式等)
│ │ └── module.json5 # 模块配置(能力、权限等)
│ └── build-profile.json5 # 构建配置
├── common/ # 共享库模块(多模块共享的代码)
│ └── src/main/ets/
├── features/ # 功能模块(按业务拆分,如首页、个人中心)
│ ├── feature_home/
│ └── feature_profile/
└── build-profile.json5 # 项目全局构建配置
同时,明确分层架构的职责边界,确保代码解耦:
-
UI 层(Pages):仅负责页面展示,不处理复杂业务逻辑,通过 ViewModel 获取数据。
-
ViewModel 层:处理 UI 相关逻辑,管理页面状态,调用 Service 层方法获取数据。
-
Service 层:封装核心业务逻辑,协调多个 Repository,对外提供统一的业务接口。
-
Repository 层:抽象数据访问,隔离本地存储(如 Preferences、RDB)和远程接口(如 HTTP 请求)。
-
Data Sources:实际的数据源,包括本地存储和远程接口请求。
3. 高频场景实战:组件、导航与网络请求
场景 1:ArkUI 组件开发(以商品卡片为例)
组件开发需遵循“单一职责”原则,封装 UI 结构、局部状态和事件处理,确保可复用性。
import { router } from '@kit.ArkUI';
@Component
export struct ProductCard {
// 父组件传递的属性(只读)
@Prop product: Product;
// 父组件传递的回调函数
@Prop onAddToCart: (product: Product) => void;
// 组件局部状态
@State isExpanded: boolean = false;
// 计算属性(通过 getter 封装衍生数据)
get formattedPrice(): string {
return `¥${this.product.price.toFixed(2)}`;
}
// 生命周期钩子:组件即将显示
aboutToAppear(): void {
console.info('ProductCard appearing');
}
// 生命周期钩子:组件即将消失
aboutToDisappear(): void {
console.info('ProductCard disappearing');
}
// 私有事件处理方法
private handleTap(): void {
// 跳转到商品详情页
router.pushUrl({ url: 'pages/ProductDetail', params: { id: this.product.id } });
}
private handleAddToCart(): void {
// 触发父组件传递的回调
this.onAddToCart(this.product);
}
// UI 构建
build() {
Column() {
Image(this.product.imageUrl)
.width('100%')
.aspectRatio(1)
.objectFit(ImageFit.Cover)
Text(this.product.name)
.fontSize(16)
.fontWeight(FontWeight.Medium)
Text(this.formattedPrice)
.fontSize(14)
.fontColor('#FF6B00')
Button('Add to Cart')
.onClick(() => this.handleAddToCart())
}
.padding(12)
.backgroundColor(Color.White)
.borderRadius(8)
.onClick(() => this.handleTap())
}
}
场景 2:导航模式(推荐 HarmonyOS NEXT 导航组件)
HarmonyOS 提供了两种导航方式:路由导航(router)和导航组件(Navigation),其中 Navigation 组件更适配 HarmonyOS NEXT,支持路径栈管理,体验更流畅。
// 主页面(导航入口)
@Entry
@Component
struct MainPage {
// 提供导航路径栈,供子组件消费
@Provide('navPathStack') navPathStack: NavPathStack = new NavPathStack();
// 页面构建器:根据路径名称渲染对应页面
@Builder
pageBuilder(name: string, params: object) {
if (name === 'detail') {
DetailPage({ params: params as DetailParams })
} else if (name === 'settings') {
SettingsPage()
}
}
build() {
Navigation(this.navPathStack) {
Column() {
Button('Go to Detail')
.onClick(() => {
// 跳转到详情页,传递参数
this.navPathStack.pushPath({ name: 'detail', param: { id: '123' } });
})
}
}
.navDestination(this.pageBuilder)
.title('Home')
}
}
// 详情页面(导航目标页)
@Component
struct DetailPage {
// 消费主页面提供的导航路径栈
@Consume('navPathStack') navPathStack: NavPathStack;
// 接收传递的参数
params: DetailParams = { id: '' };
build() {
NavDestination() {
Column() {
Text(`Product ID: ${this.params.id}`)
Button('Back')
.onClick(() => this.navPathStack.pop()) // 返回上一页
}
}
.title('Detail')
}
}
场景 3:网络请求(封装 HTTP 客户端)
网络请求需封装统一的客户端,处理请求头、授权、错误处理等通用逻辑,避免重复编码,同时提高代码可维护性。
import { http } from '@kit.NetworkKit';
// 定义接口响应通用格式
interface ApiResponse<T> {
code: number;
message: string;
data: T;
}
class HttpClient {
private baseUrl: string = 'https://api.example.com';
// GET 请求封装
async get<T>(path: string): Promise<T> {
const httpRequest = http.createHttp();
try {
const response = await httpRequest.request(
`${this.baseUrl}${path}`,
{
method: http.RequestMethod.GET,
header: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${await this.getToken()}` // 授权令牌
},
expectDataType: http.HttpDataType.OBJECT
}
);
if (response.responseCode === 200) {
const result = response.result as ApiResponse<T>;
if (result.code === 0) {
return result.data; // 接口请求成功,返回数据
}
throw new Error(result.message); // 接口返回错误信息
}
throw new Error(`HTTP ${response.responseCode}`); // HTTP 状态码错误
} finally {
httpRequest.destroy(); // 销毁请求,避免内存泄漏
}
}
// POST 请求封装
async post<T, R>(path: string, data: T): Promise<R> {
const httpRequest = http.createHttp();
try {
const response = await httpRequest.request(
`${this.baseUrl}${path}`,
{
method: http.RequestMethod.POST,
header: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${await this.getToken()}`
},
extraData: JSON.stringify(data), // 请求体数据
expectDataType: http.HttpDataType.OBJECT
}
);
const result = response.result as ApiResponse<R>;
return result.data;
} finally {
httpRequest.destroy();
}
}
// 获取授权令牌(从 AppStorage 中获取)
private async getToken(): Promise<string> {
return AppStorage.get('authToken') ?? '';
}
}
// 导出单例对象,全局复用
export const httpClient = new HttpClient();
四、避坑指南:测试与检查清单
1. 测试最佳实践
测试分为单元测试和 UI 测试,分别针对业务逻辑和 UI 交互,覆盖核心场景,减少线上 Bug。
单元测试(以 ViewModel 为例)
import { describe, it, expect, beforeEach } from '@ohos/hypium';
import { ProductViewModel } from '../viewmodel/ProductViewModel';
export default function ProductViewModelTest() {
describe('ProductViewModel', () => {
let viewModel: ProductViewModel;
// 每个测试用例执行前初始化 ViewModel
beforeEach(() => {
viewModel = new ProductViewModel();
});
// 测试:成功加载商品列表
it('should load products successfully', async () => {
await viewModel.loadProducts();
expect(viewModel.products.length).assertLarger(0);
expect(viewModel.isLoading).assertFalse();
expect(viewModel.errorMessage).assertEqual('');
});
// 测试:成功添加商品
it('should add product to list', async () => {
const initialCount = viewModel.products.length;
const newProduct: Product = { id: 'test', name: 'Test Product', price: 99 };
await viewModel.addProduct(newProduct);
expect(viewModel.products.length).assertEqual(initialCount + 1);
});
});
}
UI 测试(以商品页面为例)
import { describe, it, expect } from '@ohos/hypium';
import { Driver, ON } from '@ohos.UiTest';
export default function ProductPageUITest() {
describe('ProductPage UI', () => {
// 测试:商品列表正常显示
it('should display product list', async () => {
const driver = Driver.create();
await driver.delayMs(1000); // 等待页面加载
// 查找 List 组件,验证其存在
const list = await driver.findComponent(ON.type('List'));
expect(list).not().assertNull();
// 查找 ListItem 组件,验证列表有数据
const items = await driver.findComponents(ON.type('ListItem'));
expect(items.length).assertLarger(0);
});
// 测试:点击商品卡片跳转到详情页
it('should navigate to detail on tap', async () => {
const driver = Driver.create();
// 查找第一个商品卡片并点击
const card = await driver.findComponent(ON.type('ProductCard'));
await card.click();
await driver.delayMs(500); // 等待导航完成
// 验证跳转至详情页(通过标题判断)
const detailTitle = await driver.findComponent(ON.text('Product Detail'));
expect(detailTitle).not().assertNull();
});
});
}
2. 开发检查清单
开发完成后,对照以下清单自查,确保所有规范都已遵守:
项目设置自查
-
✅ 使用阶段模型(未使用 FA 模型)
-
✅ module.json5 配置正确(能力、权限等)
-
✅ 必要权限已在 module.json5 中声明
-
✅ 资源文件(字符串、图片)组织规范
代码质量自查
-
✅ 代码中无 any 类型
-
✅ 所有状态都使用了正确的装饰器
-
✅ 无直接修改 @State 对象的写法
-
✅ 可复用 UI 已提取为独立组件
-
✅ 生命周期方法使用恰当
UI/UX 自查
-
✅ 长列表使用 LazyForEach(避免性能问题)
-
✅ 实现了加载状态(避免用户困惑)
-
✅ 错误处理有用户反馈(如提示文本)
-
✅ 使用 GridRow/GridCol 实现多设备适配
-
✅ 添加了可访问性属性(适配无障碍)
五、总结:用标准化提升 HarmonyOS 开发效率
-
快速掌握规范开发流程,减少隐性 Bug;
-
复用高频场景代码,提升开发效率;
-
搭建可扩展、可维护的项目架构,降低后期维护成本;
-
适配 HarmonyOS 最新特性,确保应用兼容性。
后续开发中,也可以结合官方提供的参考文档,深入学习 HarmonyOS 开发细节,打造更高质量的应用。
> (注:文档部分内容可能由 AI 生成)
更多推荐


所有评论(0)