HarmonyOS NEXT 实战:HarmonyOS Kit 封装最佳实践

前言

HarmonyOS NEXT 提供了丰富的系统能力 Kit,包括 File Kit、Image Kit、Media Library Kit、Picker Kit、Share Kit、Notification Kit 等。如果直接在各业务页面调用这些 Kit,会导致代码散乱、难以维护、版本升级成本高。HarmonyExplorer 通过 KitManager 统一架构,将所有 Kit 调用收敛到 Manager 层。统一的 Kit 封装是大型鸿蒙工程保持可维护性的关键基础设施,本文将完整讲解 KitManager 的架构设计与六大 Kit 的封装实践。

提示:本文代码基于 HarmonyOS NEXT(API 12+)ArkTS 严格模式编写,禁用 any 类型与隐式断言,所有 Kit 封装均提供统一错误处理与权限管理。

一、KitManager 统一架构设计

1.1 设计目标

KitManager 的核心设计目标是将系统能力与业务逻辑解耦,提供统一、可测试、可扩展的 Kit 调用层。

  1. 统一入口:所有 Kit 调用经由 KitManager 分发,业务层不直接依赖具体 Kit
  2. 统一错误处理:封装 BusinessError,提供一致的错误码与消息体系
  3. 统一权限管理:调用前自动校验所需权限,缺失时引导授权
  4. 可替换性:Kit 版本升级时只需修改 Manager 层,业务层无感知

1.2 架构分层

KitManager 位于 Service 与系统 Kit 之间,是能力调用的唯一收敛点。

  • 业务层(Service):调用 KitManager 提供的方法,不感知底层 Kit
  • KitManager 层:分发调用到具体 KitManager 子类
  • 子 Manager 层:FileKitManager、ImageKitManager 等封装具体 Kit
  • 系统 Kit 层:HarmonyOS 提供的原始 Kit 能力

提示:KitManager 采用门面模式,对外暴露简洁接口,对内协调多个子 Manager,降低业务层的心智负担。

HarmonyExplorer 封装的六大 Kit Manager 及职责如下表所示:

子 Manager 封装的 Kit 核心职责
FileKitManager Core File Kit 文件读写与目录操作
ImageKitManager Image Kit 图片解码与缩略图
MediaKitManager Media Library Kit 媒体资源检索
PickerKitManager Picker Kit 文件与图片选择
ShareKitManager Share Kit 系统分享能力
NotifyKitManager Notification Kit 通知发布管理
// manager/KitManager.ets
export class KitManager {
  static fileKit: FileKitManager = new FileKitManager()
  static imageKit: ImageKitManager = new ImageKitManager()
  static mediaKit: MediaKitManager = new MediaKitManager()
  static pickerKit: PickerKitManager = new PickerKitManager()
  static shareKit: ShareKitManager = new ShareKitManager()
  static notifyKit: NotifyKitManager = new NotifyKitManager()

  static init(): void {
    KitManager.fileKit.init()
    KitManager.imageKit.init()
    KitManager.mediaKit.init()
  }
}

二、File Kit 封装

2.1 封装实现

FileKitManager 封装 Core File Kit 的文件读写、目录操作等能力,提供文件存在性检查、读写与删除等基础方法。文件操作是所有上层能力的基础,封装质量直接影响整体稳定性。

// manager/FileKitManager.ets
import { fileIo } from '@kit.CoreFileKit'
import { KitError } from '../model/KitModel'

export class FileKitManager {
  init(): void {
    // 初始化文件系统相关资源
  }

  async readFile(filePath: string): Promise<string> {
    try {
      const file: fileIo.File = fileIo.openSync(filePath, fileIo.OpenMode.READ_ONLY)
      const stat: fileIo.Stat = fileIo.statSync(file.fd)
      const buffer: ArrayBuffer = new ArrayBuffer(stat.size)
      fileIo.readSync(file.fd, buffer)
      fileIo.closeSync(file)
      return new TextDecoder('utf-8').decode(buffer)
    } catch (e) {
      throw new KitError(5001, '文件读取失败')
    }
  }

  async writeFile(filePath: string, content: string): Promise<void> {
    try {
      const file: fileIo.File = fileIo.openSync(filePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY)
      fileIo.writeSync(file.fd, content)
      fileIo.closeSync(file)
    } catch (e) {
      throw new KitError(5002, '文件写入失败')
    }
  }
}

三、Image Kit 封装

3.1 封装实现

ImageKitManager 封装 Image Kit 的图片解码、缩放、格式转换能力,为图片预览与缩略图生成提供支持。

// manager/ImageKitManager.ets
import { image } from '@kit.ImageKit'
import { KitError } from '../model/KitModel'

