在 ArkUI-X 跨平台开发中,合理的工程目录结构是保障项目可维护性与扩展性的基石。其核心设计思想是从 OpenHarmony 应用工程原生支持跨平台的角度出发,在 OpenHarmony 应用工程之上叠加 Android 和 iOS 应用工程。
一、 跨平台工程根目录结构
一个标准的 ArkUI-X 工程在根目录下会包含跨平台的核心业务代码以及各平台的原生工程代码。
核心目录结构:
MyCrossApp/ ├── .arkui-x/ # ArkUI-X 跨平台核心配置 │ ├── android/ # Android 平台相关代码 │ ├── ios/ # iOS 平台相关代码 │ └── arkui-x-config.json5 # 标记哪些模块支持跨平台 ├── AppScope/ # 应用级全局配置 ├── entry/ # 主业务模块(ArkTS 代码) ├── commons/ # 公共基础能力模块(可选) ├── hvigor/ # 构建工具配置 ├── build-profile.json5 # 全局构建配置 └── oh-package.json5 # 依赖管理配置二、 共享代码与平台特定代码的隔离策略
为了保持上层 ArkTS 业务代码的纯粹性,强烈建议将平台强相关的代码(如原生插件、特定硬件调用)与跨平台共享代码进行物理隔离。
推荐的目录组织方式:
├── commons/ │ ├── shared/ # 纯跨平台共享代码(UI、通用业务逻辑) │ ├── media/ # 包含平台差异化的能力模块 │ │ └── src/main/ets/camera/ │ │ ├── interface/ # 统一接口定义 (CameraInterface.ets) │ │ └── impl/ # 平台差异化实现 │ │ ├── Camera.ets # 工厂类:根据平台动态分发 │ │ ├── CameraLocal.ets # HarmonyOS 原生实现 │ │ └── CameraArkUIX.ets # Android/iOS 的 Bridge 实现 │ └── platform_specific/ # 平台特定代码隔离区 │ ├── android/ # Android 专属逻辑(如推送、权限) │ ├── ios/ # iOS 专属逻辑 │ └── openharmony/ # 鸿蒙专属逻辑(如分布式协同)三、 跨平台模块声明与配置
为了让构建系统准确识别哪些模块需要参与跨平台编译,必须在.arkui-x/arkui-x-config.json5中进行明确声明。
核心配置示例:
{ "crossplatform": true, "modules": [ "entry", "shared", "media" ] }四、 编译产物与原生工程的资源映射
在构建过程中,ArkTS 源码会被编译为 abc(Ark Byte Code),并与 ArkUI 资源一起被拷贝到各平台的原生工程中作为资源进行管理。
平台资源映射说明:
- Android 平台:编译后的字节码文件、resources 资源以及 ArkUI 框架资源,统一存放在 Android 工程的
app/src/main/assets/arkui-x/目录下。 - iOS 平台:对应的编译产物和资源则统一存放在 iOS 工程的
Bundle Resources中。
通过这种“共享代码统一编写、平台代码隔离实现、配置集中声明”的工程组织方式,开发者可以最大化地复用业务代码,同时保证各平台底层能力的灵活扩展与高效维护。
1. 定义统一的跨平台接口(Interface)
在共享代码区(如commons/media/src/main/ets/camera/interface/),首先定义一个抽象接口,规定跨平台组件必须实现的标准方法,确保上层 UI 代码无需关心底层实现。
核心代码示例(CameraInterface.ets):
// 统一接口定义 export interface ICameraService { openCamera(): void; takePhoto(): Promise<string>; // 返回照片的本地路径 closeCamera(): void; }2. 实现各平台的差异化逻辑(Impl)
在隔离区中,针对不同平台编写具体的实现类。鸿蒙端直接调用原生 Kit,而 Android/iOS 端则通过 Bridge 调用原生层。
核心代码示例(HarmonyOS 原生实现 - CameraLocal.ets):
import { ICameraService } from '../interface/CameraInterface'; import camera from '@ohos.multimedia.camera'; export class CameraLocal implements ICameraService { openCamera(): void { // 鸿蒙端:直接调用系统相机 API camera.getCameraManager().getSupportedCameras(); } async takePhoto(): Promise<string> { // 鸿蒙端原生拍照逻辑... return '/data/storage/photo_harmony.jpg'; } closeCamera(): void { /* 释放鸿蒙相机资源 */ } }核心代码示例(Android/iOS 桥接实现 - CameraArkUIX.ets):
import { ICameraService } from '../interface/CameraInterface'; import bridge from '@arkui-x.bridge'; export class CameraArkUIX implements ICameraService { private nativeBridge = bridge.createBridge('CameraBridge'); openCamera(): void { // Android/iOS端:通过 Bridge 通知原生层打开相机 this.nativeBridge.callMethod('openNativeCamera'); } async takePhoto(): Promise<string> { // 异步等待原生层拍照完成并返回路径 return await this.nativeBridge.callMethod('takeNativePhoto'); } closeCamera(): void { this.nativeBridge.callMethod('closeNativeCamera'); } }3. 利用工厂模式动态分发(Factory)
在工厂类中,结合平台嗅探工具(platform.osType),在运行时动态实例化对应平台的实现类,对上层业务完全屏蔽底层差异。
核心代码示例(Camera.ets):
import { ICameraService } from './interface/CameraInterface'; import { CameraLocal } from './impl/CameraLocal'; import { CameraArkUIX } from './impl/CameraArkUIX'; import { platform } from '@arkui-x/platform'; export class CameraFactory { static create(): ICameraService { switch (platform.osType) { case platform.OsType.HARMONY_OS: return new CameraLocal(); case platform.OsType.ANDROID: case platform.OsType.IOS: return new CameraArkUIX(); default: throw new Error('Unsupported platform for Camera'); } } }4. 上层 UI 的纯粹调用
在最终的 UI 页面中,开发者只需通过工厂获取服务并调用标准方法,代码中不会出现任何if-else平台判断,保持了业务逻辑的纯粹性。
核心代码示例(PhotoPage.ets):
@Entry @Component struct PhotoPage { private cameraService: ICameraService = CameraFactory.create(); build() { Column() { Button('拍照') .onClick(async () => { this.cameraService.openCamera(); const path = await this.cameraService.takePhoto(); console.info('照片保存路径:', path); }) } } }