本文记录 smooth-rounded-corner-shape 接入 OpenHarmony 的完整过程,覆盖 Compose 平滑圆角库盘点、鸿蒙 Kotlin 工具链选型、androidx.graphics:graphics-shapes 几何内核移植、ohosArm64 / ohosX64 目标、Kotlin/Native 动态库、C ABI/N-API 桥接、ArkUI 真机页面、HAP 构建和真机验收。

smooth-rounded-corner-shape 是一个极小的 Compose Multiplatform 平滑圆角库:SmoothRoundedCornerShape / AbsoluteSmoothRoundedCornerShape / Path.smoothRoundedRectangle 在 RoundedCornerShape 之上增加 smoothing 参数(0~1,约等于 Figma 的 Corner smoothing 百分比,0.6f 即 iOS 同款连续圆角),自身不含任何平滑数学——每个角的三次贝塞尔全部由 AndroidX 的 graphics-shapes(RoundedPolygon + CornerRounding)算出。本次适配与社区 KStore 路线(“真编译整库 + 补一个 actual”)的方向相反:graphics-shapes 与 compose.ui / compose.foundation 一样没有 ohos 制品,Compose 面在当前工具链下编不进鸿蒙,因此把上游实际依赖的 graphics-shapes 1.0.1 的 RoundedPolygon(vertices, perVertexRounding) 管线逐表达式移植成纯 Kotlin(不升版本、不改数学、不重写算法),上游 4 个 Compose 文件原文隔离到 src/composeMain 等待制品,移植正确性由 21 项 JVM 对拍用例对着真实的 graphics-shapes 1.0.1 逐 float 验证——ArkUI 页面作为验收宿主,交付物是矢量 SVG 路径。

项目地址: AtomGit/oh-tpc/smooth-rounded-corner-shape

上游仓库: iamcalledrob/smooth-rounded-corner-shape

开发工具: 华为云码道

环境安装: 环境安装指南

一、背景

1.1 为什么做 OpenHarmony 平台 KMP/CMP 适配

smooth-rounded-corner-shape 解决一个具体问题:RoundedCornerShape 的圆角在直线与圆弧相切处曲率突变,视觉上"生硬";超椭圆(squircle)过渡没有这个切点。iOS 的连续圆角、Figma 的 Corner smoothing 滑杆都是这个思路。上游把 smoothing 接进 Compose 的 Shape 体系:方向敏感的 SmoothRoundedCornerShape(CornerBasedShape 子类,跟随 LayoutDirection)、绝对方向的 AbsoluteSmoothRoundedCornerShape、直接产出 Path 的 Path.smoothRoundedRectangle。KMP 项目把这些能力放在 commonMain,由 Android、桌面共享。OpenHarmony 应用同样需要这套圆角能力,但上游构建(Kotlin 1.9.23 / Compose 1.6.11 / AGP 8.2.0)不会生成 OpenHarmony 变体。

如果只把示例页面改成 ArkTS,页面可以画一个普通圆角矩形,却无法证明上游的平滑数学在 OpenHarmony ARM64 设备上完成编译、链接和执行。适配需要同时验证几何内核、交叉编译工具链、Native 动态库、C ABI、N-API、ArkUI 页面和 HAP 交付链路。

障碍具体问题
目标缺失必须增加 ohosArm64() / ohosX64() 才能生成 OpenHarmony KLIB。
工具链不一致上游 Kotlin 1.9.23 + AGP 8.2.0 + vanniktech 发布插件与鸿蒙工具链无法共存于一个 Gradle 构建,根构建必须整体替换。
依赖矩阵平滑数学全部在 androidx.graphics:graphics-shapes,Compose 面还依赖 compose.ui / compose.foundation——三者都没有 ohos 变体,一个都解析不到。
语言边界不同ArkTS 不能直接持有 Kotlin 对象或调用 @CName 符号,需要 C ABI、C++ N-API 和 JSON。
几何语义跨不了桥CornerBasedShape 的 start/end 方向语义、CornerSize(percent) 解析规则是 Compose 层概念,C ABI 只能同步一来一回。
交付链路复杂.so、CMake、N-API、HAP、签名和 hdc 都要单独验收。

因此,本项目把边界放在:graphics-shapes 1.0.1 几何内核的逐表达式移植、根构建替换(cmp_qrose 模式)和 C ABI/N-API 桥接层。圆角的方向/百分比语义完全在桥接层对齐 Compose 行为,ArkTS 只负责调用 Native、解析 JSON 和用 Path().commands() 画结果。

1.2 库提供的能力

Demo 提供一个真实的几何渲染会话,对应桥接的全部入口:

  • 平滑角渲染:SmoothCornerGeometry.cubics(...) 按 smoothing / 四角半径 / 宽高产出闭合轮廓,svgPath 摊平成 M ... C ... Z 绝对路径,ArkUI Path().commands() 直接消费——矢量无损、分辨率无关;
  • 平滑档位:smoothing 滑杆 0~1 实时重绘,0 退化为纯圆角、0.6 是 Figma 60% / iOS 档、1 两翼曲线相接;
  • 对照轮廓:同一参数但 smoothing=0 的红色描边叠在平滑轮廓之下,切点差异一目了然;
  • RTL 语义:开关镜像 start/end 四角,对应上游 SmoothRoundedCornerShape 的 LayoutDirection.Rtl 行为;
  • 百分比语义:percent=true 时圆角按 min(宽, 高) 的百分比解析,对应 Compose CornerSize(percent);
  • 版本握手:smoothCornerVersion() 返回 fork 版本号 1.0.4-ohos.1,来自真实 Native 调用而非静态文字。

响应包含:

字段作用
ok操作是否成功,失败时 error 带原文。
width / height / smoothing / rtl回显本次几何参数。
cubicCount三次贝塞尔段数:全直角 = 4,四角圆角(smoothing=0)= 9,四角全平滑 = 17。
path绝对坐标 SVG 路径字符串,坐标 3 位小数。

内核侧完整能力(RoundedCorner 切割量计算、侧翼曲线、圆弧 cubic 近似、零长度段丢弃、首角圆弧对半拆分闭合)全部随移植进入 .so,JVM 侧保留 21 项对拍用例对着真实 graphics-shapes 1.0.1 逐 float 验证,证明 ohos .so 里执行的几何没有漂移。

1.3 实现适配

