ArkTS ArkGuard Obfuscation: Two Configs, Release Build, Bytecode-Level Protection
This guide explains how to enable ArkTS's built-in ArkGuard obfuscation with just two configuration files and a release build, detailing its bytecode-level operation, automatic semantic-aware rules for ArkUI and system APIs, multi-module rule management, mapping files for debugging, and step-by-step rollout with practical demos for property, filename, and dynamic access keep rules.
ArkGuard is the official obfuscation capability integrated into the ArkTS toolchain from API version 20. Unlike generic JavaScript/TypeScript obfuscators that require external plugins and separate pipelines, ArkGuard operates directly on Ark bytecode (abc) during the standard release build, with configuration confined to the module's build-profile.json5 and an obfuscation-rules.txt file.
Why ArkGuard Is Worth Enabling
Closer to the final deliverable: Works on the actual abc bytecode shipped to devices, avoiding intermediate source-code obfuscation and extra transformation steps.
Near-zero source-code intrusion: Developers keep readable names during development; name compression happens only in release builds.
Native ArkTS semantics awareness: Built-in rules and automatic allow-lists cover ArkUI component attributes, SDK APIs, Ability, Worker, HAR/HSP boundaries, reducing the common “builds but crashes at runtime” issues seen with generic obfuscators.
Complete multi-module coverage: obfuscation-rules.txt, consumer-rules.txt, and the published obfuscation.txt handle apps, source libraries, and bytecode libraries without each module inventing its own rule-passing scheme.
Debuggable after protection: nameCache.json, sourceMaps.json, config.json, and hstack form a traceable chain; protection strength and production maintainability are no longer mutually exclusive.
Low adoption and rollback cost: Two config changes + one release build to verify; per-module toggle for troubleshooting; mapping files quickly reveal which names changed.
Compared to generic JS/TS obfuscation plugins, ArkGuard eliminates the external pipeline and adds ArkTS/ArkUI/system-API semantic awareness. Compared to post-packaging scripts, it is generated, packaged, and mapped within the official build flow, reducing adaptation costs for artifact structure, signing, and version upgrades. Compared to app hardening/shelling, name obfuscation is lighter, integrates earlier, and has lower daily build cost, making it suitable as a baseline release-time defense; high-security scenarios can layer hardening on top.
Five-Minute Start: Two Configs + Release Build
In the module's build-profile.json5, enable the obfuscation switch and point to the rules file:
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": true,
"files": ["./obfuscation-rules.txt"]
}
}
}In obfuscation-rules.txt, enable bytecode obfuscation and optional sub-features:
-enable-bytecode-obfuscation
-enable-property-obfuscation
-enable-toplevel-obfuscation
-enable-filename-obfuscation
-enable-export-obfuscationBoth enable: true and -enable-bytecode-obfuscation must be present for the ArkGuard pipeline to activate.
Build in release mode (debug builds do not obfuscate), e.g.:
hvigorw assembleHap -p product=default -p buildMode=release --no-daemonWhen investigating whether a behavioral difference is caused by obfuscation, toggle ruleOptions.enable rather than relying solely on debug/release switches, because the two modes differ in more ways than just obfuscation.
Hands-On Demo: OrderHelper Before and After
Source ( OrderHelper.ts):
class OrderHelper {
static orderId: string = ''
static createId(prefix: string): string {
OrderHelper.orderId = `${prefix}_20260725`
return OrderHelper.orderId
}
static printOrder(): void {
console.info(`[obfuscation-demo] ${OrderHelper.orderId}`)
}
}
OrderHelper.createId('ORD')
OrderHelper.printOrder()After enabling -enable-bytecode-obfuscation, -enable-property-obfuscation, and -enable-toplevel-obfuscation and building release, the tool produces: origin/modules.abc – pre-obfuscation bytecode obf/modules.abc – post-obfuscation bytecode nameCache.json – original-to-short-name mapping modules.pa – instruction-level textual bytecode (when debugging enabled)
Example nameCache.json mapping (format illustration; actual names are assigned per build):
{
"entry/src/main/ets/utils/OrderHelper.ets": {
"IdentifierCache": { "#OrderHelper": "a" },
"MemberMethodCache": {
"OrderHelper:0:0": "a",
"createId:4:7": "b",
"printOrder:9:11": "c"
},
"obfName": "entry/src/main/ets/utils/OrderHelper.ets",
"OriSourceFile": "entry|entry|1.0.0|src/main/ets/utils/OrderHelper.ts",
"ObfSourceFile": "entry|entry|1.0.0|src/main/ets/utils/OrderHelper.ts"
},
"entryPackageInfo": "entry|1.0.0",
"compileSdkVersion": "5.0.0.70",
"PropertyCache": { "orderId": "i" },
"FileNameCache": {}
}Equivalent pseudo-code of the obfuscated bytecode:
class a {
static i: string = ''
static b(prefix: string): string {
a.i = `${prefix}_20260725`
return a.i
}
static c(): void {
console.info(`[obfuscation-demo] ${a.i}`)
}
}
a.b('ORD')
a.c()Runtime behavior is unchanged; static analysis now sees a.b(), a.c(), and a.i instead of self-explanatory names. Parameter prefix remains unobfuscated; short names are assigned per build and should not be assumed stable.
Automatic Keep Rules (Default Allow-List)
ArkGuard automatically preserves names required for framework compatibility (e.g., ArkUI @State, @Prop, component lifecycle methods, SDK APIs, Ability/Worker entry points). The article recommends relying on these defaults rather than manually copying large allow-lists. To observe property renaming, use plain business helper classes as test subjects.
Case B: Static Definition + Dynamic Access – Writing Correct Keep Rules
Pattern: property defined statically but accessed via a computed string.
const obj = { orderId: 5 }
const fieldName = 'order' + 'Id'
console.info(obj[fieldName]) // relies on original property name 'orderId'With -enable-property-obfuscation, the static orderId may be renamed while the string literal 'orderId' stays literal → runtime failure. Fix with -keep-property-name orderId.
String-literal property keys (e.g., {'firstName': 'abc'} or person['personAge']) are not obfuscated unless -enable-string-property-obfuscation is explicitly enabled. The real danger is the combination of renamed static members and unchanged string-based access.
Filename / Dynamic Import / Router
-keep-file-namepreserves the file or directory name (without extension), not a full path like pages/OrderDetail.
# Correct: name component
-keep-file-name
OrderDetail
file2
# Incorrect: full path segment
# -keep-file-name
# pages/OrderDetailTypical must-keep scenarios:
Dynamic import(path) where path is a runtime string.
routerMap pageSourceFilein module.json5.
Pages navigated via router.pushUrl / ohmUrl with path strings.
Compiler entry points, Ability, and Worker filenames are auto-allow-listed in newer DevEco versions; other dynamic paths still need manual keep rules.
Case C: HAR / HSP – Three Rule Files
Library module build-profile.json5:
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": true,
"files": ["./obfuscation-rules.txt"]
},
"consumerFiles": ["./consumer-rules.txt"]
}
} obfuscation-rules.txt– rules applied when building the library itself. consumer-rules.txt – rules passed to consumers; should contain only keep rules (e.g., -keep-global-name formatPrice, -keep-property-name tradeNo amount) to avoid leaking obfuscation switches downstream. obfuscation.txt – published with bytecode HARs; consumed by dependents when declared in the module's oh-package.json5 (project-level dependency alone is insufficient).
Dependency shape matters:
Local HAR / published-source HAR (oh_modules): Source code is obfuscated together with the consumer; mappings land in the consumer's obfuscation/nameCache.json; exported names are auto-collected into the no-obfuscate set.
Bytecode HAR: To keep declarations and implementation consistent, the consumer does not re-obfuscate the HAR's abc; obfuscation happened when the HAR was built. Correct integration still relies on exported-name collection and consumer-rules.txt → obfuscation.txt flow.
Third-party library obfuscation.txt : Only effective when declared in the module's oh-package.json5.
Recommended Step-by-Step Enablement Order
Enable one feature at a time, run functional regression after each step; on failure, inspect nameCache.json + config.json and add the minimal keep rules – close the loop first, then add scenario-specific preserves. -enable-bytecode-obfuscation – get release building. -enable-toplevel-obfuscation (use -keep-global-name for globalThis accesses). -enable-property-obfuscation (static/dynamic properties, NAPI/JSON/DB fields via -keep-property-name). -enable-export-obfuscation (HSP/HAR public APIs via -keep-global-name / -keep-property-name). -enable-filename-obfuscation (dynamic import, routerMap, ohmUrl via -keep-file-name).
DevEco's ObfuscationHelper can scan and suggest allow-lists; dynamic string scenarios still require manual review.
Release & Debugging: Backup obfuscation/ + hstack
At release, back up the entire build/default/cache/.../release/obfuscation directory (or the whole release folder). De-obfuscation requires nameCache.json and sourceMaps.json (or the project's source-map artifacts). Use hstack from DevEco Command Line Tools to restore obfuscated stack traces.
From Basic Obfuscation to Defense-in-Depth
ArkGuard's name transformation + precise keep rules form the baseline always-on code protection for release builds, suitable for default inclusion in the app pipeline.
Under ArkTS's structural type system, property keep rules apply globally by name; consistent cross-type field naming lets keep rules stay minimal while maximizing obfuscation coverage.
For higher-security apps, layer app encryption and app hardening on top, building a defense-in-depth system from code-semantic protection to artifact protection.
Summary
Unified entry: build-profile.json5 + obfuscation-rules.txt + release.
Fewer semantic pitfalls: ArkUI/SDK auto allow-lists reduce useless keep rules.
Predictable collaboration: Three rule files + HAR single-obfuscation convention.
Reproducible debugging: Clear obfuscation/ artifact structure, hstack in the toolchain.
Read mappings, write keep rules, enable switches incrementally – follow the actual artifact fields and recommended order so examples match engineering behavior and the delivery chain stays controllable.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
HarmonyOS Developer Technology
HarmonyOS developers provide key technology analysis, version updates, Codelabs practice, and event information for HarmonyOS. Welcome developers to join the HarmonyOS ecosystem and create infinite possibilities together!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