export class ImageKitManager {
  init(): void {
    // 初始化图片处理资源
  }

  async createThumbnail(filePath: string, maxSize: number): Promise<PixelMap> {
    try {
      const file: fileIo.File = fileIo.openSync(filePath, fileIo.OpenMode.READ_ONLY)
      const source: image.ImageSource = image.createImageSource(file.fd)
      const opts: image.ThumbnailOption = { width: maxSize, height: maxSize, scale: 0.5 }
      const pixelMap: PixelMap = await source.createThumbnail(opts)
      fileIo.closeSync(file)
      return pixelMap
    } catch (e) {
      throw new KitError(5101, '缩略图生成失败')
    }
  }

  async getImageInfo(filePath: string): Promise<image.ImageInfo> {
    try {
      const file: fileIo.File = fileIo.openSync(filePath, fileIo.OpenMode.READ_ONLY)
      const source: image.ImageSource = image.createImageSource(file.fd)
      const info: image.ImageInfo = await source.getImageInfo()
      fileIo.closeSync(file)
      return info
    } catch (e) {
      throw new KitError(5102, '图片信息获取失败')
    }
  }
}

四、Media Library Kit 封装

4.1 封装实现

MediaKitManager 封装 Media Library Kit 的媒体文件检索能力,支持按类型查询图片、视频、音频资源。

// manager/MediaKitManager.ets
import { mediaLibrary } from '@kit.MediaLibraryKit'
import { KitError } from '../model/KitModel'

export class MediaKitManager {
  init(): void {
    // 初始化媒体库资源
  }

  async queryMediaByType(type: mediaLibrary.MediaType): Promise<mediaLibrary.FileAsset[]> {
    try {
      const helper: mediaLibrary.MediaLibrary = mediaLibrary.getMediaLibrary()
      const fetchOptions: mediaLibrary.MediaFetchOptions = {
        fetchColumns: ['title', 'size', 'date_modified'],
        predicates: 'media_type = ' + type.toString()
      }
      const fetchResult: mediaLibrary.FetchResult = await helper.getFileAssets(fetchOptions)
      const assets: mediaLibrary.FileAsset[] = await fetchResult.getAllObject()
      return assets
    } catch (e) {
      throw new KitError(5201, '媒体文件查询失败')
    }
  }
}

五、Picker Kit 封装

5.1 封装实现

PickerKitManager 封装 Picker Kit 的文件选择、照片选择能力,统一管理 Picker 选项与回调处理。

// manager/PickerKitManager.ets
import { picker } from '@kit.CoreFileKit'
import { KitError } from '../model/KitModel'

export class PickerKitManager {
  init(): void {
    // 初始化 Picker 资源
  }

  async pickFiles(maxCount: number, filters: string[]): Promise<string[]> {
    try {
      const options: picker.DocumentSelectOptions = new picker.DocumentSelectOptions()
      options.maxSelectNumber = maxCount
      options.fileMimeTypeFilters = filters
      const viewPicker: picker.DocumentViewPicker = new picker.DocumentViewPicker()
      const uris: string[] = await viewPicker.select(options)
      return uris
    } catch (e) {
      throw new KitError(5301, '文件选择失败')
    }
  }

  async pickImages(maxCount: number): Promise<string[]> {
    try {
      const options: picker.PhotoSelectOptions = new picker.PhotoSelectOptions()
      options.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE
      options.maxSelectNumber = maxCount
      const photoPicker: picker.PhotoViewPicker = new picker.PhotoViewPicker()
      const result: picker.PhotoSelectResult = await photoPicker.select(options)
      return result.photoUris
    } catch (e) {
      throw new KitError(5302, '图片选择失败')
    }
  }
}

六、Share Kit 封装

6.1 封装实现

ShareKitManager 封装 Share Kit 的系统分享能力,提供单文件与多文件分享入口。分享能力的统一封装保证了跨页面的体验一致性

// manager/ShareKitManager.ets
import { systemShare } from '@kit.ShareKit'
import { utd } from '@kit.UnifiedDataModel'
import { KitError } from '../model/KitModel'

export class ShareKitManager {
  init(): void {
    // 初始化分享资源
  }

  async shareFile(filePath: string, fileType: string): Promise<void> {
    try {
      const utdType: string = utd.getUniformDataType(fileType, utd.UniformDataType.FILE)
      const content: systemShare.SharedContent = new systemShare.SharedContent({
        utd: utdType,
        content: filePath
      })
      const controller: systemShare.ShareController = new systemShare.ShareController(content)
      await controller.show(getContext(), systemShare.SharePanelBehavior.DETACHED)
    } catch (e) {
      throw new KitError(5401, '分享失败')
    }
  }
}

七、Notification Kit 封装

7.1 封装实现