维度要求
内核移植graphics-shapes 1.0.1 的 RoundedPolygon 管线逐表达式移植,魔数、运算顺序、分支顺序全部保留原样;不升 1.1.0(对拍基准必须等于上游声明的依赖版本)。
上游保真4 个 Compose 文件 + 2 个 actual 原文移入 src/composeMain(不注册源码集),git 识别为 100% 重命名,零修改留档。
平台目标根构建直接声明 ohosArm64 + ohosX64,保留 jvm() 作对拍车道,库模块出 KLIB,example/nativeApp 出双 ABI 动态库。
构建隔离根构建替换为极简 ohos 构建(cmp_qrose 模式);AGP / Compose 插件 / vanniktech 发布 / signing 全部剥离——本 fork 不发 Maven Central。
桥接稳定使用 2 个 C ABI 和 UTF-8 JSON,不传递 Kotlin 对象地址;异常永远不跨 FFI。
UI 完整双页签覆盖全部桥接参数:宽高、smoothing、四角联动/独立、RTL、百分比、色板、对照轮廓和版本握手。
仓库规范项目说明、文章、效果图和源码链接统一使用 AtomGit。

本项目的 ArkUI 页面不是 Compose Multiplatform UI 实现。上游的公共面就是 Compose Shape,当前工具链编不进鸿蒙,所以鸿蒙侧的公共面是几何内核本身;ArkTS Demo 只是把桥暴露的几何能力画出来。

二、实现路线图

第 1 阶段:项目初始化     ── 盘点模块与依赖边界、确认 graphics-shapes 无 ohos 制品、确定交付物
第 2 阶段:目标与依赖打通 ── 根构建替换、eazytec Maven 置前、Kotlin 2.2.21-1.0.0 钉版、源码集拆分与 composeMain 隔离
第 3 阶段:内核移植       ── graphics-shapes 1.0.1 逐表达式移植、公共入口 SmoothCornerGeometry、JVM 对拍
第 4 阶段:桥协议与原生桥接 ── JSON 契约、@CName C ABI、C++ N-API、参数校验和内存释放
第 5 阶段:ArkUI 宿主     ── 双页签、滑杆实时重绘、红色对照轮廓和版本握手
第 6 阶段:示例与验证     ── HAP、签名、设备安装、真机运行和效果图

三、逐步实现过程

第 1 阶段:项目初始化

1.1 工程边界
smooth-rounded-corner-shape/          库模块(进 ohos 构建,jvm + ohosArm64 + ohosX64)
  src/commonMain/.../geoshape/        新增:GraphicsShapesPort.kt(内核移植)+ SmoothCornerGeometry.kt(公共入口)
  src/composeMain/                    上游 4 个 Compose 文件 + 2 个 actual 原文,不注册源码集
  src/jvmTest/.../geoshape/           新增:21 项对拍用例(对真实 graphics-shapes 1.0.1)
example/nativeApp/                    Kotlin/Native 动态库(Bridge + MiniJson)
example/harmonyApp/                   DevEco Stage、CMake N-API 和 ArkTS 双页签
README.OpenHarmony.md / _CN.md        鸿蒙适配说明(中英双份)
README.upstream.md                    上游原文保存
doc/                                  本文与效果图

构建拓扑走 cmp_qrose 模式(根构建即 ohos 构建):settings.gradle.kts 只 include :smooth-rounded-corner-shape 与 :example:nativeApp,rootProject.name = "ohos_smooth_corner_shape"。上游根构建里的 vanniktech 发布、signing、AGP、Compose 插件全部随根构建替换剥离——本 fork 不发 Maven Central,上游的 Android / Desktop 变体继续用上游 1.0.4。

1.2 工具链矩阵
项目配置
Kotlin MultiplatformHarmonyOS Kotlin 2.2.21-1.0.0(eazytec Maven,与已过审的 cmp_qrose 同款钉法)
JDK21(Temurin,org.gradle.java.home 写进 gradle.properties)
OpenHarmony 目标ohosArm64 + ohosX64(jvm() 保留作对拍车道)
Gradle8.14.1(wrapper 随钉法调整;2.2.21 线使用 8.x)
几何依赖androidx.graphics:graphics-shapes:1.0.1——上游钉的版本,仅 jvmTest 对拍解析
DevEco product5.1.0(18) 兼容
DevEco Studio5.1.0 Release
ABIarm64-v8a + x86_64
Bundleorg.terminator.ohos.smoothcorner
1.3 源码依赖度盘点
模块文件依赖形态处置
上游 commonMain4compose.foundation.shape.* + compose.ui.* + graphics-shapes.*,零平台专属 API移入 composeMain,不编译(等 ohos 制品)
上游 androidMain / nonAndroidMain2toComposePath actual(android.graphics.Path / Compose Path 摊平)随 actual 移入 composeMain 留档
graphics-shapes 1.0.16纯 Kotlin 数学(无 Android 依赖),Point 是 androidx.collection.FloatFloatPair 的 typealias逐表达式移植成零依赖纯 Kotlin(见第 3 阶段)

值得说明的是 graphics-shapes 的依赖面:它的 commonMain 本身是纯 Kotlin 数学库,唯一的"外部依赖"是 androidx.collection 的 FloatFloatPair(被 typealias 成内部 Point)和 MutableFloatList——而 androidx.collection 同样没有 ohos 变体。移植时用零依赖的 Pt 类与 FloatArray 等价替换(只影响存储,不影响算术),这是移植能做到"零第三方依赖"的原因。

1.4 页面边界
标题区          SmoothRoundedCornerShape · OpenHarmony / 版本握手行(Kotlin/Native 内核 · 1.0.4-ohos.1)
Tab 切换        形状预览 / 关于
预览区          Stack:平滑轮廓(填充或描边)+ 红色对照轮廓(smoothing=0,可开关)
参数区          宽度 / 高度 / 平滑 smoothing 滑杆,四角联动开关 + 圆角半径滑杆(联动)或四角独立滑杆
语义开关        RTL(镜像 start/end)、百分比圆角(CornerSize %)、填充/描边、对照轮廓
色板区          五套前景/背景配色 + 重置按钮
状态行          最近一次渲染结果(如"17 段三次贝塞尔 · 300×300 · smoothing=0.6")
关于区          版本握手、库简介、调用链、桥接协议、验收要点、仓库与社区链接

页面启动时先调 smoothCornerVersion() 做握手,再以默认参数(300×300、r=50、smoothing=0.6)发起首次渲染。

第 2 阶段:目标与依赖打通

2.1 制品线验证(本适配的成败手)

KStore 那类存储库的适配首先验证"社区 Maven 上有没有 ohos 制品",结论是"有,真编译整库"。本库验证的结论恰好相反,三个关键对象逐一查证:

