| name | harmonyos-development |
| description | Use when developing, reviewing, debugging, or migrating HarmonyOS NEXT native apps with ArkTS, ArkUI, DevEco Studio, DevEco Code, DevEco CLI, Agent Framework Kit, Stage model, UIAbility, .ets, module.json5, oh-package.json5, HAP/HSP/HAR, API 22-24, API 26 Beta1, HarmonyOS 6.1, HarmonyOS 6.1.1 Release, HarmonyOS 7 preview, HarmonyOS 26.0.0 Beta1, state management decorators, Navigation/NavPathStack, ArkTS concurrency, permissions, persistence, networking, media, Camera Kit, Scan Kit, Map Kit, Push Kit, Payment Kit, App Linking, Share Kit, Weather Service Kit, ArkGuard, testing, performance, or common 鸿蒙开发 workflows.
|
HarmonyOS (鸿蒙) Development
Covers HarmonyOS 6.1 (API 23, stable) / 6.1.1 (API 24, Release) / HarmonyOS 7 developer preview (API 26 Beta1) / NEXT native app development — the Huawei mobile OS family that runs independently of Android (AOSP-free since HarmonyOS NEXT, released 2024). Primary language is ArkTS (a strict, statically-checked superset of TypeScript) and the primary UI framework is ArkUI (declarative, state-driven). Use API 24 Release as the default production baseline; use API 26 Beta1 only for preview, adaptation, and early compatibility work.
Platform snapshot
| Item | Value |
|---|
| OS | HarmonyOS 6.1 (stable, released 2026/04/20, API 23). HarmonyOS 6.1.1 (Release, released 2026/05/26, API 24). HarmonyOS 7 / 26.0.0 Beta1 (developer preview, released 2026/06/12, API 26). Pure HarmonyOS, AOSP-free |
| Language | ArkTS (primary), Cangjie (beta), C/C++ via NAPI |
| UI framework | ArkUI declarative (ArkUI-X for cross-platform) |
| Compiler | ArkCompiler — AOT to native machine code; LiteActor concurrency |
| Package manager | ohpm — oh-package.json5; registry at DevEco Service (OHPM Central) |
| IDE | DevEco Studio 6.1.1 Release (6.1.1.280; API 24 production). DevEco Studio 26.0.0 Beta1 (26.0.0.461; API 26 preview) |
| App model | Stage model (FA model is legacy — don't use in new apps) |
| Packaging | HAP (entry/feature), HSP (shared package), HAR (static archive), atomic .app |
| Recommended API | Use API 24 Release for production. Use API 26 Beta1 only for HarmonyOS 7 preview/adaptation. |
| Sample catalog | https://developer.huawei.com/consumer/cn/samples/ |
Release timeline (recent):
- HarmonyOS 6.0.1(21) — 2025/11/25 (initial stable with Mate 80 series)
- HarmonyOS 6.0.2(22) — 2026/01/23 (incremental update)
- HarmonyOS 6.0.0.328 Pollen Beta(23) — 2026/02/28 (closed beta, 25 models)
- HarmonyOS 6.1(23) — 2026/04/20 (stable general release)
- HarmonyOS 6.1.1(24) Beta 1 — 2026/04/30 (developer beta)
- HarmonyOS 6.1.1(24) Release — 2026/05/26 (API 24 Release; DevEco Studio 6.1.1.280)
- HarmonyOS 7 / 26.0.0 Beta1 — 2026/06/12 (API 26 developer preview; DevEco Studio 26.0.0.461)
What's new in API 23 (HarmonyOS 6.1)
ArkUI enhancements:
Navigation supports binding the routing stack to the component itself and specifying a NavDestination as the navigation bar (home page) — no more separate root container needed
Menu adds anchorPosition property: control popup position relative to upper-left of anchor with horizontal/vertical offsets
Image component improved SVG parsing capabilities
- Batch of new C APIs for attribute styles (Native side)
New C-side capabilities (Native/NAPI):
- UDMF (Unified Data Management Framework) C APIs
- Component drag-and-drop C APIs
- Cryptographic algorithm C APIs
Data:
relationalStore enhanced sendable function — better cross-thread data passing
Graphics & AI:
- AI super frame feature in Graphics Accelerate Kit (frame interpolation for smoother animations)
ArkWeb: further capability enhancements (intercept/cookies)
What's new in API 24 (HarmonyOS 6.1.1 Release)
Version baseline: API 24 is now a Release SDK (not only Beta). Use DevEco Studio 6.1.1 Release (6.1.1.280), HarmonyOS SDK 6.1.1 Release, Hvigor 6.24.2, ohpm 6.1.2.268, and Node.js 18.20.1 for API 24 projects.
Release additions over Beta1:
- Ability Kit —
AbilityStage adds callbacks before the first Ability is created and when a process starts from an application snapshot.
- ArkTS — adds
enableLocalHandleDetection to keep EventHandler/libuv tasks inside the intended scope and avoid leaks; XML parsing adds XmlSAXHandler callbacks for SAX-style parsing.
- ArkWeb — download completion callbacks can retrieve the original URL and referrer URL.
- Call Service Kit — enterprise call service lookup for incoming/outgoing phone numbers.
- Camera Kit professional controls — flash-state event subscribe/unsubscribe; OIS query/set; lens focal length/equivalent focal length/min focus distance/distortion/intrinsic calibration/sensor size/pixel array/color-filter data; logical camera composition; auto/manual exposure; manual focus; ISO; physical aperture.
- CANN Kit — large-language-model inference acceleration APIs on PC devices.
- MDM Kit — manage hidden settings entries for the current user.
Beta1 additions still relevant in API 24 Release:
HarmonyOS 7 / API 26 Beta1 preview (2026/06/12)
Status: developer Beta, not the default production baseline. Mention API 26 features only when the user asks about HarmonyOS 7, API 26, HDC 2026, preview adaptation, or Beta1 capabilities. For production code, prefer API 24 Release unless the project explicitly targets API 26 preview.
Developer kit baseline: HarmonyOS SDK 26.0.0 Beta1 (OpenHarmony SDK Ohos_sdk_public 26.0.0.23, API Version 26.0.0 Beta1) and DevEco Studio 26.0.0 Beta1 (26.0.0.461). Toolchain: HarmonyOS Emulator 26.0.0.200, Hvigor/hvigorw 6.26.1, ohpm 26.0.0.410, Node.js 24.14.1, hstack 6.0.0, compileSdkVersion: "26.0.0", targetSdkVersion: "4.0.0(10)~26.0.0".
Version-number rule: Starting with API 26.0.0, HarmonyOS developer kit API versions use SemVer (X.Y.Z) instead of the legacy X.Y.Z(N) format. X means a major version with substantial capabilities or adaptation-impacting changes, Y means a minor version with new capabilities, and Z means compatible fixes/small improvements.
High-value API 26 Beta1 changes:
- Ability Kit — AgentCard support; ArkTS script-based app Skill development; package-name + clone-index app name lookup; ArkTS APIs for script management; C APIs for
ModularObjectExtensionAbility.
- Accessibility Kit — system care mode integration for elder-friendly app experiences.
- Accessory Kit — new Kit for accessory wake-up, system service linkage, on-demand scheduling, and secure trust management.
- Account Kit —
LoginWithHuaweiIDButton supports custom multilingual text and loading animation.
- AR Engine — C API camera flash control; ArkTS preview stream image access; 3D Gaussian model loading; ArkTS/C APIs for external camera and sensor data.
- ArkUI / UI Design — system material configuration for Toggle, Tips, Toast, dialogs, menus, popups, custom dialogs, half modals, and Popup; component-level immersive light perception; global reuse pools for
@Reusable / @ReusableV2; standard floating windows; title-area customization updates.
- ArkWeb — Chromium kernel upgraded from 132 to 144; new security configuration options.
- AVCodec Kit — H.265 hardware encoder CBRHQ mode; Audio Vivid encoding and C APIs.
- AVSession Kit — new extra-key enum values for scenario-specific AVSession metadata.
- Background Tasks Kit — reminder countdown instances add
repeatInterval and repeatCount.
- Core File Kit —
UNCACHE open option, recursive listFileExt, mmap-based file mapping, and sharing an app sandbox directory as system-visible.
- Core Vision Kit — image super-resolution and semantic text search over images.
- Data Augmentation Kit — mail intelligence handler for classification, summarization, and todo extraction.
- Device Security Kit — enhanced Star Shield confidential risk-control engine, unified risk-control credentials, privacy policy controls for camera/microphone/location, and file-event subscription/filtering.
- Driver Development Kit — query external USB hubs and develop user-mode drivers.
- Enterprise Data Guard Kit — file classification policy APIs
getPolicy and isKia.
- Enterprise Space Kit — query dual-space state and determine whether the workspace is enterprise space.
- FAST Kit — real-number FFT and inverse FFT; intelligent sequence prediction.
- Graphics Accelerate Kit — game prelaunch feature to improve startup experience.
- Image Kit — metadata classes for GIF/JFIF/TIFF/PNG/AVIS plus XMP metadata.
- Input Kit — keyboard and mouse input event injection.
- Live View Kit — auxiliary-area template with percentage progress ring.
- NDK / JSVM — create
ArrayBuffer from external memory.
- NearLink Kit —
startScan scans all discoverable nearby NearLink devices.
- Network Boost Kit —
netBoost.setDataFlowDesc sets flow descriptions from five-tuple data.
- Notification Kit — stronger notification management/display, including half-modal notification settings entry.
- Online Authentication Kit — DID (Decentralized Identifier) key generation, credential import/query/delete, and data signing.
- PDF Kit — convert specified regions across multiple pages into one image.
- Performance Analysis Kit — gray release fault-log collection and HiAppEvent app-freeze warning subscriptions.
- Preview Kit — file acceleration scanning, preload strategy customization, availability query, and file-operation event reporting.
- Push Kit — Live View push messages support Wearable devices.
- Remote Communication Kit —
HttpVersionSelectCallback for HTTP version selection, HMS_Rcp_SetRequestGetDataCallback() for streaming upload, HMS_Rcp_SetFormOrder() for ordered forms, and QUIC C API.
- Scenario Fusion Kit — scenario sharing Button supports image, video, and text.
- Share Kit — phone-to-PC/2in1/tablet tap sharing can expose tap position on the receiving side.
- Spatial Recon Kit — 3DGS gaussian editing and spatial photo generation from a single photo.
- Scan Kit — query support for default/custom scan UI on the current device.
API 26 behavior and UX changes to watch during adaptation:
- Ability Kit — public package-change common events (
COMMON_EVENT_PACKAGE_ADDED, REMOVED, CHANGED, CACHE_CLEARED) add controls for In-House apps when targetSdkVersion >= 26.0.0; In-House apps must configure allowListenBundleChangedEvent in app.json5 for third-party listeners.
- ArkTS / JSVM — Chromium/V8 core upgrades 132 → 144; async function type detection is fixed; Wasm jitless default behavior changes;
fastConvertToJSObject now preserves sibling text nodes when parsing XML.
- ArkUI —
NodeAdapter.onAttachToNode, mouse rawDeltaX/rawDeltaY, LayoutPolicy.matchParent, EmbeddedComponent focus, WithTheme, queryNavDestinationInfo / onResult on the home NavDestination, NODE_SWIPER_EVENT_ON_CONTENT_DID_SCROLL, and shadow blur radius behavior have adaptation-impacting changes.
- Permissions —
ohos.permission.READ_IMAGEVIDEO, getUidRxBytes, getUidTxBytes, and general permission policy behavior change under API 26 rules.
- UX — form controls minimum touch target changes from 28vp to 32vp for Button/Button-style Toggle/Select/Chip/ChipGroup; built-in text line breaking and small-language line height are optimized; Dialog, Toast, AlphabetIndexer, and text selection menu enable immersive system material by default. Disable globally with
metadata name ohos.arkui.UIMaterial.state value disable, or per component with uiMaterial.Material.empty.
API 26 V2 behavior-scope notes (official docs updated 2026/06/17):
- Always effective: JSVM/Chromium 132 → 144, async function type detection,
fastConvertToJSObject sibling-text preservation, ArkUI rawDeltaX/rawDeltaY, Stage-only ArkUI API constraints, home NavDestination queryNavDestinationInfo / onResult, @ReusableV2 dynamic reuse identifiers, ArkWeb Chromium 132 → 144, READ_IMAGEVIDEO permission behavior, and notofonts small-language font updates.
- Effective only when
targetSdkVersion >= 26.0.0: In-House package-change event controls, JSVM Wasm jitless default behavior, NodeAdapter.onAttachToNode, attributed-string paragraph style with leading CustomSpan / ImageAttachment, LayoutPolicy.matchParent, EmbeddedComponent focus, WithTheme, NODE_SWIPER_EVENT_ON_CONTENT_DID_SCROLL, component shadow blur radius, getUidRxBytes / getUidTxBytes, permission policy changes, 32vp form-control touch targets, built-in text style optimization, immersive material defaults, and half-modal centered dialog max height.
DevEco Studio 26.0.0 Beta1 additions:
- AI coding: custom Agent token usage display, conversation rollback, project Q&A with MCP Market tools / LSP tools / ArkTS and C++ semantic code search, built-in Inline Chat commands such as File Comments and Parameter Validation,
UI Verification tool, and custom Commands.
- Editing/debugging: API 26.0.0 projects, Load/Unload Modules, ArkUI state-variable relation viewer, Code Scanner resource-leak checks, custom Clang-Tidy, ACL permission requests, 8-breakpoint preview, Car multi-screen emulator, scenario simulation, remote emulator control, Native debug startup acceleration, device projection, SQL-highlight database debugging, dump-file stack parsing, HiLog tag filtering, AppAnalyzer report diagnosis, and diagnostics for OOM/app-freeze/resource leaks.
- Performance analysis: Memory lane adds ArkWeb PA and JS Heap sub-lanes for Malloc allocation and ArkWeb Render-process JS heap usage, plus a Statistics tab for VMA counts and PSS memory min/max/average.
- Build/release:
apiCompatibilityCheck, tsImportSoCheck, module nativeLib.enableSoDirCollection, syncNative, Hvigor getAllDependencyInfo, AppGallery package re-signing, Linux emulator support, and ohpmrc auto_skip_install, metadata_cache_effective, metadata_cache, plus exact-version metadata queries.
- Compatibility changes: DevEco Studio and Command Line Tools upgrade Node.js from 18 to 24; custom Hvigor/ohpm/ohpm-repo plugins need Node.js 24 adaptation.
ohpm-repo 5.5.1 no longer depends on node-fetch; plugins that relied on that bundled dependency must replace it or install node-fetch@2.7.0 themselves.
DevEco Testing 26.0.0 Beta1:
- Stability testing can target specified entry points to trigger stability issues and expands memory-leak detection coverage.
- UX testing supports multi-device layout comparison across straight-screen and foldable devices.
- Test-service matrix includes local app listing precheck, performance baseline/monitoring, stability baseline, memory-leak testing, UX baseline and multi-device layout comparison, security baseline, power baseline, functional-experience baseline, exploratory testing, regression testing, device projection, UIViewer, app graph management, performance report auto-analysis, and report comparison.
HarmonyOS AI development tools and capability highlights (officially surfaced 2026/06):
- DevEco Code — a HarmonyOS-focused AI coding Agent for planning, code generation, build/run, device logs, UI verification, ArkTS checking, knowledge lookup, debugging, and iterative repair. It complements DevEco Studio rather than replacing the SDK/toolchain.
- DevEco CLI — Agent-friendly command-line access to project creation, syntax checks, build, device run/debug, and other HarmonyOS engineering actions; use it for third-party coding Agents, automation, and CI/CD integration.
- Agent Framework Kit — launches a combination of system Agents from an app through UI controls. Keep it distinct from Intents Kit (declaring app intents), ArkTS script-based app Skills (exposing app capabilities), and device-side A2A (Agent-to-Agent communication).
- HarmonyOS 7 experience areas — spatial-audio processing nodes, app/game quick start, cold-start network preconnection, QUIC and weak-network live-stream optimization, and LTPO variable frame rate are highlighted platform capabilities; confirm the installed API 26 SDK and device support before presenting them as generally available APIs.
- API 26 cloud debugging — AGC remote-device cloud debugging can filter devices by API 26 or system version
7.0.0.23 for early compatibility validation.
For tool selection, capability boundaries, and answer rules, read references/ai-development-tools.md.
Official documentation updates (2026/06/12)
Huawei's release docs did not add a newer SDK after 26.0.0 Beta1, but the documentation change log added several developer-facing guides worth surfacing in answers:
- Ability Kit app lifecycle — new guides cover full app lifecycle state changes, startup configuration such as window mode and start page path, quick-start launch, user/app/system exits, and active/passive restart flows.
- Ark Intelligence Development Framework — new guides cover the framework overview, Intent Framework development, ArkTS script-based app Skill development, and device-side A2A framework development for exposing app capabilities to system agents such as Xiaoyi.
- Window management — 20+ development scenarios were reorganized and expanded, including window type, mode, layout, focus, and a new guide for locating common window logs/issues with
hidumper.
- ArkTS Sendable practice — new Sendable migration/practice guide demonstrates using TurboTransJSON to operate on Sendable objects in ArkTS.
- FA model docs moved — FA model is no longer the recommended app model except mainly for lightweight smart wearables; general HarmonyOS app docs now retain Stage model content, while FA model guidance moved under lightweight wearable app development basics.
Project layout (Stage model)
MyApp/
├─ AppScope/
│ ├─ app.json5 # global app config (bundleName, icon, label)
│ └─ resources/ # shared resources
├─ entry/ # main HAP (entry module)
│ ├─ src/main/
│ │ ├─ ets/
│ │ │ ├─ entryability/EntryAbility.ets # UIAbility subclass
│ │ │ ├─ entrybackupability/
│ │ │ └─ pages/Index.ets # ArkUI pages
│ │ ├─ resources/ # strings, colors, media, profiles
│ │ └─ module.json5 # module config, abilities, permissions
│ └─ build-profile.json5
├─ oh-package.json5 # ohpm dependencies
└─ build-profile.json5 # project-level
The Stage model — core concepts
Component types
- UIAbility — has UI, handles user interaction. Entry points. One instance per task.
- ExtensionAbility — background / extension scenarios:
ServiceExtensionAbility — background services (system apps)
FormExtensionAbility — home-screen widget (服务卡片)
WorkSchedulerExtensionAbility — deferred tasks
InputMethodExtensionAbility, WallpaperExtensionAbility, BackupExtensionAbility, etc.
- AbilityStage — module-level lifecycle container (one per HAP)
- WindowStage — window container scoped to a UIAbility
UIAbility lifecycle
import { UIAbility, Want, AbilityConstant } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { }
onDestroy(): void { }
onWindowStageCreate(windowStage: window.WindowStage): void {
windowStage.loadContent('pages/Index', (err) => { });
}
onWindowStageDestroy(): void { }
onForeground(): void { }
onBackground(): void { }
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void { }
}
Launching another ability
import { common, Want } from '@kit.AbilityKit';
const ctx = getContext(this) as common.UIAbilityContext;
const want: Want = {
bundleName: 'com.example.app',
abilityName: 'DetailAbility',
parameters: { id: 42 }
};
ctx.startAbility(want);
module.json5 essentials
{
"module": {
"name": "entry",
"type": "entry", // entry | feature | shared
"srcEntry": "./ets/entryability/EntryAbility.ets",
"deviceTypes": ["phone", "tablet", "2in1"],
"abilities": [{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"skills": [{
"actions": ["action.system.home"],
"entities": ["entity.system.home"]
}]
}],
"requestPermissions": [
{ "name": "ohos.permission.INTERNET" }
]
}
}
ArkTS language — strictness rules
ArkTS = TypeScript MINUS dynamic patterns, PLUS stricter static typing for AOT perf.
Prohibited / changed vs TS:
- No
any / unknown as everyday escape hatches — declare real types
- No dynamic property add/delete on objects (
obj.foo = bar on untyped object is a compile error)
- No
Function.prototype.bind, call, apply with reshaped this
- No structural typing shortcuts — use nominal classes / interfaces
- No
Object.keys/Object.assign for arbitrary reshaping
Record<K,V> for true dictionary maps
- Use
class / interface with explicit fields
class User { constructor(public id: number, public name: string) {} }
Naming conventions (official coding style guide)
| Element | Convention | Example |
|---|
| Classes, Structs, Enums | UpperCamelCase | PersonInfo, ColorType |
| Variables, Parameters, Methods | lowerCamelCase | userName, getUserInfo() |
| Constants | UPPER_SNAKE_CASE | MAX_VALUE, DEFAULT_TIMEOUT |
| Boolean variables | Prefix with is, has, can | isVisible, hasPermission |
Formatting: 2-space indent, max 120 chars/line, K&R braces, always use {} for if/for/while.
High-performance ArkTS rules (from official best practices)
- Use
const for unchanging values — enables engine optimization
- Never mix int and float in same variable —
let n = 1; n = 1.1; causes boxing overhead
- Use TypedArrays (
Int8Array, Float32Array) for numerical computation
- Avoid sparse arrays —
arr[9999] = 0 forces hash-table storage (much slower)
- Don't mix types in arrays —
[1, "a", 2] deoptimizes
- Cache property lookups outside hot loops
- Avoid exception throwing in perf-critical loops — use sentinel values
- Minimize closures in hot paths — pass variables via function params instead
- Use Array methods (
forEach, map, filter, reduce) — internally optimized
- Keep
build() pure and declarative — no side effects, load data in aboutToAppear()
- Use
HashMap instead of Record for key-value operations — faster lookup/insert
- Reduce multi-level indirect exports — prefer direct
export { foo } from './module'
- Use lazy import (
import lazy { Foo } from './heavy') for modules not needed at startup
ArkUI — declarative UI
Custom component basics
@Entry
@Component
struct Index {
@State count: number = 0;
build() {
Column({ space: 12 }) {
Text(`Count: ${this.count}`)
.fontSize(24)
.fontWeight(FontWeight.Bold)
Button('Increment')
.onClick(() => { this.count++; })
}
.width('100%').height('100%').justifyContent(FlexAlign.Center)
}
}
Component lifecycle callbacks
All @Component:
| Callback | When | Notes |
|---|
aboutToAppear() | After created, BEFORE build() | Can change state here; changes apply in first build() |
onDidBuild() | After build() completes | Do NOT change state or call animateTo(). API 12+ |
aboutToDisappear() | Before destruction | Do NOT change state (especially @Link). No async/await |
aboutToReuse(params) | Reusable component re-added from cache | Update state with new params. API 10+ |
aboutToRecycle() | Component moving to reuse cache | Release heavy resources. API 10+ |
Only @Entry:
| Callback | When |
|---|
onPageShow() | Each time page is displayed |
onPageHide() | Each time page is hidden |
onBackPress(): boolean | User taps Back. Return true to override default |
Execution order (cold start):
Parent aboutToAppear → Parent build → Parent onDidBuild → Child aboutToAppear → Child build → Child onDidBuild → onPageShow
Layout containers
| Container | When to use | Performance |
|---|
Column / Row | Linear arrangement | Best — single-pass layout |
Stack | Overlapping / stacking | Good |
Flex | Items need stretch/shrink | Slower — extra pass for flexGrow/flexShrink |
RelativeContainer | Complex layouts, avoid deep nesting | Good — flat structure |
GridRow / GridCol | Responsive multi-device grids | Good |
List | Scrollable list with recycling | Best for long lists (with LazyForEach) |
Column/Row alignment:
- Main axis:
justifyContent(FlexAlign.Start | .Center | .End | .SpaceBetween | .SpaceAround | .SpaceEvenly)
- Cross axis: Column →
alignItems(HorizontalAlign.Start | .Center | .End), Row → alignItems(VerticalAlign.Top | .Center | .Bottom)
Stack: alignContent takes 9 positions (TopStart, Top, TopEnd, Start, Center, End, BottomStart, Bottom, BottomEnd). zIndex controls layer order.
Flex vs Column/Row: Flex requires re-layout for flexShrink/flexGrow. Always prefer Column/Row when you don't need flex behavior.
RelativeContainer: Use __container__ as anchor ID for the container itself. Each child needs .id(). Set .alignRules({ top: { anchor: 'id', align: VerticalAlign.Bottom } }).
Blank(): Fills remaining space in Row/Column — use for "label ... value" layouts: Row() { Text('Name'); Blank(); Text('Value') }.
displayPriority: Lower-priority children auto-hide when container shrinks. Row() { A().displayPriority(1); B().displayPriority(3); C().displayPriority(1) } — A and C hide first.
layoutWeight: Proportional sizing — Row() { Column().layoutWeight(1); Column().layoutWeight(2) } gives 1:2 ratio.
AttributeModifier — reusable style object:
class PrimaryButtonModifier implements AttributeModifier<ButtonAttribute> {
applyNormalAttribute(instance: ButtonAttribute): void {
instance.width('100%').height(48).fontSize(16).fontColor(Color.White).backgroundColor('#007DFF');
}
applyPressedAttribute(instance: ButtonAttribute): void {
instance.backgroundColor('#0056B3');
}
}
Button('Submit').attributeModifier(new PrimaryButtonModifier())
Performance-critical patterns
LazyForEach for large lists (only renders visible items):
class MyDataSource implements IDataSource {
private data: string[] = []
totalCount(): number { return this.data.length }
getData(index: number): string { return this.data[index] }
registerDataChangeListener(listener: DataChangeListener): void { }
unregisterDataChangeListener(listener: DataChangeListener): void { }
}
List() {
LazyForEach(this.dataSource, (item: string, index: number) => {
ListItem() { Text(item) }
}, (item: string) => item)
}
.cachedCount(5)
@Reusable components (69% faster component creation):
@Reusable
@Component
struct MyListItem {
@State message: Message = new Message('default')
aboutToReuse(params: Record<string, ESObject>) {
this.message = params.message as Message
}
aboutToRecycle() { }
build() { Text(this.message.value) }
}
Rules: only works within same parent; don't nest @Reusable inside @Reusable; combine with LazyForEach.
Layout performance rules:
- Max 3 levels of nesting — each level adds layout cost
- Use
if/else over .visibility() — hidden components still participate in layout
- Use
RelativeContainer to flatten deep Row/Column/Flex hierarchies (documented 26% improvement)
- Set explicit dimensions on
List inside Scroll — without them ALL children load at once
- Avoid
@StorageLink for frequently-changing data — propagates to all subscribers
onVisibleAreaChange — trigger logic when component enters/leaves viewport:
Image(item.url)
.onVisibleAreaChange([0.0, 1.0], (isVisible: boolean, currentRatio: number) => {
if (isVisible && currentRatio >= 1.0) { this.loadHighRes(); }
if (!isVisible) { this.releaseImage(); }
})
Use cases: lazy image loading, video auto-play/pause on scroll, exposure analytics.
Animation
Explicit animation (animateTo) — state changes in closure animate:
this.getUIContext()?.animateTo({
duration: 300,
curve: Curve.EaseOut,
onFinish: () => { console.info('done') }
}, () => {
this.width = 200
})
Property animation (.animation()) — implicit, applied to preceding attributes:
Text('Hello')
.width(this.myWidth)
.animation({ duration: 500, curve: Curve.EaseIn })
Curve values: Curve.Linear | .Ease | .EaseIn | .EaseOut | .EaseInOut | .FastOutSlowIn | .Friction | .Sharp | .Smooth
Spring curves (string): 'spring(velocity,mass,stiffness,damping)', 'springMotion(response,dampingFraction)', 'responsiveSpringMotion(response,dampingFraction)'
Shared element transition:
Image($r('app.media.photo')).geometryTransition('picture')
this.getUIContext()?.animateTo({ duration: 300 }, () => { this.isExpanded = !this.isExpanded })
Keyframe animation (keyframeAnimateTo) — multi-step sequences:
this.getUIContext()?.keyframeAnimateTo({ iterations: 2 }, [
{ duration: 100, event: () => { this.translateX = 10; } },
{ duration: 100, event: () => { this.translateX = -10; } },
{ duration: 100, event: () => { this.translateX = 0; } },
]);
Animation performance tips: Prefer transform properties (scale/translate/rotate/opacity) over layout properties (width/height/margin) — transforms skip re-layout.
Tabs — bottom/top navigation
@Entry @Component
struct MainPage {
@State currentIndex: number = 0;
@Builder tabBuilder(index: number, title: string, icon: Resource) {
Column() {
SymbolGlyph(icon).fontSize(24)
.fontColor([this.currentIndex === index ? '#007DFF' : '#99000000'])
Text(title).fontSize(10).margin({ top: 4 })
.fontColor(this.currentIndex === index ? '#007DFF' : '#99000000')
}.justifyContent(FlexAlign.Center).height('100%').width('100%')
}
build() {
Tabs({ barPosition: BarPosition.End }) {
TabContent() { HomePage() }
.tabBar(this.tabBuilder(0, 'Home', $r('sys.symbol.house')))
TabContent() { MinePage() }
.tabBar(this.tabBuilder(1, 'Me', $r('sys.symbol.person')))
}
.barHeight(56)
.onChange((index) => { this.currentIndex = index; })
.scrollable(false)
}
}
Glass-blur tab bar: .barOverlap(true).barBackgroundBlurStyle(BlurStyle.Thin).
Swiper — carousel / banner
Swiper() {
ForEach(this.banners, (item: BannerItem) => {
Image(item.url).width('100%').height(180).borderRadius(12)
})
}
.loop(true)
.autoPlay(true)
.interval(3000)
.indicator(new DotIndicator()
.color('#33000000').selectedColor('#007DFF')
.itemWidth(8).selectedItemWidth(16))
WaterFlow — Pinterest-style layout
WaterFlow({ scroller: this.scroller }) {
LazyForEach(this.dataSource, (item: CardItem) => {
FlowItem() {
Column() {
Image(item.image).width('100%').borderRadius(8)
Text(item.title).fontSize(14).padding(8)
}
}
}, (item: CardItem) => item.id)
}
.columnsTemplate('1fr 1fr')
.columnsGap(8)
.rowsGap(8)
.cachedCount(10)
Grid — fixed grid layout
Grid() {
ForEach(this.items, (item: GridItemData) => {
GridItem() {
Column() {
Image(item.icon).width(40).height(40)
Text(item.name).fontSize(12).margin({ top: 4 })
}
}
})
}
.columnsTemplate('1fr 1fr 1fr 1fr')
.rowsGap(12)
.columnsGap(12)
.height(200)
TextInput / TextArea
TextInput({ placeholder: 'Enter username' })
.type(InputType.Normal)
.maxLength(20)
.onChange((value: string) => { this.username = value; })
.onSubmit((enterKey: EnterKeyType) => { })
TextArea({ placeholder: 'Enter description', text: $$this.desc })
.maxLength(200)
.showCounter(true)
Two-way binding with $$: TextInput({ text: $$this.value }) — no onChange needed.
Router — basic page navigation
import { router } from '@kit.ArkUI';
router.pushUrl({
url: 'pages/Detail',
params: { id: '123', title: 'Hello' }
});
const params = router.getParams() as Record<string, string>;
router.back();
router.replaceUrl({ url: 'pages/Login' });
Note: For Navigation-based apps, prefer NavPathStack.pushPath() over Router.
AlertDialog / Toast
AlertDialog.show({
title: 'Confirm',
message: 'Delete this item?',
primaryButton: { value: 'Cancel', action: () => {} },
secondaryButton: { value: 'Delete', fontColor: Color.Red,
action: () => { this.deleteItem(); }
},
});
this.getUIContext().getPromptAction().showToast({
message: 'Operation successful',
duration: 2000,
});
Common form components — quick reference
| Component | Key Props | Example |
|---|
Checkbox | select, onChange((val: boolean) => {}) | Checkbox({ name: 'agree' }).select(this.agreed) |
Toggle | type(ToggleType.Switch), isOn, onChange | Toggle({ type: ToggleType.Switch, isOn: $$this.on }) |
Radio | value, group, checked, onChange | Radio({ value: 'male', group: 'gender' }).checked(true) |
Select | options: SelectOption[], selected, value, onSelect | Select([{value:'A'},{value:'B'}]).selected(0) |
Slider | value, min, max, step, onChange | Slider({ value: $$this.val, min: 0, max: 100 }) |
DatePicker | start, end, selected, onChange | DatePicker({ selected: this.date }).onChange((v) => {}) |
TimePicker | selected, useMilitaryTime, onChange | TimePicker({ selected: this.time }) |
Search | value, placeholder, onSubmit, onChange | Search({ value: $$this.keyword, placeholder: 'Search' }) |
Progress | value, total, type(ProgressType.Linear) | Progress({ value: 60, total: 100 }) |
LoadingProgress | — | LoadingProgress().width(48).color('#007DFF') |
EventHub — UIAbility ↔ page communication
this.context.eventHub.emit('dataReady', { items: [...] });
const context = getContext(this) as common.UIAbilityContext;
context.eventHub.on('dataReady', (data: Record<string, ESObject>) => {
this.items = data.items;
});
context.eventHub.off('dataReady');
HarmonyOS 6.0 visual effects (沉浸光感视效 / 液态玻璃)
HarmonyOS 6.0 (API 23) introduces system-level "Immersive Light Perception" visual effects. Users enable via Settings → Desktop & Personalization → Immersive Light Effect (强/均衡/弱). Developers achieve similar effects through these ArkUI attributes:
BlurStyle enum (API 9–11):
| Name | Since | Level |
|---|
Thin / Regular / Thick | API 9 | Material blur |
BACKGROUND_THIN / BACKGROUND_REGULAR / BACKGROUND_THICK / BACKGROUND_ULTRA_THICK | API 10 | Depth-of-field (min→max) |
COMPONENT_ULTRA_THIN / COMPONENT_THIN / COMPONENT_REGULAR / COMPONENT_THICK / COMPONENT_ULTRA_THICK | API 11 | Component-level material |
NONE | API 10 | No blur |
backgroundBlurStyle (API 9+):
Column() { }
.backgroundBlurStyle(BlurStyle.Thin, {
colorMode: ThemeColorMode.LIGHT,
adaptiveColor: AdaptiveColor.DEFAULT,
scale: 1.0
})
foregroundBlurStyle (API 10+):
Image($r('app.media.photo'))
.foregroundBlurStyle(BlurStyle.Regular)
backgroundEffect (API 11+) — fine-grained control:
Column() { }
.backgroundEffect({
radius: 20,
saturation: 15,
brightness: 0.6,
color: '#80FFFFFF'
})
blur / backdropBlur (API 7+) — numeric radius:
Column() { }
.backdropBlur(20, { grayscale: [30, 50] })
.blur(10)
backgroundBrightness (API 12+):
Column() { }
.backgroundBrightness({ rate: 0.5, lightUpDegree: 0.2 })
Visual effect filters (API 12+):
import { uiEffect } from '@kit.ArkGraphics2D';
const blurFilter = uiEffect.createFilter().blur(10);
Column() { }
.backgroundFilter(blurFilter)
.foregroundFilter(blurFilter)
pointLight (API 11+, System API only — NOT available for third-party apps):
Flex()
.pointLight({
lightSource: { positionX: '50%', positionY: '50%', positionZ: 80, intensity: 2, color: Color.White },
illuminated: IlluminatedType.BORDER,
bloom: 0.5
})
Up to 12 light sources can illuminate a single component. HarmonyOS 6.0 adds dual-edge flow light and UV background flow light effects.
systemMaterialEffect (HDS layer, API 23+, HarmonyOS-only SDK):
import { hdsMaterial } from '@kit.ArkUI';
Column() { }
.systemMaterialEffect({
materialType: hdsMaterial.MaterialType.ADAPTIVE,
materialLevel: hdsMaterial.MaterialLevel.ADAPTIVE
})
Note: hdsMaterial is part of the closed-source HarmonyOS Design System (HDS), not OpenHarmony. Requires HarmonyOS 6.0 SDK (API 23+).
State-management decorators
| Decorator | Scope | Purpose |
|---|
@State | within component | Owned mutable state; triggers re-render |
@Prop | parent → child | One-way copy (child has local copy) |
@Link | parent ↔ child | Two-way binding (use $var to pass) |
@Provide / @Consume | ancestor → descendant | Cross-level implicit binding by key |
@Observed (class) + @ObjectLink (prop) | class instances | Observe changes to class properties |
@Watch('handler') | any of above | Callback on value change |
@StorageLink / @StorageProp | app-wide AppStorage | Global reactive state |
@LocalStorageLink / @LocalStorageProp | page-scoped | Scoped reactive state |
Passing @Link:
@Entry @Component struct Parent {
@State val: number = 0;
build() { Child({ val: $val }) }
}
@Component struct Child {
@Link val: number;
build() { Button(`${this.val}`).onClick(() => this.val++) }
}
Observing class objects:
@Observed class Task { constructor(public title: string, public done: boolean) {} }
@Component struct TaskRow {
@ObjectLink task: Task;
build() { Text(this.task.title) }
}
Arrays of @Observed instances require @ObjectLink in the row component — parent @State tasks: Task[] only reacts to array mutations (push/splice/reassign), not per-item changes.
State management performance rules (from official docs):
- Minimize state scope: only
@State variables that directly affect UI
@Prop creates deep copy on every update — for large objects, prefer @Link (by reference) or @ObjectLink
@Link is preferred for inter-component communication — avoids unnecessary re-renders
@Observed + @ObjectLink for nested objects — fine-grained property observation
@ObjectLink is READ-ONLY — cannot reassign whole object (this.task = new Task() breaks binding)
- Avoid
@StorageLink for frequently-changing data — global state changes propagate to ALL subscribers
- Observation depth (V1):
@State/@Prop/@Link observe ONLY first-level properties. Nested changes are NOT detected. Array: only push/splice/reassign/length, NOT item mutations.
V2 state decorators (API 12+, stable since API 23 — recommended for new code)
V2 decorators have graduated from experimental to stable as of HarmonyOS 6.1 (API 23). Official recommendation: migrate to V2 for new projects.
| V1 | V2 replacement | Change |
|---|
@Component | @ComponentV2 | Clearer semantics |
@State | @Local | Cannot be initialized externally — internal state only |
@Prop | @Param + @Once | Read-only inputs; @Once for one-time init |
@Link | @Param + @Event | Two-way: input via @Param, output via callback @Event |
@Observed + @ObjectLink | @ObservedV2 + @Trace | Deep observation across multiple nested levels |
@Watch | @Monitor('prop') | More precise deep listener |
AppStorage | AppStorageV2 | Unified with @ObservedV2 + @Trace |
| (none) | PersistenceV2 | Persistent storage with V2 observation; auto-saved to disk |
@Provide / @Consume | @Provider() / @Consumer() | Renamed; same semantics |
@ObservedV2
class UserInfo {
@Trace name: string = '';
@Trace age: number = 0;
address: string = '';
}
Rules: @ObservedV2 and @Trace must be used together (either alone has no effect). Only @Trace-decorated properties participate in UI rendering.
AppStorageV2 — global reactive state:
import { AppStorageV2 } from '@kit.ArkUI';
@ObservedV2
class UserState { @Trace name: string = 'Guest'; }
const user = AppStorageV2.connect(UserState, 'user', () => new UserState())!;
@ComponentV2
struct Header {
user: UserState = AppStorageV2.connect(UserState, 'user')!;
build() { Text(this.user.name) }
}
PersistenceV2 — auto-persisted state (survives app restart):
import { PersistenceV2, Type } from '@kit.ArkUI';
@ObservedV2
class Settings {
@Trace @Type(String) theme: string = 'light';
@Trace @Type(Number) fontSize: number = 14;
}
const settings = PersistenceV2.connect(Settings, 'app_settings', () => new Settings())!;
PersistenceV2.notifyOnError((key, reason, msg) => { console.error(reason, msg); });
@Type decorator is required for PersistenceV2 to serialize correctly.
StateStore — global state management (2026, officially recommended for mid-large apps)
Separates state logic from UI components entirely. Works with @ObservedV2 + @Trace.
import { StateStore } from '@kit.ArkUI';
@ObservedV2
class CounterStore {
@Trace count: number = 0;
increment(): void {
this.count++;
}
}
const counterStore = StateStore.createStore(new CounterStore());
@Entry
@Component
struct CounterPage {
build() {
Column() {
Text(`Count: ${counterStore.getState().count}`)
Button('Add').onClick(() => {
counterStore.getState().increment();
})
}
}
}
When to use: Multiple pages/components share the same state; state logic is complex; need thread-safe updates (TaskPool workers can safely update StateStore).
Docs: https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-global-state-management-state-store
Builders, styles, extends
@Builder function Label(text: string) { Text(text).fontSize(16) }
@Styles function Card() { .padding(12).borderRadius(12).backgroundColor('#FFF') }
@Extend(Text) function title() { .fontSize(22).fontWeight(FontWeight.Bold) }
Text('Hello').title()
Column() { Label('x') } .Card()
Navigation (recommended: Navigation component, not Router)
@Entry @Component struct App {
@Provide('pathStack') pathStack: NavPathStack = new NavPathStack();
build() {
Navigation(this.pathStack) {
Button('Go').onClick(() => this.pathStack.pushPath({ name: 'Detail', param: 42 }))
}
.navDestination((name: string, param: Object) => {
if (name === 'Detail') Detail({ id: param as number })
})
}
}
The older router module (@ohos.router) still works but is being phased out — Navigation + NavPathStack is the official replacement since API 12+. Huawei publishes a transition guide for migrating from router to Navigation. For new projects, always use Navigation; for legacy code, migrate when convenient.
NavPathStack full API:
pathStack.pushPath({ name: 'Page', param: data });
pathStack.pushPathByName('Page', data);
pathStack.pushPathByName('Page', data, (popInfo) => {
console.info('Pop result: ' + JSON.stringify(popInfo.result));
});
pathStack.pop();
pathStack.replacePath({ name: 'Page', param: data });
pathStack.removeIndex(0);
pathStack.movePageToTop('Page');
pathStack.getParamByIndex(index);
pathStack.getParamByName('Page');
pathStack.getAllPathName();
pathStack.size();
Route interception:
pathStack.setInterception({
willShow: (from, to, operation) => { },
didShow: (from, to, operation) => { }
});
Display modes: Stack (single column), Split (two columns), Auto (adaptive, 600vp threshold).
HarmonyOS Kits (common imports)
import { UIAbility, Want, common, abilityAccessCtrl } from '@kit.AbilityKit';
import { window, display, promptAction } from '@kit.ArkUI';
import { http, webSocket, connection } from '@kit.NetworkKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { fileIo as fs } from '@kit.CoreFileKit';
import { geoLocationManager } from '@kit.LocationKit';
import { relationalStore, preferences, distributedKVStore } from '@kit.ArkData';
import { notificationManager } from '@kit.NotificationKit';
import { speechRecognizer } from '@kit.CoreSpeechKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
Full Kit catalog — official SDK categories (developer.huawei.com/consumer/cn/sdk/)
应用框架 Application Framework
| Kit | Import key | Purpose |
|---|
| Ability Kit | AbilityKit | UIAbility, ExtensionAbility, Want, context, routing |
| Accessibility Kit | AccessibilityKit | Screen reader, universal design, a11y services |
| ArkData | ArkData | relationalStore, preferences, distributedKVStore |
| ArkTS | — | Language spec & Ark compiler tooling |
| ArkUI | ArkUI | window, display, promptAction, Navigation, components |
| ArkWeb | ArkWeb | WebView / Web component embedding |
| Background Tasks Kit | BackgroundTasksKit | Deferred/scheduled background work, transient tasks |
| Core File Kit | CoreFileKit | fileIo, picker, sandbox paths |
| Form Kit | FormKit | FormExtensionAbility, home-screen service cards/widgets |
| IME Kit | IMEKit | Input method engine development |
| IPC Kit | IPCKit | Inter-process communication (Parcel, RemoteObject) |
| Localization Kit | LocalizationKit | i18n, l10n, RTL, pseudo-localization |
应用服务 Application Services
| Kit | Import key | Purpose |
|---|
| Account Kit | AccountKit | One-click Huawei ID login, OAuth 2.0 |
| Ads Kit | AdsKit | Advertising SDK (banner, native, interstitial) |
| App Linking Kit | AppLinkingKit | Deep links, deferred deep links |
| Calendar Kit | CalendarKit | Calendar events, reminders |
| Contacts Kit | ContactsKit | Contact read/write/search |
| Content Embed Kit | ContentEmbedKit | Cross-app document embedding and collaborative editing |
| IAP Kit | IAPKit | In-app purchases (consumable, non-consumable, subscription) |
| Live View Kit | LiveViewKit | Live activities on lock screen / notification center |
| Location Kit | LocationKit | geoLocationManager, geofencing, geocoding |
| Map Kit | MapKit | Huawei Maps SDK, routing, place search |
| Notification Kit | NotificationKit | Local + push notifications, badges |
| Payment Kit | PaymentKit | Huawei Pay transaction processing |
| Push Kit | PushKit | Push notification delivery service |
| Scan Kit | ScanKit | QR/barcode scanning |
| Share Kit | ShareKit | Cross-app content sharing |
| Call Service Kit | CallServiceKit | Enterprise call identification and service lookup |
| Weather Service Kit | WeatherServiceKit | Weather data (current/daily/hourly/alerts/indices/tides) |
| Pen Kit | Penkit | Stylus / handwriting component (M-Pencil devices) |
| Wear Engine | WearEngine | Phone↔watch communication, device discovery |
| Health Service Kit | HealthServiceKit | Health data services |
系统 System
| Kit | Import key | Purpose |
|---|
| Asset Store Kit | AssetStoreKit | Secure credential/secret storage |
| Basic Services Kit | BasicServicesKit | Battery, vibration, thermal, brightness, clipboard |
| Connectivity Kit | ConnectivityKit | Bluetooth, Wi-Fi, NFC, USB, hotspot |
| Crypto Architecture Kit | CryptoArchitectureKit | Encryption, key management, certificates |
| Device Security Kit | DeviceSecurityKit | Code-signature queries, digital shield, security events |
| Distributed Service Kit | DistributedServiceKit | deviceManager, cross-device discovery |
| Enterprise Threat Protection Kit | EnterpriseThreatProtectionKit | Enterprise file threat scan, isolation, restore, delete |
| MDM Kit | MDMKit | Enterprise device, app, and settings management |
| Network Boost Kit | NetworkBoostKit | Network transfer optimization and low-power transfer mode |
| NearLink Kit | NearLinkKit | NearLink device capability and partner device management |
| Screen Time Guard Kit | ScreenTimeGuardKit | Screen-time authorization and app-control policy |
媒体 Media
| Kit | Import key | Purpose |
|---|
| Audio Kit | AudioKit | Audio playback, recording, routing, focus |
| AVCodec Kit | AVCodecKit | Hardware-accelerated encode/decode (H.264, H.265, AAC…) |
| Camera Kit | CameraKit | Camera preview, photo capture, video recording |
| Image Kit | ImageKit | Image decoding, transformation, EXIF |
| Media Kit | MediaKit | AVPlayer, AVRecorder (unified playback/recording) |
| Media Library Kit | MediaLibraryKit | photoAccessHelper, media library CRUD |
| Scan Kit | ScanKit | QR/barcode scanning |
图形 Graphics
| Kit | Import key | Purpose |
|---|
| ArkGraphics 2D | ArkGraphics2D | 2D Canvas drawing, effects, blur, shadow |
| ArkGraphics 3D | ArkGraphics3D | 3D scene graph, glTF rendering |
| UI Design Kit | UIDesignKit | hdsDrawable icon processing, HdsNavigation component |
| XComponent | (ArkUI built-in) | Native OpenGL ES / Vulkan surface via NAPI |
AI
| Kit | Import key | Purpose |
|---|
| Core Speech Kit | CoreSpeechKit | On-device ASR / TTS engine |
| Core Vision Kit | CoreVisionKit | OCR, face detection, image segmentation, super-resolution |
| CANN Kit | CANNKit | AI compute acceleration; API 24 adds PC LLM inference support |
| FAST Kit | FASTKit | Concurrent hash tables, vector operations, filters |
| Intents Kit | IntentsKit | Intent recognition (30+ domains, 60+ built-in intents) |
| MindSpore Lite | MindSporeLiteKit | Edge model inference (Caffe/TF/ONNX/MindIR) |
| Natural Language Kit | NaturalLanguageKit | Word segmentation, NER, keyword extraction |
Performance & DevTools
| Kit | Import key | Purpose |
|---|
| Performance Analysis Kit | PerformanceAnalysisKit | hilog, HiAppEvent, crash analysis |
Photo/video picker (correct API — picker.PhotoViewPicker is deprecated)
import { photoAccessHelper } from '@kit.MediaLibraryKit';
const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
const picker = new photoAccessHelper.PhotoViewPicker();
const result = await picker.select({
MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
maxSelectNumber: 9
});
const uris: string[] = result.photoUris;
File/document picker
import { picker } from '@kit.CoreFileKit';
const documentPicker = new picker.DocumentViewPicker(context);
const result = await documentPicker.select({
maxSelectNumber: 5,
fileSuffixFilters: ['.pdf', '.docx', '.xlsx'],
});
const uris: string[] = result;
const savePicker = new picker.DocumentViewPicker(context);
const saveResult = await savePicker.save({
newFileNames: ['export.pdf'],
});
const destUri: string = saveResult[0];
CoreSpeechKit — ASR audio format requirements
import { speechRecognizer } from '@kit.CoreSpeechKit';
const engine = await speechRecognizer.createEngine({
language: 'zh-CN',
online: 0
});
engine.startListening({
sessionId: `asr_${Date.now()}`,
audioInfo: {
audioType: 'pcm',
sampleRate: 16000,
soundChannel: 1,
sampleBit: 16
}
});
HTTP request example
import { http } from '@kit.NetworkKit';
async function fetchJson(url: string): Promise<string> {
const req = http.createHttp();
try {
const res = await req.request(url, {
method: http.RequestMethod.GET,
header: { 'Content-Type': 'application/json' },
connectTimeout: 5000, readTimeout: 10000
});
return res.result as string;
} finally {
req.destroy();
}
}
Network connectivity monitoring
import { connection } from '@kit.NetworkKit';
const hasNet = connection.hasDefaultNetSync();
const netCon = connection.createNetConnection();
netCon.on('netAvailable', () => { });
netCon.on('netLost', () => { });
netCon.on('netCapabilitiesChange', (info: connection.NetCapabilityInfo) => {
const isWifi = info.netCap.bearerTypes.includes(connection.NetBearType.BEARER_WIFI);
const isCellular = info.netCap.bearerTypes.includes(connection.NetBearType.BEARER_CELLULAR);
});
netCon.register(() => {});
netCon.unregister(() => {});
WebSocket
import { webSocket } from '@kit.NetworkKit';
const ws = webSocket.createWebSocket();
ws.on('open', () => { ws.send('hello'); });
ws.on('message', (err, data: string | ArrayBuffer) => {
console.info('received:', typeof data === 'string' ? data : 'binary');
});
ws.on('close', (err, { code, reason }) => { });
ws.on('error', (err) => { });
ws.connect('wss://example.com/ws', { header: { 'Authorization': 'Bearer xxx' } });
ws.send(JSON.stringify({ type: 'chat', text: 'hi' }));
ws.close();
Launch app by type (startAbilityByType)
import { common } from '@kit.AbilityKit';
const context = getContext(this) as common.UIAbilityContext;
context.startAbilityByType('navigation', {
sceneType: 1,
destinationLatitude: 39.9042,
destinationLongitude: 116.4074,
destinationName: 'Beijing',
} as Record<string, Object>);
context.startAbilityByType('browser', {
uri: 'https://example.com',
} as Record<string, Object>);
Supported types: navigation, browser, email, finance, transit, etc.
Permissions
Declare in module.json5 → requestPermissions. For user-granted permissions, request at runtime via abilityAccessCtrl.createAtManager().requestPermissionsFromUser(context, [...]).
Atomic Services / Meta-Services (原子化服务 / 元服务)
Installation-free, small (≤10MB) apps launched from:
- Service cards (home-screen widgets built with
FormExtensionAbility)
- Search, scan, NFC, cross-device continuation
Configured via module.json5 with "installationFree": true. Build-time they produce .app packages containing multiple HAPs.
Distributed features
- Cross-device continuation (流转) —
continueAbility / onContinue/onNewWant lifecycle
- Distributed data object — synced state across devices
- Distributed file system — shared sandbox
- Device manager — discover trusted devices
Packaging types
| Type | Purpose |
|---|
| HAP (Harmony Ability Package) | Runnable module: entry or feature type |
| HSP (Harmony Shared Package) | In-app shared module, dynamic-linked at runtime |
| HAR (Harmony Archive) | Static library, packaged into HAP at build time |
Distribute via AppGallery Connect (华为应用市场).
Official samples: https://developer.huawei.com/consumer/cn/samples/
sys.symbol — icon glyph system
HarmonyOS Symbol is a 1500+ vector icon font with multi-layer color and 7 animation types.
SymbolGlyph($r('sys.symbol.bell_fill'))
.fontSize(24)
.fontColor([Color.Blue, Color.Green])
.symbolEffect(new BounceSymbolEffect(EffectScope.WHOLE), true)
Confirmed working names (SDK 6.0.1): xmark · plus · minus · checkmark · chevron_right · chevron_left · star · star_fill · bell · bell_fill · doc · video · mic · mic_fill · clock · trash · pencil · camera · person
Names that do NOT exist (common mistakes): photo · doc_richtext · sparkles · checklist · image (use doc or camera instead) · location_fill (use text label instead)
Find valid names: https://developer.huawei.com/consumer/cn/design/harmonyos-symbol
DevEco Studio 6.x — Project Setup
DevEco Studio 6.x requires additional Hvigor infrastructure files. Without them the IDE shows "工程结构及配置需要升级".
Current API 24 Release toolchain (HarmonyOS 6.1.1, 2026/05/26):
- DevEco Studio: 6.1.1 Release (6.1.1.280)
- HarmonyOS SDK: 6.1.1 Release (OpenHarmony SDK
Ohos_sdk_public 6.1.1.125, API 24 Release)
- Hvigor / hvigorw: 6.24.2
- ohpm: 6.1.2.268
- Node.js: 18.20.1
compileSdkVersion: 6.1.1(24)
targetSdkVersion: 4.0.0(10) ~ 6.1.1(24)
Recommended workflow: Always let DevEco Studio generate the scaffold (新建项目 → Empty Ability), then copy your source files in. This avoids stale Hvigor wrapper/plugin versions.
hvigorfile.ts (root + each module)
import { appTasks } from '@ohos/hvigor-ohos-plugin';
export default { system: appTasks, plugins:[] }
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
export default { system: hapTasks, plugins:[] }
hvigor/wrapper/hvigor-config.json5
{
// Use the exact version generated by DevEco Studio for your SDK.
// API 24 Release uses Hvigor 6.24.2.
"hvigorVersion": "6.24.2",
"dependencies": {
// Keep this aligned with the DevEco-generated scaffold.
"@ohos/hvigor-ohos-plugin": "<generated-by-deveco>"
}
}
build-profile.json5 — SDK version placement
SDK versions go in one place only — either under app OR inside each product, not both. Mixing them causes "Sync Failed".
API 24 DevEco Studio adds strictCheckerOnly under project-level build-profile.json5 strictMode for running only strict syntax checks on .ets files, reducing end-to-end compile time during checks:
{
"app": {
"compileSdkVersion": "6.1.1(24)",
"compatibleSdkVersion": "4.0.0(10)",
"targetSdkVersion": "6.1.1(24)",
"strictMode": {
"strictCheckerOnly": true
}
}
}
API 24 also adds project-level oh-package.json5 properties for multi-environment dependency management. Use it for environment-specific dependency values instead of duplicating package files.
ArkTS strict-mode compiler errors (SDK 6.0.1)
No object literals as types
parseOutput(): { text: string; tags: string[] } { ... }
interface ParsedOutput { text: string; tags: string[]; }
parseOutput(): ParsedOutput { ... }
No any / unknown
const task = JSON.parse(rawStr) as AgentTask;
navDestination requires a @Builder function reference
.navDestination((name, param) => { if (name==='X') MyPage() })
@Builder function PageRouter(name: string) { if (name==='X') MyPage() }
Navigation(stack) { ... }.navDestination(PageRouter)
@Entry build() root must be a container
Wrap in Stack(), Column(), or Row() — a custom component alone is not a container.
display.width is pixels, not vp
function isTablet(): boolean {
const dm = display.getDefaultDisplaySync();
return (dm.width / dm.densityPixels) >= 840;
}
All user_grant permissions need reason + usedScene
{
"name": "ohos.permission.READ_MEDIA",
"reason": "$string:permission_media_reason",
"usedScene": { "abilities": ["EntryAbility"], "when": "inuse" }
}
INTERNET is system_grant — no extra fields needed.
Common gotchas
-
Don't mix FA and Stage models — FA is legacy; HarmonyOS NEXT only supports Stage.
-
this in ArkUI callbacks — arrow functions are required; regular function () {} loses this.
-
@State on nested objects — changes to nested props don't trigger updates; use @Observed/@ObjectLink or reassign the whole object.
-
Array item updates — replace the item (arr[i] = newItem) or use @Observed on the item class.
-
Resource references — use $r('app.string.foo'), $r('app.media.icon'), not string paths.
-
getContext(this) inside a component returns the UIAbilityContext; cast explicitly.
-
Async in build() is forbidden — load data in aboutToAppear() and store in @State.
-
Permissions must be declared AND requested at runtime for user-grant permissions.
-
ohpm is the package manager (similar to npm) — dependencies live in oh-package.json5.
-
Preview on device — DevEco Previewer doesn't fully simulate; always test on real HarmonyOS device or emulator.
-
Navigation has no hideSideBar — use .hideBackButton(true) instead.
-
promptAction.showToast() is deprecated — use getUIContext().getPromptAction().showToast(...) instead; wrap in try-catch for safety.
-
Floating FAB button blocks last list item — use Navigation.menus() for primary action buttons, or add bottom padding to List equal to FAB height + margin.
-
Named callbacks for on/off — anonymous functions can't be unregistered. Always store references:
session.on('stateChange', (state) => { ... });
const cb = (state: StateType) => { ... };
session.on('stateChange', cb);
session.off('stateChange', cb);
-
Batch state mutations — multiple @State changes trigger multiple re-renders. Accumulate in a temp variable, assign once:
this.list.push(a); this.list.push(b); this.list.push(c);
const tmp = [...this.list, a, b, c];
this.list = tmp;
-
State decorator selection priority — @State+@Prop/@Link/@ObjectLink (parent-child) > @Provide+@Consume (deep nesting) > LocalStorage (page-level) > AppStorage (global). Avoid AppStorage for frequently-changing data.
-
Unit conversion — px2vp(px) / vp2px(vp) via this.getUIContext().px2vp(value). Screen density: display.getDefaultDisplaySync().densityPixels.
-
Keep screen on — win.setWindowKeepScreenOn(true) during video playback / navigation; reset on pause.
Stability — crash types and error handling
| Type | Description |
|---|
| JS_ERROR | ArkTS/JS runtime exceptions (most common) — TypeError: Cannot read property 'x' of undefined |
| CPP_CRASH | Native C/C++ crash (SIGSEGV, SIGABRT) |
| APP_FREEZE | Main thread blocked >6s (ANR equivalent). Root causes: thread locks (57%), system resources (14%), heavy main-thread work (9%) |
| OOM | Out-of-memory kill |
Global error handler:
import { errorManager } from '@kit.AbilityKit';
const observer: errorManager.ErrorObserver = {
onUnhandledException(errMsg: string): void {
console.error('Uncaught: ' + errMsg);
},
onException?(errObject: Error): void {
console.error(errObject.name + ': ' + errObject.message);
}
};
const observerId = errorManager.on('error', observer);
Crash event subscription (HiAppEvent):
import { hiAppEvent } from '@kit.PerformanceAnalysisKit';
hiAppEvent.addWatcher({
name: "crashWatcher",
appEventFilters: [{
domain: hiAppEvent.domain.OS,
names: [hiAppEvent.event.APP_CRASH]
}],
onReceive: (domain, appEventGroups) => { }
});
Background Tasks — 4 types
| Type | API | Duration | Use case |
|---|
| Transient | requestSuspendDelay | ~3 min max | Save data, upload logs |
| Continuous | startBackgroundRunning | Unlimited (needs notification) | Music, navigation, recording |
| Deferred | workScheduler.startWork | System-determined | Timed sync, cleanup |
| Agent Reminders | ReminderRequestTimer | System-managed | Alarms, timers |
Continuous task example:
import { backgroundTaskManager } from '@kit.BackgroundTasksKit';
import { wantAgent, WantAgent } from '@kit.AbilityKit';
const info: wantAgent.WantAgentInfo = {
wants: [{ bundleName: 'com.example.app', abilityName: 'MainAbility' }],
actionType: wantAgent.OperationType.START_ABILITY,
requestCode: 0, actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
};
const agent = await wantAgent.getWantAgent(info);
backgroundTaskManager.startBackgroundRunning(
this.context, backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, agent
);
9 background modes: dataTransfer · audioPlayback · audioRecording · location · bluetoothInteraction · multiDeviceConnection · taskKeeping (2-in-1 only)
Deferred task frequency by user activity: Active=2h, Frequent=4h, Regular=24h, Rare=48h, Never used=prohibited.
Security coding rules (from official best practices)
- Set
exported: false for non-interactive abilities
- Validate all parameters crossing trust boundaries (Want intents, rpc.RemoteObject)
- Use parameterized queries — never string concat for SQL
- Replace HTTP with HTTPS; validate SSL certificates
- Never store personal data in clipboard
- Use
Asset Store Kit for sensitive short data (passwords, tokens)
- Avoid passing personal data through implicit intents
- Use code obfuscation for production builds
- Use precise
InputType (.USER_NAME, .Password) for system-level protection
- Never use debug signatures for production releases
Permission check + request pattern:
import { abilityAccessCtrl, bundleManager } from '@kit.AbilityKit';
const atManager = abilityAccessCtrl.createAtManager();
const bundleInfo = await bundleManager.getBundleInfoForSelf(
bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
const status = await atManager.checkAccessToken(
bundleInfo.appInfo.accessTokenId, 'ohos.permission.CAMERA');
const result = await atManager.requestPermissionsFromUser(context,
['ohos.permission.CAMERA', 'ohos.permission.MICROPHONE']);
if (result.authResults[0] === 0) {
} else if (result.dialogShownResults?.[0]) {
} else {
atManager.requestPermissionOnSetting(context,
['ohos.permission.CAMERA']).then((statuses) => {
});
}
Data encryption levels: EL1 (device-level) → EL2 (user-level, default) → EL3 (accessible while locked) → EL4 (inaccessible when locked)
Network security config — HTTPS/certificate pinning for production apps:
Create src/main/resources/base/profile/network_config.json:
{
"network-security-config": {
"domain-config": [{
"domains": [{ "include-subdomains": true, "name": "api.example.com" }],
"trust-anchors": [{ "certificates": "/data/storage/el1/bundle/entry/resources/resfile/ca_cert.pem" }]
}]
}
}
Reference in module.json5: "metadata": [{ "name": "NetworkSecurityConfig", "resource": "$profile:network_config" }].
Testing — arkxtest framework
Package: @ohos/hypium (Mocha-style). Three sub-frameworks: JsUnit (unit), UiTest (UI automation), PerfTest (performance).
JsUnit
import { describe, it, expect, beforeAll, beforeEach, afterEach, afterAll } from '@ohos/hypium';
export default function abilityTest() {
describe('MyTestSuite', () => {
beforeAll(() => { });
beforeEach(() => { });
afterEach(() => { });
afterAll(() => { });
it('sync_test', 0, () => {
expect(1 + 1).assertEqual(2);
});
it('async_test', 0, async (done: Function) => {
let result = await someAsyncOp();
expect(result).assertContain('expected');
done();
});
});
}
Key assertions: assertEqual(v) · assertContain(v) · assertTrue() · assertFalse() · assertNull() · assertUndefined() · assertNaN() · assertInstanceOf(type) · assertThrowError(fn) · assertDeepEquals(v) · assertClose(v, tolerance) · assertLarger(v) · assertLess(v) · not() (negation) · assertPromiseIsResolved() · assertPromiseIsRejected()
Test files in entry/src/ohosTest/ets/test/. For UI automation, see the UiTest section below.
仓颉 (Cangjie) is Huawei's new language (beta) — use ArkTS for all production apps until Cangjie is stable.
ArkCompiler — runtime details
- AOT mode — static type info generates optimized native machine code; no JIT warm-up
- LiteActor concurrency — Actor model with isolated memory per thread; communication via message passing
TaskPool vs Worker
| Feature | TaskPool | Worker |
|---|
| Thread management | Automatic (create/reuse/destroy) | Manual lifecycle |
| Max threads | Auto-scaled to physical cores | Max 64 per process |
| Task duration limit | 3 minutes (excluding async I/O) | Unlimited |
| Priority | HIGH / MEDIUM / LOW / IDLE | API 18+ only |
| Cancellation | Supported | Not supported |
| Thread reuse | Yes | No |
| Task groups | Yes | No |
| Delayed/periodic | Yes | No |
Use Worker when: tasks exceed 3 minutes, need persistent state, or strongly associated synchronous tasks.
@Concurrent rules
- Required on all TaskPool functions, only in
.ets files
- Allowed: regular functions, async functions
- Prohibited: arrow functions, class methods, anonymous functions, generator functions
- No closure variables — cannot reference outer scope; only local vars, params, and imports
- Cannot call other same-file functions (closure violation) — must import them
import { taskpool } from '@kit.ArkTS';
@Concurrent
function heavyCalc(n: number): number { return n * n; }
const result = await taskpool.execute(heavyCalc, 42);
const task = new taskpool.Task(heavyCalc, 42);
await taskpool.execute(task, taskpool.Priority.HIGH);
taskpool.executeDelayed(heavyCalc, 2000, 42);
taskpool.executePeriodically(heavyCalc, 5000, 42);
const group = new taskpool.TaskGroup();
group.addTask(heavyCalc, 10);
group.addTask(heavyCalc, 20);
group.addTask(heavyCalc, 30);
const results = await taskpool.execute(group);
Long-time tasks: async code (Promise/IO) in TaskPool has NO time limit (only CPU-bound sync code is capped at 3 minutes). HarmonyOS 6.0 officially supports long-running async tasks in TaskPool.
@Sendable — shared-heap reference passing
Objects on SharedHeap (process-level, all threads can access) — 100x faster than serialization for 1MB data.
@Sendable
class SharedData {
value: number = 0;
}
Constraints: Can only inherit from Sendable classes. Property types limited to: primitives, Sendable classes, @arkts.collections containers. Cannot add/delete properties at runtime. No computed properties. No # private (use private keyword).
Worker pattern
const worker = new worker.ThreadWorker('entry/ets/workers/myWorker.ets');
worker.postMessage({ type: 'compute', data: payload });
worker.onmessage = (e) => { };
worker.terminate();
const workerPort = worker.workerPort;
workerPort.onmessage = (e) => {
const result = processData(e.data);
workerPort.postMessage(result);
};
Both TaskPool and Worker: Cannot access AppStorage or UI libraries from worker threads. Different thread contexts prevent context object sharing.
OHPM — package manager
ohpm install @ohos/axios
ohpm install
oh-package.json5 example:
{
"name": "entry",
"dependencies": {
"@ohos/axios": "^2.0.0"
}
}
OHPM Central Repository: https://developer.huawei.com/consumer/cn/deveco-service
Popular ohpm libraries
@ohos/axios — HTTP client (ohpm install @ohos/axios, requires ohos.permission.INTERNET):
import axios, { AxiosResponse, AxiosError, InternalAxiosRequestConfig } from '@ohos/axios';
interface UserInfo { id: number; name: string }
axios.get<UserInfo, AxiosResponse<UserInfo>, null>('/user', { params: { ID: 12345 } })
.then((res: AxiosResponse<UserInfo>) => console.info(res.data.name))
.catch((err: AxiosError) => console.error(err.message));
interface NewUser { firstName: string; lastName: string }
axios.post<string, AxiosResponse<string>, NewUser>('/user',
{ firstName: 'Fred', lastName: 'Flintstone' });
const http = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000,
headers: { 'X-Custom-Header': 'value' },
});
http.interceptors.request.use((config: InternalAxiosRequestConfig) => {
config.headers['Authorization'] = 'Bearer ' + AppStorage.get<string>('token');
return config;
}, (err: AxiosError) => Promise.reject(err));
http.interceptors.response.use(
(res: AxiosResponse) => res,
(err: AxiosError) => {
if (err.response?.status === 401) { }
return Promise.reject(err);
}
);
import fs from '@ohos.file.fs';
const filePath = getContext(this).cacheDir + '/file.jpg';
axios({ url: 'https://example.com/file.jpg', method: 'get', filePath,
onDownloadProgress: (e) => {
console.info('Progress: ' + (e.loaded && e.total ? Math.ceil(e.loaded / e.total * 100) : 0) + '%');
}
});
import { FormData } from '@ohos/axios';
const form = new FormData();
form.append('file', 'internal://cache/photo.jpg');
axios.post<string, AxiosResponse<string>, FormData>('/upload', form, {
headers: { 'Content-Type': 'multipart/form-data' },
onUploadProgress: (e) => console.info(e.loaded + '/' + e.total),
});
const ctrl = new AbortController();
axios.get('/slow', { signal: ctrl.signal });
ctrl.abort();
responseType: 'string' | 'object' | 'array_buffer'. Mutual TLS requires API 11+.
@ohos/pulltorefresh — pull-down refresh + load-more (ohpm install @ohos/pulltorefresh, supports List/Scroll/Tabs/Grid/WaterFlow, API 12+):
import { PullToRefresh, PullToRefreshType } from '@ohos/pulltorefresh';
@Component
struct NewsPage {
@State data: string[] = ['Item 1', 'Item 2', 'Item 3'];
@State refreshing: boolean = false;
build() {
PullToRefresh({
pullToRefreshType: PullToRefreshType.LIST,
refreshing: $refreshing,
customList: () => { this.ListBuilder(); },
onRefresh: () => new Promise<string>((resolve) => {
setTimeout(() => {
this.data = ['Refreshed 1', 'Refreshed 2'];
resolve('Done');
}, 1000);
}),
onLoadMore: () => new Promise<string>((resolve) => {
setTimeout(() => {
for (let i = 0; i < 10; i++) this.data.push('New ' + this.data.length);
resolve('');
}, 1000);
}),
customLoad: null,
customRefresh: null,
})
}
@Builder ListBuilder() {
List() {
ForEach(this.data, (item: string) => {
ListItem() { Text(item).padding(16) }
})
}
}
}
@ohos/lottie — JSON animation (ohpm install @ohos/lottie, also consider @ohos/lottie-turbo for 30%+ perf):
import lottie, { AnimationItem } from '@ohos/lottie';
@Component
struct LottieDemo {
private canvasCtx = new CanvasRenderingContext2D(new RenderingContextSettings(true));
private animItem: AnimationItem | null = null;
private animName: string = 'myAnim';
aboutToDisappear(): void { lottie.destroy(); }
build() {
Canvas(this.canvasCtx).width(200).height(200)
.onReady(() => {
this.canvasCtx.imageSmoothingEnabled = true;
lottie.destroy(this.animName);
this.animItem = lottie.loadAnimation({
container: this.canvasCtx, renderer: 'canvas',
loop: true, autoplay: false, name: this.animName,
contentMode: 'Contain',
path: 'common/animation.json',
frameRate: 30,
});
this.animItem.addEventListener('DOMLoaded', () => {
this.animItem?.play();
});
})
}
}
Obfuscation: add -keep ./oh_modules/@ohos/lottie to obfuscation-rules.txt