base64-cj 使用指南:ArkTS 调用 Cangjie 版 Base64 编解码算法实战

原创2026-10-14 22:38:551,748 阅读
文章标签:OpenHarmony

base64-cj 使用指南:ArkTS 调用 Cangjie 版 Base64 编解码算法实战

本指南以 library/README.md 为主体,结合仓库源码(library/src/main/ets/components/MainPage.ets、library/src/main/cangjie/index.cj 等)展开,完整覆盖 base64-cj 的对外接口、安装接入方式、功能示例、实现原理与约束条件,帮助开发者在 HarmonyOS 应用工程中快速引入并理解这一套「ArkTS 调用 Cangjie 版 Base64」的编解码方案。

base64-cj 是一个以 OpenHarmony HAR 库形式发布的开源组件,核心价值是让 ArkTS 开发者通过简洁的函数调用,直接复用 Cangjie 语言标准库 encoding.base64 实现的 Base64 编解码算法。读完本文,你将掌握该库的全部 5 个对外 API、两种安装接入方式(中心仓安装与本地 module 引入)、两套完整可运行的功能示例,并能从源码层面理解 ArkTS 与 Cangjie 的互操作调用链。

项目概览与特性

base64-cj 的定位非常聚焦:ArkTS 调用 Cangjie 版 base64 编解码算法实现(见 library/README.md 的「介绍」与 library/oh-package.json5 中的包描述)。其核心特性是:

  • 支持 ArkTS 调用 Cangjie 版 base64 编解码,对外暴露字符串与字节数组两套数据形态的编码、解码能力。

源码目录结构

仓库采用典型的多模块 HarmonyOS 工程布局,README 给出了如下目录组织:

├─ AppScope
├─ entry                 # 示例代码
├─ hvigor                # 构建工具
├─ library               # 源码文件夹
│  └─ src
│      └─ main
│          ├─ cangjie    # cangjie 和 ArkTS 互操作代码
│          ├─ ets        # ets 对外接口
│          └─ resources
└─ README.md             # 库使用介绍

结合源码可以进一步明确各模块职责:

对外接口说明

base64-cj 对外共暴露 5 个函数,覆盖两种典型场景:字符串数据编解码 与 字节(ArrayBuffer/Uint8Array)数据编解码。README 中的接口定义如下:

/*
 * 将 ArrayBuffer 数据转换为 base64。
 *
 * 参数 data - 原始数据
 * 返回值 string - base64 数据
 */
function encode_Uint8Array(data: ArrayBuffer): string

/*
 * 将 base64 数据转换为 ArrayBuffer
 *
 * 参数 data - base64 数据
 * 返回值 ArrayBuffer - 原始数据
 */
function decode_Uint8Array(data: ArrayBuffer): ArrayBuffer

/*
 * 将 string 类型数据转换为 base64。
 *
 * 参数 data - 原始数据
 * 返回值 string - base64 数据
 */
function encode_String(data: string): string

/*
 * 将 base64 数据转换为 string 数据。
 *
 * 参数 data - base64 数据
 * 返回值 string - 原始数据
 */
function decode_string(data: string): string

/*
 * 将 base64 数据转换为 ArrayBuffer 数据。
 *
 * 参数 data - base64 数据
 * 返回值 ArrayBuffer - 原始数据
 */
function decode_String_toUint8Array(data: string): ArrayBuffer

为便于快速查阅,汇总为下表:

函数名 输入 输出 典型用途
encode_String(data) string 原始数据 base64 字符串 文本内容编码
decode_string(data) base64 字符串 原始字符串 文本内容解码
encode_Uint8Array(data) 字节数据 base64 字符串 二进制内容编码(如文件、图片字节)
decode_Uint8Array(data) 字节形式的 base64 数据 原始字节数据 二进制内容解码
decode_String_toUint8Array(data) base64 字符串 字节数据 base64 字符串还原为二进制

关于接口签名的实现细节

对照源码可以发现一个值得注意的细节:README 的接口注释以 ArrayBuffer 描述字节类型,而实际导出函数的 ArkTS 签名中,入参与返回值均为 Uint8Array(见 library/src/main/ets/components/MainPage.ets)。例如:

export function encode_Uint8Array(data: Uint8Array): string {
  return cjlib.toBase64StringUtf8Arkts(data)
}

export function decode_String_toUint8Array(data: string): Uint8Array {
  return new Uint8Array(cjlib.fromBase64StringUtf8Arkts(data))
}