androidx.graphics:graphics-shapes        → Maven Central / google() 只有 android + jvm 变体,无 ohos
androidx.compose.ui / compose.foundation → 无 ohos 变体;社区 CMP 1.9.2 是应用侧独立发行版,
                                           不是能从 Maven 消费的 Gradle KMP 依赖
androidx.collection(Point 的老家)      → 多平台 native 变体不含 ohos

结论:上游的公共 API 在当前工具链下编不进鸿蒙,但它的数学内核是纯 Kotlin。于是路线确定——把数学搬进 commonMain(移植),把 Compose 面原样封存(composeMain),鸿蒙交付几何。这与 KStore"真编译整库"不矛盾:路线选择必须基于当天的制品可达性,存储库的制品线在,图形库的制品线不在。

2.2 工具链钉版(为什么是 2.2.21-1.0.0 + Gradle 8.14.1)

本库 commonMain 移植后没有任何外部依赖,没有 KStore 那种"kotlinx 制品线 stdlib 元数据倒逼 Kotlin 升版"的约束。工具链因此跟随社区已过审的 cmp_qrose 钉法:Kotlin 钉 2.2.21-1.0.0,Gradle Wrapper 钉 8.14.1,JDK 钉 21。两条工具链线的经验不能互相套用:2.4.20 线(KStore / continuous-corner 用)支持 Gradle 9.x,2.2.21 线用 8.14.1;本仓在 2.2.21 线上从零构建,直接落 8.14.1。

settings.gradle.kts 把 eazytec 仓库写在最前:

pluginManagement {
    repositories {
        maven("https://maven.eazytec-cloud.com/nexus/repository/maven-public/")
        maven("https://maven.eazytec-cloud.com/nexus/content/groups/harmonyos")
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}

rootProject.name = "ohos_smooth_corner_shape"

include(":smooth-rounded-corner-shape")
include(":example:nativeApp")
2.3 源码集拆分与 composeMain 隔离

这是本库特有的一刀:continuous-corner 只挪"依赖 graphics-shapes 的实现文件",本库则是整个上游公共 API都依赖 Compose 面——4 个 commonMain 文件(SmoothRoundedCornerShape、AbsoluteSmoothRoundedCornerShape、Path.smoothRoundedRectangle、RoundedPolygon.toComposePath expect)加 2 个 actual(androidMain / nonAndroidMain)全部原封不动移入 src/composeMain 的 kotlin/、androidMain/kotlin/、nonAndroidMain/kotlin/ 三个子目录,不注册为源码集,配一篇 README.md 说明隔离原因与接回条件。挪完之后 commonMain 清零,新的公共面就是移植内核的 SmoothCornerGeometry。git 对这批文件识别为 100% 重命名——上游保真是可审计的。

库模块构建收敛为纯 KMP:

kotlin {
    applyDefaultHierarchyTemplate()
    jvmToolchain(21)

    jvm()          // 对拍车道,不是为了跑 Compose
    ohosArm64()
    ohosX64()

    sourceSets {
        val jvmTest by getting {
            dependencies {
                implementation(kotlin("test"))
                implementation(libs.androidx.graphics.shapes)   // 真实 1.0.1,仅测试解析
                implementation(libs.androidx.collection)
            }
        }
    }
}

实测:

./gradlew :smooth-rounded-corner-shape:compileKotlinOhosArm64 :smooth-rounded-corner-shape:compileKotlinOhosX64
# BUILD SUCCESSFUL,双架构 klib
2.4 测试的处置:对拍统一 JVM

与 KStore 相同的两条纪律:测试统一在 JVM 跑,根构建全局禁用 ohos 测试任务:

subprojects {
    tasks.matching { it.name.contains("Ohos", ignoreCase = true) && it.name.contains("Test") }
        .configureEach { enabled = false }
}

不同之处在测试的来源:上游库没有自带测试,本 fork 的对拍用例是新写的——它们不是"上游测试照跑",而是把真实 graphics-shapes 当作参照实现,验证移植内核与它逐 float 一致(见第 3 阶段)。

第 3 阶段:内核移植(本适配的核心)

3.1 移植面收窄

上游对 graphics-shapes 的调用只有一处、形态非常收敛:

RoundedPolygon(
    vertices = floatArrayOf(0,0, w,0, w,h, 0,h),
    perVertexRounding = listOf(CornerRounding(topLeft, smoothing), ...同四角...)
).cubics   // → List<Cubic> → Compose Path

移植面因此只需要:RoundedPolygon(FloatArray, List<CornerRounding>) 构造器与 .cubics 的输出逐位一致。GraphicsShapesPort.kt(全 internal)覆盖以下管线:

  • RoundedCorner:角切割量 expectedRoundCut = radius·(cosA+1)/sinA;空间不足时先保双侧圆角再分平滑余量的三级 cutAdjusts 分配;computeFlankingCurve 侧翼曲线(圆切线与直边求交作锚点、2/3 取点);Cubic.circularArc 圆弧 k 常量近似;两侧独立的 actualSmoothing 线性缩放。
  • Cubic:8 浮点平铺存储、split(首角圆弧对半拆分闭合用)、reverse、straightLine、circularArc、zeroLength。
  • Point 代数:零依赖 Pt 替换 FloatFloatPair typealias,只保留管线用到的运算。
  • Feature(Corner/Edge)与 cubics 构建器:零长度段丢弃并把锚点前移、首特征三段时把中段圆弧 split(0.5f) 拆到起点两侧、末段复制并吸附首锚点保证精确闭合——这三条直接决定段数(全平滑矩形是 17 段不是 16 段),是"看起来对"和"逐位对"的分水岭。
  • 不移植:Morph、transformed / normalized / bounds、numVertices 工厂、MutableCubic、调试日志。
3.2 移植的求值顺序纪律

对拍能逐 float 通过的前提,是移植不只是"算法一样",而是表达式一样。浮点运算不满足结合律,(a+b)+c ≠ a+(b+c) 在第 15 位有效数字上的差异会经过侧翼曲线的乘除放大到 1e-4 量级。移植遵守三条纪律:

  1. 常量原样搬运:4f/3f、0.999f、1e-3(sinAngle 阈值)、2/3 取点比例全部保留原字面量与原类型,不"顺手化简";
  2. 运算顺序原样保留:circularArc 里 distance(...) * 4f / 3f * (sqrt(...) - sqrt(...)) / (1 - cosa) * (±1f) 的乘除链不重排;
  3. 控制流原样保留:cutAdjusts 的三级分配与 calculateActualSmoothingValue 的两段线性缩放,分支顺序与上游一致——极端参数(超大半径、退化小尺寸)下分支顺序决定走哪条数值路径。

文件头按 Apache-2.0 声明来源与版权;公共面只有 SmoothCornerGeometry.cubics / percentRadius / svgPath 与数据载体 ShapeCubic。

3.3 方向与百分比语义放在哪

上游有两层语义,移植内核不掺和,由桥接层对齐:

  • RTL:SmoothRoundedCornerShape.createOutline 在 LayoutDirection.Rtl 时交换 start/end。桥接层按同一规则交换后再调内核,与 Compose 行为逐角一致;
  • 百分比:Compose 的 CornerSize(percent) 按 min(宽, 高) 解析。桥接层 percent=true 时走 percentRadius。

内核只做纯几何,Composable 语义的任何后续修正都不会碰移植代码。

第 4 阶段:原生桥接(技术难点)

4.1 三层桥接
ArkTS
  │ JSON string
  ▼
C++ N-API entry(libsmoothcorner_napi.so)
  │ const char*
  ▼
Kotlin/Native C ABI(libohossmoothcorner.so)
  │ SmoothCornerRender / SmoothCornerVersion
  ▼
UTF-8 JSON + DisposeString
4.2 Kotlin/Native 导出函数
@CName("SmoothCornerRender")
fun smoothCornerRender(request: String): String   // 几何参数一口进,SVG 路径一出

@CName("SmoothCornerVersion")
fun smoothCornerVersion(): String = "1.0.4-ohos.1"  // 版本握手
C ABI 符号ArkTS 方法覆盖内核
SmoothCornerRendersmoothCornerRender(req)SmoothCornerGeometry.cubics + RTL/percent 语义对齐 + svgPath
SmoothCornerVersionsmoothCornerVersion()fork 版本握手(真机版本行的数据来源)

请求与响应:

请求 : {"width":300,"height":300,"topStart":50,"topEnd":50,"bottomEnd":50,
        "bottomStart":50,"smoothing":0.6,"rtl":false,"percent":false}
响应 : {"ok":true,"width":300,"height":300,"smoothing":0.6,"rtl":false,
        "cubicCount":17,"path":"M ... C ... Z"}
     | {"ok":false,"error":"..."}
4.3 C++ N-API 方法分发
napi_property_descriptor desc[] = {
    {"smoothCornerRender", nullptr, NapiSmoothCornerRender, nullptr, nullptr, nullptr,
     static_cast<napi_property_attributes>(napi_default | napi_enumerable), nullptr},
    {"smoothCornerVersion", nullptr, NapiSmoothCornerVersion, nullptr, nullptr, nullptr,
     static_cast<napi_property_attributes>(napi_default | napi_enumerable), nullptr},
};

每个回调统一三步:napi_typeof 校验必须是 string、OH_LOG_INFO 打字节数、调 KN 函数并包装返回。KN 返回的字符串必须经 libohossmoothcorner_symbols()->DisposeString 归还 Kotlin 运行时,绝不 free()。libohossmoothcorner_api.h 按社区已审仓库同款手写(只声明 ExportedSymbols 结构与两个业务符号),不拖整份生成头。

4.4 CMake 和类型声明
add_library(ohossmoothcorner SHARED IMPORTED)
set_target_properties(ohossmoothcorner PROPERTIES
  IMPORTED_LOCATION ${KN_SO}
  IMPORTED_NO_SONAME TRUE)

add_library(smoothcorner_napi SHARED napi_init.cpp)
target_link_libraries(smoothcorner_napi PUBLIC
  libace_napi.z.so
  libhilog_ndk.z.so
  ohossmoothcorner)

OHOS_ARCH 为空或 libohossmoothcorner.so 缺失直接 FATAL_ERROR(提示先跑 link 任务);$ORIGIN rpath 加 POST_BUILD 拷贝保证 NAPI so、KN so、libc++ 三件套同目录,dlopen 时互相可见。KN 侧 .so 由 linkDebugShared* 任务经 copyKnSo* 自动拷入 entry/libs/<abi>/,构建链路无手工步骤。

export const smoothCornerRender: (request: string) => string;
export const smoothCornerVersion: () => string;

第 5 阶段:ArkUI 宿主

5.1 版本握手和实时重绘
aboutToAppear(): void {
  try { this.version = smoothCornerVersion(); } catch (e) { this.version = '版本握手失败'; }
  this.render();   // 默认参数 300×300 / r=50 / smoothing=0.6 首绘
}

private render(): void {
  const raw: string = smoothCornerRender(this.buildRequest(this.smoothing));
  const res = JSON.parse(raw) as RenderResponse;
  if (res.ok && res.path !== undefined) {
    this.pathStr = res.path;
    this.info = `${res.cubicCount} 段三次贝塞尔 · ${res.width}×${res.height} · smoothing=${res.smoothing}...`;
  } else {
    this.info = `错误: ${res.error ?? 'unknown'}`;   // ok:false 通道,ArkTS 侧永不崩
  }
}

所有滑杆 / 开关的 onChange 直接调 render()——桥是同步 C 调用,单次几何计算在微秒量级,无需异步调度,拖动即所见即所得。

5.2 页面交互

形状预览 Tab 自上而下:预览 Stack(平滑轮廓 + 红色对照轮廓叠加)、状态行、宽高 / smoothing 滑杆、四角联动开关(联动时一根"圆角半径"滑杆,独立时四根方向角滑杆)、RTL / 百分比 / 填充描边 / 对照轮廓四个开关、五套色板与重置按钮。关于 Tab 展示版本握手行、库简介、ArkTS → NAPI → C ABI → 几何内核 → SVG path → Path().commands() 分层说明、桥接协议、验收要点与仓库 / 社区链接。

红色对照轮廓是本 Demo 的关键设计:同一参数但 smoothing=0 的路径以红描边叠在填充轮廓之下,平滑角与经典圆角在"直线与圆弧相切处"的差异被直接可视化,不需要任何口头解释。

5.3 对比度和错误边界

深色前景配浅色背景、五套色板覆盖深浅两用;ok:false 时错误原文进状态行;Native 调用本身抛错(理论不该发生)同样被 try/catch 收进状态行。半径拉到超过半边时内核自动钳制,预览不越界、不崩。

第 6 阶段:示例与验证

6.1 工程结构
example/
├── nativeApp/
│   ├── build.gradle.kts                      双 ABI sharedLib(baseName=ohossmoothcorner)+ cxxShared + copyKnSo*
│   └── src/ohosMain/kotlin/org/terminator/ohos/smoothcorner/
│       └── Bridge.kt                         @CName × 2 + MiniJson(扁平 JSON,继承自 cmp_qrose 审核模式)
└── harmonyApp/
    ├── build-profile.json5                   signingConfigs 留空(签名由 DevEco 自动生成回填)
    ├── AppScope/app.json5                    bundleName org.terminator.ohos.smoothcorner、versionName 1.0.4-ohos.1
    └── entry/
        ├── build-profile.json5               externalNativeOptions + abiFilters [arm64-v8a, x86_64]
        ├── libs/{arm64-v8a,x86_64}/          linkDebugShared* 经 copyKnSo* 回填的三件套(gitignore)
        ├── src/main/cpp/CMakeLists.txt       IMPORTED 引入 KN so、$ORIGIN rpath
        ├── src/main/cpp/napi_init.cpp        N-API 导出、参数检查、DisposeString
        ├── src/main/cpp/include/libohossmoothcorner_api.h
        ├── src/main/cpp/types/libsmoothcorner_napi/{index.d.ts, oh-package.json5}
        └── src/main/ets/pages/Index.ets      ArkUI 双页签验收页面
6.2 构建、签名和安装
./gradlew :smooth-rounded-corner-shape:jvmTest    # 21 项对拍(真实 graphics-shapes 1.0.1)
./gradlew :example:nativeApp:linkDebugSharedOhosArm64 :example:nativeApp:linkDebugSharedOhosX64

cd example/harmonyApp
hvigorw assembleHap -p product=default -p buildMode=debug --no-daemon

签名在 DevEco Studio 的 File → Project Structure → Signing Configs 中勾选自动生成,证书写入本机 ~/.ohos/config,不进入仓库(仓库内 build-profile.json5 的 signingConfigs 保持空数组,勾选自动签名后由 IDE 回填完整配置)。

hdc list targets -v
hdc -t <设备序列号> install -r \
  entry/build/default/outputs/default/entry-default-signed.hap
hdc -t <设备序列号> shell aa start \
  -a EntryAbility -b org.terminator.ohos.smoothcorner -m entry

四、完整代码对照

4.1 整体架构

androidx.graphics.shapes 1.0.1(上游依赖的数学,无 ohos 制品)
    │ 逐表达式移植
geoshape/GraphicsShapesPort.kt(全 internal:RoundedPolygon / RoundedCorner / Cubic / Pt / Feature)
    │
geoshape/SmoothCornerGeometry.kt(公共入口:cubics / percentRadius / svgPath + ShapeCubic)
    │
Bridge.kt + MiniJson
    │ SmoothCornerRender / SmoothCornerVersion
libsmoothcorner_napi.so
    │ smoothCornerRender / smoothCornerVersion
Index.ets
    │ JSON parse + @State 更新
    ▼
ArkUI 真机页面(Path().commands() 双页签)

smooth-rounded-corner-shape/src/composeMain/**(上游 Compose API 原文,不编译,等 ohos 制品接回)

4.2 文件清单

文件职责
settings.gradle.kts极简 ohos 构建、eazytec Maven 置前、ohos_smooth_corner_shape
gradle/libs.versions.tomlKotlin 2.2.21-1.0.0 钉版 + 对拍专用 graphics-shapes 1.0.1 / collection
build.gradle.kts(根)版本 1.0.4-ohos.1、全局禁用 Ohos*Test* 任务
smooth-rounded-corner-shape/build.gradle.kts纯 KMP:jvm + ohosArm64 + ohosX64,composeMain 不注册的说明
.../geoshape/GraphicsShapesPort.ktgraphics-shapes 1.0.1 逐表达式移植(全 internal,Apache-2.0 头)
.../geoshape/SmoothCornerGeometry.kt公共入口:cubics / percentRadius / svgPath + ShapeCubic
.../src/composeMain/**上游 Compose API 原文 + 隔离说明(git 100% rename)
.../jvmTest/...SmoothCornerGeometryParityTest.kt21 项对拍用例
example/nativeApp/build.gradle.kts双 ABI sharedLib、cxxShared 定位 libc++、copyKnSo* 回填
nativeApp/.../Bridge.kt2 个 C ABI、RTL/percent 对齐、MiniJson、错误通道
harmonyApp/.../cpp/napi_init.cppN-API 导出、参数检查、DisposeString
harmonyApp/.../cpp/CMakeLists.txtIMPORTED 引入 KN so、$ORIGIN rpath、POST_BUILD 三件套
harmonyApp/.../ets/pages/Index.etsArkUI 双页签验收页面
README.OpenHarmony_CN.md鸿蒙适配主文档(16 节)

4.3 关键 API 对照

层次API作用
内核SmoothCornerGeometry.cubics(w, h, 四角, smoothing)闭合轮廓的 cubic 列表(绝对坐标 [0,w]×[0,h])
内核SmoothCornerGeometry.percentRadius(w, h, percent)min(w,h)·percent/100,对齐 CornerSize(percent)
内核SmoothCornerGeometry.svgPath(cubics)M ... C ... Z 绝对路径,3 位小数
内核RoundedPolygon(vertices, perVertexRounding)移植的 graphics-shapes 1.0.1 构造管线
NativeSmoothCornerRender / SmoothCornerVersionC ABI JSON 导出
N-APIsmoothCornerRender(req) / smoothCornerVersion()向 ArkTS 暴露能力
ArkTSPath().commands(pathStr)矢量渲染验收

4.4 ArkTS 与 Kotlin 的边界

const res = JSON.parse(smoothCornerRender(JSON.stringify({
  width: 300, height: 300,
  topStart: 50, topEnd: 50, bottomEnd: 50, bottomStart: 50,
  smoothing: 0.6, rtl: false, percent: false
})));
// res.ok === true;res.path 形如 "M0 50 C ... Z",res.cubicCount === 17
// SmoothRoundedCornerShape.createOutline 的 LayoutDirection 映射,在桥内复刻
val topLeft = if (!rtl) topStart else topEnd
val topRight = if (!rtl) topEnd else topStart
val bottomLeft = if (!rtl) bottomStart else bottomEnd
val bottomRight = if (!rtl) bottomEnd else bottomStart
val cubics = SmoothCornerGeometry.cubics(width, height, topLeft, topRight, bottomRight, bottomLeft, smoothing)

两者之间只传输扁平 JSON 字符串与 SVG 路径文本,不传输 Kotlin 对象或未校验的动态结构。

五、关键决策说明

决策 1:移植内核而不是等制品、也不是 ArkTS 重写

graphics-shapes 没有 ohos 制品,"等"没有时间表;ArkTS 重写则把圆角切割、侧翼曲线、圆弧近似的每个浮点常量重新发明一遍,等于换一套需要重新证明的实现。移植是唯一同时满足"零漂移风险下界可控"与"当下可交付"的路线——而且移植面可以收窄到上游实际调用的那条管线,Morph / bounds / 变换等用不到的代码一个字节都不搬。

决策 2:对拍基准钉上游声明的 1.0.1,不升 1.1.0

对拍的意义是"鸿蒙 .so 里的几何 = 上游渲染的几何",基准必须与上游 build.gradle.kts 里声明的 graphics-shapes:1.0.1 完全一致。1.1.0 与 1.0.1 的行为差异属上游升级范畴,应随上游 bump 一起做;鸿蒙 fork 单方面"超前"会让对拍失去基准资格。

决策 3:根构建替换(cmp_qrose 模式)+ composeMain 隔离

上游根构建(AGP / Compose 1.6.11 / vanniktech 发布 / signing)对鸿蒙没有保留价值,且 AGP 与鸿蒙 Kotlin 插件无法共存,整个替换为极简 ohos 构建。上游 Compose 面是库的公共 API,不能删——原文移入 src/composeMain 不注册源码集,配 README 写明接回条件(compose.ui / graphics-shapes 出 ohos 变体),git 100% rename 可审计。

决策 4:RTL / 百分比语义放桥侧,内核只做纯几何

CornerBasedShape 的 start/end 语义与 CornerSize(percent) 的解析规则属于 Compose 层。语义集中在桥接层,将来 Compose 面接回时,内核与 21 项对拍都零改动。

决策 5:交付 SVG path 而不是 PNG

qrose 的条码输出位图可行;圆角轮廓是矢量语义,转 PNG 是有损降级。ArkUI Path().commands() 直接吃 SVG 命令串,矢量无损、分辨率无关,没有理由多绕一层像素。

决策 6:手写 MiniJson,不上 kotlinx.serialization

桥协议只有扁平数字与布尔,60 行手写解析器足够;KN 侧少一个序列化依赖,.so 少几百 KB,也避免为鸿蒙线找 serialization ohos 制品的额外验证面。

六、测试与验证

6.1 测试环境

本次验证使用 Windows(x86_64)、JDK 21(Temurin,org.gradle.java.home 钉版)、DevEco Studio 5.1.0 Release(含 hvigor / ohpm / hdc 命令行工具)与鸿蒙真机(arm64)。

6.2 JVM 对拍(内核没漂的唯一可信证明)

./gradlew :smooth-rounded-corner-shape:jvmTest

21 项用例全部通过。同一个构造器分别喂给真实的 androidx.graphics:graphics-shapes:1.0.1(google() 仓)与移植内核,逐 float 对比(容差 1e-4——即 graphics-shapes 自身的 DistanceEpsilon):

组用例覆盖点
平滑档位 ×4smoothing 0 / 0.3 / 0.6 / 10=纯圆弧,1=双翼相接,0.6=Figma 60% 档
圆角形态 ×4README 示例 10/5/0/20、锐圆混排、全锐角、全锐角+平滑每角独立、零半径走直线分支
钳制路径 ×3单角超半边、同边两角相争、超大+最大平滑cutAdjusts 三级分配的两个不足分支
极端参数 ×32×2 退化尺寸、半径=半短边、1080×480 卡片阈值边界与大坐标
语义收敛 ×7smoothing>1 收敛、闭合性、越界、percentRadius ×2、SVG 形状、全锐角段数=4公共入口的契约

段数事实(对拍确认,Demo「关于」页文案与之对应):全直角 = 4 段;四角圆角(smoothing=0)= 9 段;四角全平滑 = 17 段——12 段角部曲线 + 4 段直边,再因首角圆弧对半拆分闭合多 1 段。这条事实链还纠正过一次直觉错误(开发时曾按 16 段写断言,对拍立刻打回):只要 21 个用例保持绿色,鸿蒙 .so 里的几何就是上游渲染的几何。

6.3 HAP 验证

:smooth-rounded-corner-shape:compileKotlinOhosArm64 / OhosX64: BUILD SUCCESSFUL
linkDebugSharedOhosArm64 / linkDebugSharedOhosX64: BUILD SUCCESSFUL(copyKnSo* 自动回填三件套)
llvm-nm: SmoothCornerRender / SmoothCornerVersion 均为全局 T 符号
BuildNativeWithNinja: finished(双 ABI 编出 libsmoothcorner_napi.so)
CompileArkTS: finished
PackageHap: finished
BUILD SUCCESSFUL
install bundle successfully
start ability successfully

entry-default-unsigned.hap 约 6.8 MB,内含双 ABI 各三件套(libsmoothcorner_napi.so ≈65KB / libohossmoothcorner.so / libc++_shared.so);HAP 内 strip 后 KN so arm64 ≈1.9MB、x86_64 ≈1.9MB(debugShared 未 strip 时分别约 3.7MB / 3.4MB,含 Kotlin/Native 运行时)。

6.4 功能用例

  1. 启动后标题下出现 Kotlin/Native 内核 · 1.0.4-ohos.1(来自真实 Native 调用,非静态文字);
  2. 默认参数 300×300 / r=50 / smoothing=0.6 首绘,四角为超椭圆过渡,红色对照(smoothing=0)可见经典圆角与平滑角的切点差异;
  3. 拖动 smoothing 滑杆 0→1,轮廓从纯圆角连续过渡到双翼相接,每次 onChange 实时重绘;
  4. 关闭四角联动,四个方向角独立滑杆分别生效;开 RTL,圆角位置左右镜像;
  5. 开百分比圆角,50% 与联动模式 min(宽,高)/2 绝对值视觉一致;
  6. 半径滑杆拉满,轮廓自动钳制不越界、应用不崩;
  7. 切换五套色板与填充/描边,渲染语义不变;
  8. 「关于」页版本握手、调用链、协议与验收要点完整展示。

6.5 验证结论

几何内核、交叉编译工具链、Native 动态库、C ABI、N-API、ArkUI 页面和 HAP 已完成链路验证。应用在鸿蒙真机上成功安装并进入前台,页面展示了真实的几何会话:版本握手、平滑角渲染、对照轮廓与参数实时重绘(见下节效果图)。

七、运行效果

7.1 真机截图

在这里插入图片描述

7.2 命令速查

git clone https://atomgit.com/oh-tpc/smooth-rounded-corner-shape.git
cd smooth-rounded-corner-shape
# Windows: gradle.properties 已写 org.gradle.java.home(JDK 21),命令行另需 JDK bin 进 PATH
./gradlew :smooth-rounded-corner-shape:jvmTest    # 21 项对拍
./gradlew :smooth-rounded-corner-shape:compileKotlinOhosArm64 :smooth-rounded-corner-shape:compileKotlinOhosX64
./gradlew :example:nativeApp:linkDebugSharedOhosArm64 :example:nativeApp:linkDebugSharedOhosX64
cd example/harmonyApp
hvigorw assembleHap -p product=default -p buildMode=debug --no-daemon
hdc install -r entry/build/default/outputs/default/entry-default-signed.hap
hdc shell aa start -a EntryAbility -b org.terminator.ohos.smoothcorner -m entry
hdc shell hilog | grep SmoothCorner

八、遗留问题与改进方向

8.1 踩坑复盘

  1. 只改 ArkTS 页面不算 KMP 适配,必须让内核真正编译成 ohosArm64 / ohosX64 动态库,并用对拍证明它算的就是上游那套数学;
  2. settings.gradle.kts 里 eazytec 双仓必须排在 pluginManagement 与 dependencyResolutionManagement 最前,否则配置期直接 Unresolved reference: ohosArm64;
  3. 上游根构建的 AGP + Compose 插件 + Kotlin 1.9.23 与鸿蒙工具链不共存,根构建必须整体替换,保留任何一行 AGP 痕迹都会在配置期冲突;
  4. graphics-shapes 内部的 Point 是 androidx.collection.FloatFloatPair 的 typealias、MutableFloatList 也是 androidx.collection 的——两个"藏得最深"的依赖都没有 ohos 变体,移植时用零依赖的 Pt / FloatArray 等价替换(只影响存储,不影响算术);
  5. 移植必须守住求值顺序纪律:浮点乘除链重排、魔数"化简"、分支顺序调整,任何一处都会让对拍在极端参数上打回——本仓的对拍用例真的抓到过一次(段数断言按直觉写成 16,实测 17:首角圆弧为精确闭合被对半拆分多出 1 段);
  6. ArkTS 不能直接 import KN so 调 @CName 业务符号(HarmonyOS Kotlin 的 CAdapter 不导出),必须走 CMake NAPI 包装层,$ORIGIN rpath 保证三件套同目录互相可见;
  7. KN 返回字符串必须 DisposeString 归还运行时,N-API 层不能 free();
  8. hvigor 命令行打包阶段 spawn java ENOENT——PackageHap 需要系统 PATH 里有 JDK,命令行构建时把 JDK bin 加进 PATH(DevEco GUI 内不受影响);
  9. MiniJson 的取值函数漏写默认参数值会在 KN 编译期报 No value passed for parameter 'default'——协议里"缺字段按 0 再走参数校验"的语义要显式落成默认值;
  10. HAP 缺当前 ABI 的 so 会报安装失败 9568347,abiFilters 必须双 ABI,每个 ABI 三件套缺一不可;
  11. entry/libs/ 里的 so 与 DevEco 生成的 .clang-tidy / .clangd 是构建产物,gitignore 必须覆盖,否则混进提交;
  12. 签名材料由 DevEco 自动写入 build-profile.json5,提交前注意不要把带 material 的签名配置推进仓库,证书绝不进入 AtomGit。

8.2 已知问题

  • ArkUI Path().commands() 的坐标单位是 px,而桥交付的几何按 vp 数值给出:真机上图形按屏幕密度比缩小、显示在组件左上角(形状本身逐位正确,对照轮廓与平滑轮廓的比例关系不受影响)。修复方向是渲染侧按 density 缩放坐标、或以 px 设置组件尺寸,内核与协议零改动;
  • 鸿蒙侧没有 Compose Shape:交付物是几何(SVG path / cubic 列表),SmoothRoundedCornerShape 不能直接塞进 ArkUI 组件的 shape 属性——那是 compose.ui / graphics-shapes 出 ohos 制品后的事;
  • 上游 Compose API 暂不编译:composeMain 里的 4+2 个文件是原文快照,接回前提是制品就绪;
  • 只覆盖矩形管线:上游公共 API 本身只有矩形 smooth corner,移植面与上游公共面严格一致,没有"顺手多移植";
  • 对拍在 JVM 不在 ohos:KN 与 JVM 共用同一份 commonMain 代码与同一套 stdlib 数学,浮点求值顺序一致;真机验收做最终确认;
  • path 坐标 3 位小数:SVG payload 体积优先;需要全精度的下游可扩展 cubics 通道;
  • android 目标剥离(上游 1.0.4 继续服务 Android/Desktop),发布、signing 一并剥离,本 fork 不发 Maven Central;
  • HAP 安装必须使用与 bundle name org.terminator.ohos.smoothcorner 匹配的签名。

8.3 未来优化方向

  • 修复 px/vp 单位对齐(渲染侧 density 缩放),让预览图形精确占满画布;
  • 开放 cubics 全精度通道(绕过 SVG 3 位小数),并按需暴露任意顶点 RoundedPolygon 桥(内核已具备,仅协议扩展);
  • 跟踪 graphics-shapes 与社区 CMP 的 ohos 制品动态,制品就绪后恢复 composeMain 源码集并回归对拍;
  • 若上游 bump graphics-shapes(1.1.x),同步移植面并扩对拍矩阵,保持"上游依赖版本 = 对拍基准版本";
  • 评估 .har 形态发布,让 ArkTS 工程直接依赖而不是走 so 三件套;
  • 在 CI 中加入 ohos 编译、ELF 符号检查和 HAP 构建;补充真机(x86_64)验收矩阵和自动化截图脚本。

九、总结

9.1 核心难点回顾

上游 smooth-rounded-corner-shape 1.0.4(公共面 = Compose Shape,数学 = graphics-shapes 1.0.1)
    → 验证制品线:graphics-shapes / compose.ui / androidx.collection 均无 ohos 变体
    → 路线定型:数学移植 + Compose 面封存(与 KStore"真编译整库"互为镜像)
    → 根构建替换(cmp_qrose 模式,Kotlin 2.2.21-1.0.0 + Gradle 8.14.1 + JDK 21)
    → graphics-shapes 1.0.1 逐表达式移植(求值顺序纪律)+ 公共入口 SmoothCornerGeometry
    → 21 项 JVM 对拍对真实 1.0.1 逐 float 验证(容差 = 库自身的 DistanceEpsilon)
    → ohosArm64 / ohosX64 KLIB + 双 ABI sharedLib + @CName × 2
    → C++ N-API(DisposeString 纪律)+ ArkTS JSON 解析
    → ArkUI Path().commands() 真机双页签验收(平滑/对照/RTL/百分比/钳制)

9.2 封装层次

  • 内核层:graphics-shapes 1.0.1 的 RoundedPolygon 管线逐表达式移植,全 internal,Apache-2.0 声明;
  • 入口层:SmoothCornerGeometry.cubics / percentRadius / svgPath,纯几何、无 Compose 语义;
  • 桥接层:RTL / 百分比语义在 Kotlin 桥内对齐 Compose,2 个 C ABI 输出 JSON + SVG path;
  • N-API 层:参数检查、字符串转换和 Native 内存释放(DisposeString);
  • ArkTS 层:页面状态、滑杆实时重绘、对照轮廓叠加、色板与错误文本;
  • 隔离层:上游 Compose API 原文在 composeMain 留档,等制品接回。

9.3 三条经验

  1. 路线选择必须基于当天的制品可达性:KStore 验证出"制品在 → 真编译整库",本库验证出"制品不在 → 逐表达式移植 + 对拍兜底",两条路线在同一社区规范下互为镜像;先查制品再定路线,不要拿着上一个库的结论套下一个库;
  2. 移植类适配的可信度来自对拍,不来自"看着像":把真实上游依赖当参照实现、逐 float 对比(容差取库自身的一致性阈值),极端参数用例(超大半径、退化尺寸)是对拍真正的价值区;段数从 16 改 17 那次打回,就是这套门槛在起作用;
  3. 语义放桥侧、数学放内核:start/end 镜像与百分比解析属于 Compose 层,集中在对齐层;内核保持纯几何,将来 Compose 面接回或语义修正,移植代码与对拍矩阵零改动。

9.4 适配成果

当前适配已完成:

  • smooth-rounded-corner-shape 1.0.4(1.0.4-ohos.1)几何内核的双 ABI Kotlin/Native 编译(graphics-shapes 1.0.1 逐表达式移植,上游 Compose 文件零修改留档);
  • 21 项 JVM 对拍全绿(对真实 androidx.graphics:graphics-shapes:1.0.1,容差 1e-4);
  • 2 个 C ABI 符号和 C++ N-API 包装层(llvm-nm 验证全局 T 符号);
  • DevEco Stage ArkUI 双页签验收页面(平滑角渲染、红色对照、smoothing / 四角 / RTL / 百分比实时重绘、版本握手);
  • HAP 构建(双 ABI 六件套 so,约 6.8MB)、签名、设备安装和真机验证;
  • AtomGit 项目文档、OpenHarmony README(中英双份)与本文效果图。

适配过程 FAQ

以下问题来自 ohosArm64 目标接入、NAPI 桥接、HAP 构建与真机验收的实际流程,按出现频率排序。

Q1:DevEco Studio Sync 失败或 ohpm 依赖下载超时,怎么处理?

  • 确认 DevEco Studio 版本与工程 build-profile.json5 的 compatibleSdkVersion 一致;
  • 在 File > Settings > Build, Execution, Deployment > Ohpm 配置可用的 ohpm 仓库镜像或代理;
  • 删除 oh_modules、oh-package-lock.json5 与 .hvigor 缓存后重新 Sync;
  • 公司网络需要代理时,同时给 ohpm 与 hvigor 配置 http.proxy。

Q2:CMake 报 Missing .../libxxx.so 或找不到 Kotlin/Native 动态库?

  • 先在 example 目录执行 ./gradlew :nativeApp:linkDebugSharedOhosArm64(模拟器用 linkDebugSharedOhosX64);
  • 确认 libxxx.so 与 libc++_shared.so 已复制到 ohos/entry/libs/<abi>/;
  • 检查 entry/build-profile.json5 的 abiFilters 与设备 ABI 是否一致(真机 arm64-v8a,模拟器 x86_64);
  • 清理 entry/.cxx 与 entry/build 后重试。

Q3:ArkTS 报 Cannot find module 'libxxx_napi.so' 或调用返回 undefined?

  • 确认 CMake 的 add_library(<target> SHARED ...) 名称与 import ... from 'libxxx_napi.so' 完全一致;
  • 解包 HAP,确认 libs/<abi>/libxxx_napi.so 已打包;
  • 删除 entry/build、entry/.cxx 与 oh_modules 后重新构建;
  • 检查 module.json5 的 srcEntry 与页面路径是否正确。

Q4:真机安装报 signature verification failed 或 install failed?

  • 在 DevEco Studio 的 Signing Configs 配置证书、Profile 与密码;
  • bundleName 必须与签名 profile 中的 bundle name 一致;
  • 设备需加入 profile 的 deviceIds,调试证书有效期需覆盖当前时间;
  • 用 hdc list targets 确认设备在线,再执行 hdc install -r xxx-signed.hap。

Q5:应用启动白屏、闪退或 NAPI 调用崩溃?

  • 用 hdc hilog | grep -i "napi\|kotlin" 查看原生日志;
  • 确认 libc++_shared.so 与 Kotlin/Native 工具链版本匹配,且 ABI 与设备一致;
  • 检查 C ABI 返回的字符串是否由 Native 侧分配、ArkTS 侧复制后是否调用 XxxFree 释放;
  • 在 DevEco 的 Native 调试配置中附加 lldb,定位空指针与越界访问。

Q6:Gradle 报 ohosArm64 目标不存在或 Kotlin/Native 编译失败?

  • 使用鸿蒙发行版 Kotlin(如 2.2.21-1.0.0),并在 settings.gradle.kts 配置 eazytec 仓库;
  • Gradle 建议 8.x、JDK 21,版本不匹配时先统一工具链;
  • 确认 kotlin { ohosArm64() } 已应用,且 local.properties 的 SDK 路径有效;
  • 清理 ~/.gradle/caches 中对应版本的 Kotlin/Native 缓存后重试。

Q7:HAP 构建报 SDK 版本不匹配或 compatibleSdkVersion 错误?

  • 对齐 DevEco Studio、HarmonyOS SDK 与 build-profile.json5 中的 compatibleSdkVersion;
  • 升级 DevEco Studio 后同步升级 hvigor 与 SDK,避免 modelVersion 与 IDE 不匹配;
  • 命令行构建时设置 DEVECO_SDK_HOME 指向 DevEco 的 sdk 目录。

Q8:命令行 hvigor 构建失败,但 DevEco 里能构建?

  • 使用 DevEco 自带的 node 与 hvigor:
    "$DEVECO/Contents/tools/node/bin/node" "$DEVECO/Contents/tools/hvigor/bin/hvigorw.js" ...;
  • 设置 JAVA_HOME、NODE_HOME、DEVECO_SDK_HOME;
  • 加上 --no-daemon 排除守护进程缓存影响,并清理 entry/build 与 .hvigor。

参考文档

Logo

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

更多推荐