鸿蒙 uts 插件加密盲区:一个后缀,让 .ets 混编源码不再裸奔

适用场景:uni-app x + HarmonyOS NEXT + uts 插件 + ArkTS 声明式 UI 混编(native-view / @Builder)
关键词:uts 插件、付费插件加密、鸿蒙混编、ets、native-view

一、背景:鸿蒙原生 UI 必须写进 uts 插件的"混编文件"

uni-app x 编译到鸿蒙(4.31+ JSVM 架构)后,uvue 页面跑在 JSVM 里,不能直接调用鸿蒙原生 API。想用系统级能力(比如原生材质、原生组件、沉浸光感),标准路径只有一个:

  1. uvue 里放 native-view 组件;
  2. uts 插件里通过 bindHarmonyWrappedBuilder 挂载 ArkTS 的 @Builder 声明式 UI;
  3. 原生事件通过 dispatchEvent 回传给 uvue。

而 ArkUI 声明式界面(@Builder、Column(){} 这类 DSL)不能写在 .uts 里,官方文档《uts for HarmonyOS》写得很明确:

“uts 插件内的 ets 文件会原样拷贝到产物内,如果需要开发 ArkUI 声明式界面可以在 ets 文件内编写,uts 文件内引用。”

于是插件目录会长这样:

utssdk/app-harmony/
├── index.uts        // 逻辑入口,import "./builder.ets"
└── builder.ets      // @Builder 声明式 UI(原样拷贝进鸿蒙工程)

问题,就出在这个"原样拷贝"上。

二、发现:付费插件的加密规则,漏掉了鸿蒙 ets 文件

如果你把插件发布为付费插件,DCloud 插件市场会提供自动加密保护。《制作和发布插件指南》里写的加密规则是:

  • 加密除 interface.uts 之外的所有 uts 文件
  • 加密 utssdk/app-android 及 utssdk/app-ios 目录下的 java、kt、swift 等混编文件

对照一下就很清楚了:

文件是否被加密
xxx.uts✅ 所有 uts 文件都在范围内
app-android/*.kt、app-ios/*.swift✅ 规则第二条覆盖
app-harmony/builder.ets❌ 两条规则都不沾

它既不是 .uts 文件,又不在 app-android / app-ios 目录里。结果是:付费插件加密之后,builder.ets 依然是明文——变量名、业务逻辑、甚至中文注释全都原样暴露,付费插件的知识产权保护形同虚设。

这显然是个规则盲区:混淆点在于,鸿蒙混编文件的官方定位叫"ets 文件",而加密工具的匹配口径是"uts 文件"。

三、解法:给文件加一个 .uts 后缀

改一个文件名就够了:

utssdk/app-harmony/
├── index.uts
└── builder.ets.uts      // ← 原来叫 builder.ets

index.uts 里的 import 写法保持原样,不需要改:

import { buildNativeTabBar, changeTabIndex } from "./builder.ets"

实测结果:

  1. 加密命中:文件以 .uts 结尾,落入"除 interface.uts 外的所有 uts 文件"规则,付费插件加密后源码不可读;
  2. 编译正常:HBuilderX 编译通过,无报错;
  3. 运行正常:真机上原生 UI 渲染、交互与改名前完全一致。

也验证过另一种目录写法,同样可行(适合一个模块拆多文件的场景):

utssdk/app-harmony/
├── index.uts                          // import "./builder/index.ets"
└── builder/
    └── index.ets.uts

import 写成 "./builder/index.ets" 即可。

四、为什么两头都能跑通?

加密侧很好理解:规则按文件后缀匹配,xxx.ets.uts 以 .uts 结尾,自然被"所有 uts 文件"这条规则兜住。

编译侧则是因为 builder.ets.uts 已经不是"原样拷贝"的混编文件,而是进入了 UTS 编译链。这一点在编译产物里可以直接验证——产物目录里的这个文件仍然叫 builder.ets,但内容已带上了编译器注入的 sourceMap 注释:

// 源文件 builder.ets.uts
console.log(`[NATIVE-TABBAR] changeIndex -> ${index}`)

// 产物 builder.ets(编译后)
console.log(`[NATIVE-TABBAR] changeIndex -> ${index}`, " at .../builder.ets:52")

同时 index.ets 产物中的 import 会被规范化为模块名引用:

// 源 index.uts
import { buildNativeTabBar, changeTabIndex } from "./builder.ets"
// 产物 index.ets
import { buildNativeTabBar, changeTabIndex } from "./builder"

也就是说:文件后缀负责"被加密",编译器负责"把 ets 语义原样带进产物",两者互不冲突。对插件使用者而言,加密版插件照常走云端解密编译流程,功能不受影响。

五、注意事项

  • 本质是规则边界的务实用法,不是官方文档写法。官方后续若补全鸿蒙 ets 的加密规则,可以改回 builder.ets;目前保持双后缀也无副作用(已实测)。
  • 文件进入 UTS 编译链后,需要同时满足 uts 与 ArkTS 两套语法约束。纯声明式 UI 实测没有问题,但如果你后续在文件里使用了较新的 ArkTS 语法,务必重新编译验证。
  • interface.uts 按官方设计不加密,敏感信息不要写在那里。
  • 鸿蒙 uts 付费插件要求 HBuilderX 4.81+,且加密插件只能走云端传统打包(不支持离线打包、安心打包);鸿蒙平台需要云端编译。
  • 发布前记得自查:以加密版(或试用版)跑一次编译,确认目标文件确实不可读。

六、小结

一句话总结:把鸿蒙混编的 builder.ets 改名为 builder.ets.uts,import 不变,加密生效,功能照常。

这个坑不算深,但确实会让付费插件作者白掉一层"保护壳"——希望这篇记录能帮到同样在鸿蒙上做原生 UI 混编的开发者。如果官方后续修正了加密规则,欢迎回来改回单后缀。

Logo

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

更多推荐