而底层 Cangjie 互操作声明(library/src/main/cangjie/ark_interop_api/ark_interop_api.d.ts)中,字节类型则以 ArrayBuffer 呈现:

export declare interface CustomLib {
    toBase64StringArkts(data: string): string
    fromBase64StringArkts(data: string): string
    toBase64StringUtf8Arkts(data: ArrayBuffer): string
    fromBase64StringUtf8Arkts(data: string): ArrayBuffer
    fromBase64Uint8Array(data: ArrayBuffer): ArrayBuffer
}

这属于 ArkTS 侧包装层对字节形态的归一化处理:调用方统一使用 Uint8Array 视图操作数据,底层互操作层内部按 ArrayBuffer 传递。实际使用时,请以源码签名为准,传入 Uint8Array 即可(Uint8Array 本身是 ArrayBuffer 的视图,两者可互相转换)。

源码级实现原理:ArkTS 与 Cangjie 的互操作调用链

base64-cj 之所以能实现「ArkTS 调用 Cangjie 算法」,依赖的是 OpenHarmony 的 ArkTS-Cangjie 互操作机制。整条调用链可以从三处源码还原:

1. ArkTS 侧:加载 Cangjie 动态库并导出

在 library/src/main/ets/components/MainPage.ets 中,通过互操作加载器动态加载 Cangjie 编译产物:

import { requireCJLib } from "libark_interop_loader.so";
import { CustomLib } from "libark_interop_api.so";

const cjlib = requireCJLib("libcangjie_base64.so") as CustomLib

其中:

2. Cangjie 侧:@Interop[ArkTS] 标注导出函数

核心算法位于 library/src/main/cangjie/index.cj。该文件通过 @Interop[ArkTS] 宏将 Cangjie 函数暴露给 ArkTS,并直接复用 Cangjie 标准库 encoding.base64:

import ohos.ark_interop.*
import ohos.ark_interop_macro.*
import ohos.ark_interop_helper.*
import encoding.base64.*

@Interop[ArkTS]
public func toBase64StringArkts(data: String): String {
    return toBase64String(data.toArray())
}

@Interop[ArkTS]
public func fromBase64StringArkts(data: String): String {
    var opArr: Option<Array<Byte>> = fromBase64String(data)
    var result = match (opArr) {
        case Some(s) => unsafe { String.fromUtf8Unchecked(s)}
        case None => ''
    }
    return result
}

@Interop[ArkTS]
public func toBase64StringUtf8Arkts(data: Array<Byte>): String {
    return toBase64String(data)
}

@Interop[ArkTS]
public func fromBase64StringUtf8Arkts(data: String): Array<Byte> {
    var opArr: Option<Array<Byte>> = fromBase64String(data)
    var result: Array<Byte> = match (opArr) {
        case Some(s) => s
        case None => Array<Byte>()
    }
    return result
}

@Interop[ArkTS]
public func fromBase64Uint8Array(data: Array<Byte>): Array<Byte> {
    var opArr: Option<Array<Byte>> = fromBase64String(String.fromUtf8(data))
    var result: Array<Byte> = match (opArr) {
        case Some(s) => s
        case None => Array<Byte>()
    }
    return result
}

从中可以提取几个实现事实:

  • 算法来源:encoding.base64 是 Cangjie 标准库模块,toBase64String 负责编码、fromBase64String 负责解码,因此算法正确性与性能由 Cangjie 运行时保证;
  • 解码容错设计:fromBase64String 返回 Option<Array<Byte>>,Cangjie 侧通过 match 模式匹配处理:Some(s) 时正常返回解码结果,None 时返回空字符串或空数组,避免非法 Base64 输入直接抛错;
  • 编码路径差异:toBase64StringArkts 先将 String 转为字节数组(data.toArray())再编码,toBase64StringUtf8Arkts 则直接对 Array<Byte> 编码,对应 ArkTS 侧的两个编码函数;
  • 解码字节的转码细节:fromBase64StringUtf8Arkts 解码后直接返回 Array<Byte>;fromBase64Uint8Array 则先把输入字节按 UTF-8 转成字符串再解码,对应 ArkTS 侧 decode_Uint8Array 的实现。

3. 构建侧:cjpm 目标与依赖配置

library/src/main/cangjie/cjpm.toml 是 Cangjie 工程的构建清单,关键配置包括:

  • 包定义:name = "cangjie_base64"、output-type = "dynamic"(生成动态库供加载器按名加载)、version = "1.0.0"、cjc-version = "0.48.2";
  • 多目标平台:覆盖 aarch64-linux-ohos、x86_64-linux-ohos、x86_64-unknown-windows-gnu、aarch64-apple-darwin 等目标,其中 OHOS 目标通过 compile-option 指定 LLVM、musl、openssl 的链接路径;
  • 库依赖:依赖本地资源库 cj_res(版本 1.0.0)。

