跪拜 Guibai
← All articles
HarmonyOS

HarmonyOS Componentization Without Reflection: Contracts, Registries, and Unidirectional Dependencies

By xq9527 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

ArkTS lacks reflection, so standard Android-style service discovery patterns do not apply. This project provides a concrete, battle-tested blueprint for decoupling HarmonyOS apps that compiles cleanly and surfaces missing registrations at runtime rather than through cryptic crashes.

Summary

A complete HarmonyOS sample app splits login, payment, and forced-update features into isolated HAR and HSP packages that communicate only through a shared API layer. The architecture enforces three rules: package-type isolation, interface contracts, and unidirectional dependencies where business modules never import each other. Four communication mechanisms replace reflection, which ArkTS does not support: a ServiceRegistry for request-response calls, a RouteCenter for page navigation, AppStorage wrapped in an HSP for global reactive state, and an emitter event bus for fire-and-forget notifications. Each business module initializes by explicitly registering its service implementations and page builders, making the dependency graph traceable at compile time. A mock HTTP layer sits behind the service interfaces so that swapping in real network calls requires zero changes to business code. The project also documents ten specific build and configuration pitfalls encountered during development, from missing module.json5 files to illegal hex literals and incorrect system resource names.

Takeaways
Business modules never import each other; all cross-module calls go through interfaces defined in a shared common_api HAR.
Global state like login sessions must live in an HSP, not a HAR, to prevent class-identity splitting across package copies.
ServiceRegistry replaces dependency injection: modules register implementations at startup, and consumers fetch them by interface key.
RouteCenter decouples the shell HAP from business HARs by letting each module register its own NavDestination builders.
The emitter event bus is reserved for notification-only events; request-response calls must use ServiceRegistry to keep error handling predictable.
A mock HTTP layer behind service interfaces lets business code stay unchanged when real network calls are swapped in.
Ten specific build errors are catalogued, including missing module.json5 files, illegal hex literals, and incorrect system color resource names.
Conclusions

Explicit registration at startup is a pragmatic substitute for dependency injection in a reflection-less runtime, and it makes missing dependencies immediately visible as undefined services or unregistered pages.

The HSP-vs-HAR distinction for stateful singletons is a subtle but critical design constraint: getting it wrong silently corrupts app state rather than producing a clear error.

Reserving the event bus strictly for fire-and-forget notifications and routing all request-response traffic through a typed registry prevents the debugging nightmare of implicit, untraceable call chains.

The forced-update dialog bypasses the RouteCenter entirely because it is a component, not a page, which clarifies the boundary between component-level reuse and page-level navigation.

Concepts & terms
HAR (HarmonyOS Archive)
A static shared package in HarmonyOS. Each HAP that depends on a HAR gets its own copy of the code at build time. Suitable for stateless utilities and interface contracts.
HSP (HarmonyOS Shared Package)
A dynamic shared package in HarmonyOS. Only one copy exists per app on a device at runtime. Required for modules that must maintain a single global state, such as a session manager, to prevent class-identity splitting.
ServiceRegistry
A hand-rolled registry pattern used in place of dependency injection. Modules register interface implementations by key at startup; consumers retrieve them by key without importing implementation classes.
RouteCenter
A centralized route table that decouples the shell HAP from business HARs. Each module registers its own page builders, and the shell resolves navigation targets by name without importing business pages directly.
From the discussion
Featured comments
沉默王贰

I've also studied HarmonyOS componentization before, following the official recommendations, which is relatively simple.

xq9527

This lacks the ability to freely switch between application and library like on Android, so it still falls a bit short.

See top comments, translated →
Source: juejin.cn ↗ Google Translate ↗ Backup ↗