NotifyKitManager 封装 Notification Kit 的通知发布能力,支持基础文本通知与通知渠道管理。

// manager/NotifyKitManager.ets
import { notificationManager } from '@kit.NotificationKit'
import { KitError } from '../model/KitModel'

export class NotifyKitManager {
  init(): void {
    // 初始化通知资源
  }

  async sendNotification(title: string, text: string): Promise<void> {
    try {
      const request: notificationManager.NotificationRequest = {
        id: Date.now(),
        content: {
          notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
          normal: { title: title, text: text }
        },
        deliveryTime: new Date().getTime()
      }
      await notificationManager.publish(request)
    } catch (e) {
      throw new KitError(5501, '通知发送失败')
    }
  }
}

八、统一错误处理

8.1 错误体系

KitManager 通过 KitError 统一封装错误,业务层捕获 KitError 即可获取错误码与消息,无需关心底层异常类型。

// model/KitModel.ets
export class KitError extends Error {
  code: number
  message: string

  constructor(code: number, message: string) {
    super(message)
    this.code = code
    this.message = message
  }
}

export interface KitResult {
  success: boolean
  data?: Object
  error?: KitError
}

各 Kit 的错误码划分如下表,按 Kit 模块分段,便于快速定位问题来源:

Kit 模块 错误码段 示例
File Kit 5000-5099 5001 文件读取失败
Image Kit 5100-5199 5101 缩略图失败
Media Library 5200-5299 5201 媒体查询失败
Picker Kit 5300-5399 5301 文件选择失败
Share Kit 5400-5499 5401 分享失败
Notification 5500-5599 5501 通知失败

九、统一权限管理

9.1 权限管理

KitManager 在调用 Kit 前统一校验权限,缺失权限时抛出明确错误,由业务层引导用户授权。统一的权限前置校验是避免运行时崩溃的关键防线

// manager/PermissionChecker.ets
import { abilityAccessCtrl, bundleManager } from '@kit.AbilityKit'
import { KitError } from '../model/KitModel'

export class PermissionChecker {
  static async check(permission: string): Promise<boolean> {
    const tokenId: number = bundleManager.getApplicationInfoSync().accessTokenId
    const accessCtrl: abilityAccessCtrl.AccessController = abilityAccessCtrl.createAtManager()
    try {
      const status: number = await accessCtrl.checkAccessToken(tokenId, permission)
      return status === 0
    } catch (e) {
      return false
    }
  }

  static async ensure(permission: string): Promise<void> {
    const granted: boolean = await PermissionChecker.check(permission)
    if (!granted) {
      throw new KitError(5601, '权限不足:' + permission)
    }
  }
}

各 Kit 所需权限对照如下表,KitManager 在调用时自动校验对应权限:

Kit 模块 所需权限 校验时机
Media Library READ_MEDIA 查询媒体前
File Kit 无(沙箱内) 无需校验
Picker Kit 无(系统授权) 无需校验
Notification NOTIFICATION 发布通知前

提示:权限校验应尽量前置,在 KitManager 入口统一处理,避免每个业务调用点重复编写权限代码。

十、Kit 调用链路设计

10.1 链路说明

完整的 Kit 调用链路从业务层发起,经 KitManager 分发、权限校验、错误封装后到达系统 Kit,结果再逐层返回。

  1. 业务层:Service 调用 KitManager.xxxKit.method()
  2. 权限校验:PermissionChecker.ensure 校验所需权限
  3. Kit 调用:子 Manager 调用系统 Kit 原生 API
  4. 错误封装:异常捕获后包装为 KitError 抛出
  5. 结果返回:成功结果经 KitResult 返回业务层
// service/FileService.ets
import { KitManager } from '../manager/KitManager'
import { KitResult, KitError } from '../model/KitModel'

export class FileService {
  static async readTextFile(filePath: string): Promise<KitResult> {
    try {
      const content: string = await KitManager.fileKit.readFile(filePath)
      return { success: true, data: content }
    } catch (e) {
      const err: KitError = e instanceof KitError ? e : new KitError(5999, '未知错误')
      return { success: false, error: err }
    }
  }
}

在这里插入图片描述

上图展示了从业务层到系统 Kit 的完整调用链路,权限校验与错误封装贯穿其中,保证调用的安全性与可控性。

总结

本文完整讲解了 HarmonyExplorer 的 KitManager 统一架构,涵盖六大 Kit 的封装实现、统一错误处理、统一权限管理与调用链路设计。KitManager 通过门面模式收敛系统能力调用,大幅降低了业务层的复杂度与维护成本。统一的错误码与权限前置校验也保证了工程的健壮性。希望这套封装实践能帮助你在鸿蒙项目中构建可维护的系统能力层。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!

相关资源

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