此外,library/oh-package.json5 表明 HAR 包还依赖了三个互操作相关组件:

{
  "name": "@cangjie-tpc/base64",
  "version": "1.0.0",
  "description": "ArkTS调用Cangjie版base64编解码算法实现。",
  "main": "Index.ets",
  "author": "cangjie-tpc",
  "license": "Apache-2.0",
  "repository": "https://gitcode.com/Cangjie-TPC/base64-cj.git",
  "dependencies": {
    "libark_interop_loader.so": "file:./src/main/cangjie/loader",
    "cjhyapiregister": "file:./har/CJHyAPIRegister-v1.0.1.har",
    "libark_interop_api.so": "file:./src/main/cangjie/ark_interop_api"
  }
}

其中 cjhyapiregister 是位于 library/har/CJHyAPIRegister-v1.0.1.har 的 HAR 组件,负责 Cangjie API 的注册支撑。这些依赖在使用本地 module 方式引入时会随包一并解析。

安装与引入方式

README 提供了两种接入方式,开发者可根据工程情况任选其一。

方式一:通过中心仓下载安装

在应用工程的 oh-package.json5 依赖已配好的前提下,执行:

ohpm install @cangjie-tpc/base64

安装完成后,即可在代码中按模块名引入(引入方式见下文)。

方式二:通过本地 module 引入

适合需要直接调试库源码或不便访问中心仓的场景,步骤如下:

  1. 克隆下载项目(仓库地址为 https://gitcode.com/Cangjie-TPC/base64-cj.git,可参考 library/oh-package.json5 中 repository 字段);

  2. 将 library 模块拷贝到应用项目下(即把仓库中的 library 目录整体复制到目标工程);

  3. 修改应用 entry 下的 oh-package.json5,在 dependencies 字段添加本地依赖:

    {
       "dependencies": {
          "@cangjie-tpc/base64": "file:../library"
       }
    }
    

    这与仓库示例工程自身的配置一致——entry/oh-package.json5 中正是以 "@cangjie-tpc/base64": "file:../library" 的方式引用了 library 模块。

  4. 在项目中使用以下方式引入:

    import { encode_String, decode_string, encode_Uint8Array, decode_Uint8Array, decode_String_toUint8Array } from "@cangjie-tpc/base64cj"
    

引入时的包名注意事项

README 示例代码中的导入路径写的是 @cangjie-tpc/base64cj,而依据 library/oh-package.json5 与 entry/oh-package.json5 的实际配置,仓库内真实有效的包名是 @cangjie-tpc/base64(ohpm install @cangjie-tpc/base64 亦与之对应)。实际集成时请统一使用:

import { encode_String, decode_string, encode_Uint8Array, decode_Uint8Array, decode_String_toUint8Array } from "@cangjie-tpc/base64"

仓库内的示例页面也均按此导入,例如 entry/src/main/ets/pages/CangjieBase64Example.ets 中的 import { encode_String, decode_string } from "@cangjie-tpc/base64"。

功能示例

示例一:字符串编解码(encode_String / decode_string)

README 给出的完整 ArkTS 页面示例,演示了字符串到 Base64、Base64 到字符串的往返过程,并配合 hilog 输出调试日志:

import { encode_String, decode_string } from "@cangjie-tpc/base64"
@Entry
@Component
struct CangjieBase64Example {
  private data: string = "hello cangjie"
  @State encodeResult: string = ''
  @State decodeResult: string = ''

  build() {
    Row() {
      Column() {
        Button("encode")
          .width(200)
          .onClick((event: ClickEvent) => {
             hilog.error(0x0000, 'CangjieBase64String', '%{public}s', `原数据: ${this.data}`);
             this.encodeResult = encode_String(this.data)
             hilog.error(0x0000, 'CangjieBase64String', '%{public}s', `encode: ${this.encodeResult}`);
          }).margin(10)

        Button("decode")
          .width(200)
          .onClick((event: ClickEvent) => {
             hilog.error(0x0000, 'CangjieBase64String', '%{public}s', `原数据: ${this.encodeResult}`);
             this.decodeResult = decode_string(this.encodeResult)
             hilog.error(0x0000, 'CangjieBase64String', '%{public}s', `decode: ${this.decodeResult}`);
          }).margin(10)

      }
      .width('100%')
    }
    .height('100%')
  }
}

要点说明:

  • 点击 encode 按钮:将 hello cangjie 编码为 Base64 字符串并存入 encodeResult;
  • 点击 decode 按钮:将 encodeResult 解码还原为原始字符串并存入 decodeResult;
  • 每次操作均通过 hilog.error 输出原数据、编码结果、解码结果,便于在日志中验证往返一致性。

仓库中该示例的增强版位于 entry/src/main/ets/pages/CangjieBase64Example.ets,额外加入了循环次数(10 次 / 100 次)基准测试,用 systemDateTime.getTime(true) 计时并输出 ns/op 单次耗时,可帮助评估编解码性能。

示例二:字节数据编解码(encode_Uint8Array / decode_String_toUint8Array)

README 给出的字节形态示例,演示了如何将 UTF-8 字符串转换为 ArrayBuffer 后编码,以及将 Base64 字符串解码回字节数据:

import { encode_Uint8Array, decode_String_toUint8Array } from "@cangjie-tpc/base64"
@Entry
@Component
struct CangjieBase64Example {
  private data: ArrayBuffer = Unit8ArrayUtils.StringToArrayBuffer("hello cangjie")
  @State encodeResult: string = ''

  build() {
    Row() {
      Column() {
        Button("encode")
          .width(200)
          .onClick((event: ClickEvent) => {
             this.encodeResult = encode_Uint8Array(this.data)
          }).margin(10)

        Button("decode")
          .width(200)
          .onClick((event: ClickEvent) => {
             const decodeResult = decode_String_toUint8Array(this.encodeResult)
          }).margin(10)

      }
      .width('100%')
    }
    .height('100%')
  }
}

这里用到的 Unit8ArrayUtils.StringToArrayBuffer 是仓库提供的工具类方法(见 entry/src/main/ets/pages/common/Unit8ArrayUtils.ets),内部基于 @kit.ArkTS 的 util.TextEncoder 将字符串编码为 ArrayBuffer。同文件中还提供了:

  • Uint8ArrayToString / stringToUint8Array:Uint8Array 与字符串互转(手写 UTF-8 编解码逻辑);
  • generateRandomArray(length):生成随机字节数组,便于构造测试数据;
  • generateRandomString(length):基于随机字节数组生成随机字符串,可用于批量压测数据构造;
  • StringToArrayBuffer(str):字符串转 ArrayBuffer。

仓库中字节形态的完整增强示例位于 entry/src/main/ets/pages/CangjieBase64Utf8Example.ets,同样内置了 10 / 100 / 1000 / 10000 次循环的耗时基准测试,并额外演示了 decode_Uint8Array 的直接字节解码路径:

this.decodeResult = decode_Uint8Array(Unit8ArrayUtils.stringToUint8Array(this.encodeResult))

示例页面导航

示例应用 entry/src/main/ets/pages/Index.ets 提供了 5 个可点击跳转的入口,除上述两个 Cangjie 示例页外,还包含与 OpenHarmony 系统 Base64(@ohos.base64,见 entry/src/main/ets/pages/OhosBase64Example.ets)以及纯 JS 实现的 btoa/atob(见 entry/src/main/ets/pages/common/base64.js)的对照示例页,便于在真实设备上对比不同实现的编解码行为。

约束与限制

README 明确说明,该库在以下版本组合下验证通过:

DevEco Studio 5.0.13.210
Cangjie Support Plugin 5.0.13.210

结合 library/src/main/cangjie/cjpm.toml 的配置可以推断,构建时还需要满足:

  • Cangjie 编译器版本与 cjc-version = "0.48.2" 匹配(环境变量 DEVECO_CANGJIE_HOME 需指向 Cangjie 工具链目录,供编译选项中的 LLVM、musl、openssl 路径解析使用);
  • 目标设备架构为 OpenHarmony 支持的 aarch64-linux-ohos(真机/模拟器常见架构)或 x86_64-linux-ohos(模拟器)。

因此,集成前请确认开发环境版本与目标设备架构满足上述要求;在其他版本组合下的兼容性,需要开发者自行验证。

开源协议与参与贡献

本项目基于 Apache License 2.0 开源(许可证全文见 library/LICENSE),可自由使用、修改与参与社区共建。欢迎通过提交 PR、提交 Issue 或任何形式参与贡献,贡献入口与维护说明以 library/README.md 为准。

登录后查看全文
base64-cj