Commit 02bc9d98 authored by dsq's avatar dsq

OH.0.1.0

parent f68bb21a
......@@ -72,17 +72,25 @@ kotlin {
// 动态库 (isStatic = false) - 运行时加载的库
isStatic = true // 设置framework为静态库
}
iosTarget.compilations.getByName("main") {
compilerOptions.configure {
freeCompilerArgs.add("-Xbinary=sanitizer=address")
freeCompilerArgs.add("-Xbinary=splitBCfile=1")
}
}
}
// 配置OHOS(华为鸿蒙)arm64目标
ohosArm64 {
binaries.sharedLib {
baseName = "kn" // 共享库名称为kn
freeCompilerArgs += listOf("-Xbinary=sanitizer=address")
export(libs.compose.multiplatform.export) // 导出compose多平台库的接口
}
val main by compilations.getting // 获取主编译内容
main.compilerOptions.configure {
freeCompilerArgs.add("-Xbinary=sanitizer=address")
freeCompilerArgs.add("-Xbinary=splitBCfile=1")
}
val resource by main.cinterops.creating {
//配置C interop(cinterop)资源
defFile(file("src/ohosArm64Main/cinterop/resource.def")) // cinterop定义文件
......@@ -95,7 +103,6 @@ kotlin {
sourceSets {
androidMain.dependencies {
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.collection)
implementation(libs.androidx.lifecycle.viewmodelCompose)
implementation(libs.androidx.lifecycle.runtimeCompose)
}
......@@ -106,39 +113,19 @@ kotlin {
implementation(compose.ui) // 添加compose ui依赖
implementation(compose.components.resources) // 添加compose组件资源依赖
implementation(compose.components.uiToolingPreview) // 添加compose ui工具预览依赖
// 嵌套页面库依赖
implementation(libs.kotlinx.coroutines.core) // 官方协程核心库
implementation(libs.atomicFu)
implementation(project(":nestedlib1"))
implementation(project(":nestedlib2"))
implementation(project(":nestedlib3"))
implementation(project(":nestedlib4"))
implementation(project(":nestedlib5"))
implementation(libs.kotlinx.coroutines.core) // 官方协程核心库
implementation(libs.atomicFu) // Kotlin AtomicFu原子库
implementation(project(":nestedlib5"))// Kotlin AtomicFu原子库
}
val ohosArm64Main by getting {
dependencies {
api(libs.compose.multiplatform.export) // 导出compose多平台接口给依赖消费者
}
kotlin.srcDir("src/commonMain/kotlin/testHap")
}
// 为不同平台配置源集
val androidMain by getting
val iosMain by creating {
dependsOn(commonMain.get())
}
val iosX64Main by getting {
dependsOn(iosMain)
}
val iosArm64Main by getting {
dependsOn(iosMain)
}
val iosSimulatorArm64Main by getting {
dependsOn(iosMain)
}
val desktopMain by creating {
dependsOn(commonMain.get())
}
}
}
......@@ -154,11 +141,11 @@ Android 构建工具 → 打包成 APK
控制 APK 生成、打包、签名等
*/
android {
namespace = "com.dong.myapplication" // 设置包名
namespace = "com.dong.n4.n4test010" // 设置包名
compileSdk = libs.versions.android.compileSdk.get().toInt() // 指定编译SDK版本
defaultConfig {
applicationId = "com.dong.myapplication" // 应用ID
applicationId = "com.dong.n4.n4test010" // 应用ID
minSdk = libs.versions.android.minSdk.get().toInt() // 最低SDK版本
targetSdk = libs.versions.android.targetSdk.get().toInt()// 目标SDK版本
versionCode = 1 // 应用版本号
......@@ -184,47 +171,28 @@ dependencies {
debugImplementation(libs.compose.ui.tooling) // debug模式下依赖compose调试工具
}
compose{
ohos{
skia("0.9.22.2-ez-001")
// ohrender(" 0.9.22.2-ohrende")
}
}
// 为 ohosArm64 目标配置依赖处理
val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
val cmpVersion = versionCatalog.findVersion("composeMultiplatform")
.orElseThrow { IllegalStateException("Missing version composeMultiplatform in version catalog") }
.requiredVersion
val skikoOverrideByCmpVersion = mapOf(
"1.9.2-ez-001" to "0.9.22.2-ez-001",
// 仅在需要强制的 CMP 版本这里新增
)
val skikoOhosOverride = skikoOverrideByCmpVersion[cmpVersion]
configurations.all {
val configName = name
if (configName.contains("ohos", ignoreCase = true)) {
incoming.afterResolve {
val resolvedSkiko = resolutionResult.allComponents
.mapNotNull { it.moduleVersion }
.firstOrNull { it.group == "org.jetbrains.skiko" && it.name == "skiko" }
logger.lifecycle(
"Resolved skiko for $configName: " +
(resolvedSkiko?.let { "${it.group}:${it.name}:${it.version}" } ?: "not found")
)
}
// exclude(group = "org.jetbrains.androidx.lifecycle")
// exclude(group = "org.jetbrains.androidx.savedstate")
}
resolutionStrategy {
eachDependency {
// 如果是 skiko 依赖,检查配置名称是否包含 ohos
if (requested.group == "org.jetbrains.skiko" && requested.name == "skiko") {
if (configName.contains("ohos", ignoreCase = true)) {
skikoOhosOverride?.let { useVersion(it) }
}
// TODO: 强制刷新 compose ui ohosarm64 依赖
force("org.jetbrains.compose.export:export-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.ui:ui-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.ui:ui-arkui-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.foundation:foundation-ohosarm64:${cmpVersion}")
}
// 强制指定 androidx.collection 版本,避免冲突
if (requested.group == "androidx.collection" && requested.name == "collection") {
useVersion(libs.versions.androidx.collection.get())
}
}
}
exclude(group = "androidx.collection", module = "collection-jvm")
}
// Harmony App 输出目录(支持命令行 --harmonyAppPath)
......@@ -258,38 +226,3 @@ arrayOf("debug", "release").forEach { type ->
}
}
}
// 在现有 100MB+ 项目上继续加码
tasks.register("makeIt300MB") {
doLast {
// 生成 10 万行 @Composable
repeat(1000) { fileIndex ->
val hapDir = File("src/commonMain/kotlin/com/dong/maxhap/demos/hap")
hapDir.mkdirs()
File(hapDir, "Huge$fileIndex.kt").writeText("""
@Composable
fun HugeFunction$fileIndex() {
${(1..100).joinToString("\n") {
"Text(\"$it\", Modifier.padding($it.dp).background(Color($it)))"
}}
}
""".trimIndent())
}
// 生成 5000 个 @Stable 数据类
repeat(5000) { classIndex ->
File("src/commonMain/kotlin/com/dong/maxhap/demos/hap/Stable$classIndex.kt").writeText("""
@Stable
data class StableData$classIndex(
val field1: String,
val field2: Int,
val field3: Boolean,
val field4: List<String>,
val field5: Map<Int, String>
)
""".trimIndent())
}
}
}
\ No newline at end of file
......@@ -11,11 +11,10 @@ androidx-espresso = "3.7.0"
androidx-lifecycle = "2.9.6"
androidx-material = "1.12.0"
androidx-testExt = "1.3.0"
androidx-collection = "1.4.5"
compose = "1.9.4"
composeMultiplatform = "1.9.2-ez-001"
composeMultiplatform = "1.9.2-OH.0.1.0-01"
junit = "4.13.2"
kotlin = "2.2.21-ez-001"
kotlin = "2.2.21-OH.0.1.0-01"
kotlinx-coroutines = "1.8.0-KBA-001"
atomicFu = "0.23.2-KBA-001"
......@@ -30,7 +29,6 @@ androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "a
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity" }
androidx-lifecycle-viewmodelCompose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" }
androidx-lifecycle-runtimeCompose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose", version.ref = "androidx-lifecycle" }
androidx-collection = { module = "androidx.collection:collection", version.ref = "androidx-collection" }
compose-multiplatform-export = { module = "org.jetbrains.compose.export:export", version.ref = "composeMultiplatform" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout" }
androidx-material = { group = "com.google.android.material", name = "material", version.ref = "androidx-material" }
......
/**
能导入的包
1. 来源插件
在 当前的 build.gradle.kts 定义可以搭配的插件
plugins {
kotlin("multiplatform")
id("com.android.library")
id("org.jetbrains.compose")
id("org.jetbrains.kotlin.plugin.compose")
alias(libs.plugins.androidApplication) // 提供 android.* 相关类
alias(libs.plugins.kotlinMultiplatform) // 提供 org.jetbrains.kotlin.gradle.* 相关类
alias(libs.plugins.composeMultiplatform) // 提供 compose 相关类
}
插件的版本在 libs.versions.toml 中定义:
2.Gradle 核心类
Gradle 本身提供的核心类(如 Copy、JavaVersion 等)自动可用,无需额外配置
*/
// 导入大写工具(capitalizeUS),用于字符串首字母大写
import android.databinding.tool.ext.capitalizeUS
// 导入ExperimentalKotlinGradlePluginApi注解,用于开启Kotlin插件实验特性
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
// 导入JvmTarget,用于指定JVM的目标版本
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
android {
namespace = "com.dong.maxhap.nestedlib1"
compileSdk = 34
defaultConfig {
minSdk = 24
}
plugins {
// 应用Kotlin多平台插件
alias(libs.plugins.kotlinMultiplatform)
// 应用Android应用插件
alias(libs.plugins.androidApplication)
// 应用Compose多平台插件
alias(libs.plugins.composeMultiplatform)
// 应用Compose编译器插件
alias(libs.plugins.composeCompiler)
}
/**
Kotlin Multiplatform 配置
插件 libs.plugins.kotlinMultiplatform
负责 Kotlin 代码编译
Android: Kotlin/JVM → .class 文件 │
iOS: Kotlin/Native → LLVM IR │
OHOS: Kotlin/Native → LLVM IR
kotlin {
androidTarget()
iosX64()
iosArm64()
iosSimulatorArm64()
ohosArm64()
├── 目标平台 (androidTarget, jvm, iosX64, etc.)
│ ├── compilerOptions
│ └── binaries
├── cocoapods (iOS 特定)
├── sourceSets
│ ├── commonMain/commonTest
│ ├── platformMain/platformTest
│ └── customSourceSets
└── 其他配置
}
*/
kotlin {
// 配置Android目标
androidTarget {
@OptIn(ExperimentalKotlinGradlePluginApi::class) // 允许使用实验API
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11) // 设置JVM target为11
}
}
// 配置iOS三种架构目标
// 编译配置: Kotlin 源码 → LLVM IR -> 机器码
listOf(
iosX64(), // iOS 模拟器(x64架构)
iosArm64(), // iOS 真机(arm64架构)
iosSimulatorArm64() // iOS 模拟器(arm64架构)
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "ComposeApp" // 设置framework名称
// 静态库 (isStatic = true) - 代码直接嵌入到最终应用中
// 动态库 (isStatic = false) - 运行时加载的库
isStatic = true // 设置framework为静态库
}
iosTarget.compilations.getByName("main") {
compilerOptions.configure {
freeCompilerArgs.add("-Xbinary=sanitizer=address")
freeCompilerArgs.add("-Xbinary=splitBCfile=1")
}
}
}
// 配置OHOS(华为鸿蒙)arm64目标
ohosArm64 {
binaries.sharedLib {
baseName = "kn" // 共享库名称为kn
export(libs.compose.multiplatform.export) // 导出compose多平台库的接口
}
val main by compilations.getting // 获取主编译内容
main.compilerOptions.configure {
freeCompilerArgs.add("-Xbinary=sanitizer=address")
freeCompilerArgs.add("-Xbinary=splitBCfile=1")
}
}
// 配置各平台的依赖关系
sourceSets {
val commonMain by getting {
dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation(compose.ui)
// 跨库依赖
androidMain.dependencies {
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.lifecycle.viewmodelCompose)
implementation(libs.androidx.lifecycle.runtimeCompose)
}
commonMain.dependencies {
implementation(compose.runtime) // 添加compose runtime依赖
implementation(compose.foundation) // 添加compose基础依赖
implementation(compose.material) // 添加compose material依赖
implementation(compose.ui) // 添加compose ui依赖
implementation(compose.components.resources) // 添加compose组件资源依赖
implementation(compose.components.uiToolingPreview) // 添加compose ui工具预览依赖
implementation(libs.kotlinx.coroutines.core) // 官方协程核心库
implementation(libs.atomicFu)
implementation(project(":nestedlib2"))
}
val ohosArm64Main by getting {
dependencies {
api(libs.compose.multiplatform.export) // 导出compose多平台接口给依赖消费者
}
}
}
}
val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
val cmpVersion = versionCatalog.findVersion("composeMultiplatform")
.orElseThrow { IllegalStateException("Missing version composeMultiplatform in version catalog") }
.requiredVersion
val skikoOverrideByCmpVersion = mapOf(
"1.9.2-ez-001" to "0.9.22.2-ez-001",
)
val skikoOhosOverride = skikoOverrideByCmpVersion[cmpVersion]
/**
应用 AGP : Android Gradle Plugin
Android 应用构建 : .class → DEX(Dalvik 字节码) → APK │
由 androidApplication 插件提供
将 .class 文件转换为 DEX(Dalvik 字节码) 文件
Android 构建工具 → 打包成 APK
作用:
配置 Android 应用 的构建行为
控制 APK 生成、打包、签名等
*/
android {
namespace = "com.dong.n4.n4test010" // 设置包名
compileSdk = libs.versions.android.compileSdk.get().toInt() // 指定编译SDK版本
configurations.all {
val configName = name
if (configName.contains("ohos", ignoreCase = true)) {
incoming.afterResolve {
val resolvedSkiko = resolutionResult.allComponents
.mapNotNull { it.moduleVersion }
.firstOrNull { it.group == "org.jetbrains.skiko" && it.name == "skiko" }
logger.lifecycle(
"Resolved skiko for $configName: " +
(resolvedSkiko?.let { "${it.group}:${it.name}:${it.version}" } ?: "not found")
)
defaultConfig {
applicationId = "com.dong.n4.n4test010" // 应用ID
minSdk = libs.versions.android.minSdk.get().toInt() // 最低SDK版本
targetSdk = libs.versions.android.targetSdk.get().toInt()// 目标SDK版本
versionCode = 1 // 应用版本号
versionName = "1.0" // 应用版本名
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"// 排除打包时的冗余license资源文件
}
resolutionStrategy {
eachDependency {
if (requested.group == "org.jetbrains.skiko" && requested.name == "skiko") {
if (configName.contains("ohos", ignoreCase = true)) {
skikoOhosOverride?.let { useVersion(it) }
}
buildTypes {
getByName("release") {
isMinifyEnabled = false // 发布包不混淆代码
}
if (requested.group == "androidx.collection" && requested.name == "collection") {
useVersion(libs.versions.androidx.collection.get())
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11 // 源码兼容Java 11
targetCompatibility = JavaVersion.VERSION_11 // 输出兼容Java 11
}
}
dependencies {
debugImplementation(libs.compose.ui.tooling) // debug模式下依赖compose调试工具
}
compose{
ohos{
skia("0.9.22.2-ez-001")
// ohrender(" 0.9.22.2-ohrende")
}
}
// 为 ohosArm64 目标配置依赖处理
val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
val cmpVersion = versionCatalog.findVersion("composeMultiplatform")
.orElseThrow { IllegalStateException("Missing version composeMultiplatform in version catalog") }
.requiredVersion
configurations.all {
resolutionStrategy {
// TODO: 强制刷新 compose ui ohosarm64 依赖
force("org.jetbrains.compose.export:export-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.ui:ui-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.ui:ui-arkui-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.foundation:foundation-ohosarm64:${cmpVersion}")
}
exclude(group = "androidx.collection", module = "collection-jvm")
}
/**
能导入的包
1. 来源插件
在 当前的 build.gradle.kts 定义可以搭配的插件
plugins {
kotlin("multiplatform")
id("com.android.library")
id("org.jetbrains.compose")
id("org.jetbrains.kotlin.plugin.compose")
alias(libs.plugins.androidApplication) // 提供 android.* 相关类
alias(libs.plugins.kotlinMultiplatform) // 提供 org.jetbrains.kotlin.gradle.* 相关类
alias(libs.plugins.composeMultiplatform) // 提供 compose 相关类
}
插件的版本在 libs.versions.toml 中定义:
2.Gradle 核心类
Gradle 本身提供的核心类(如 Copy、JavaVersion 等)自动可用,无需额外配置
*/
// 导入大写工具(capitalizeUS),用于字符串首字母大写
import android.databinding.tool.ext.capitalizeUS
// 导入ExperimentalKotlinGradlePluginApi注解,用于开启Kotlin插件实验特性
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
// 导入JvmTarget,用于指定JVM的目标版本
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
android {
namespace = "com.dong.maxhap.nestedlib2"
compileSdk = 34
defaultConfig {
minSdk = 24
}
plugins {
// 应用Kotlin多平台插件
alias(libs.plugins.kotlinMultiplatform)
// 应用Android应用插件
alias(libs.plugins.androidApplication)
// 应用Compose多平台插件
alias(libs.plugins.composeMultiplatform)
// 应用Compose编译器插件
alias(libs.plugins.composeCompiler)
}
/**
Kotlin Multiplatform 配置
插件 libs.plugins.kotlinMultiplatform
负责 Kotlin 代码编译
Android: Kotlin/JVM → .class 文件 │
iOS: Kotlin/Native → LLVM IR │
OHOS: Kotlin/Native → LLVM IR
kotlin {
androidTarget()
iosX64()
iosArm64()
iosSimulatorArm64()
ohosArm64()
├── 目标平台 (androidTarget, jvm, iosX64, etc.)
│ ├── compilerOptions
│ └── binaries
├── cocoapods (iOS 特定)
├── sourceSets
│ ├── commonMain/commonTest
│ ├── platformMain/platformTest
│ └── customSourceSets
└── 其他配置
}
*/
kotlin {
// 配置Android目标
androidTarget {
@OptIn(ExperimentalKotlinGradlePluginApi::class) // 允许使用实验API
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11) // 设置JVM target为11
}
}
// 配置iOS三种架构目标
// 编译配置: Kotlin 源码 → LLVM IR -> 机器码
listOf(
iosX64(), // iOS 模拟器(x64架构)
iosArm64(), // iOS 真机(arm64架构)
iosSimulatorArm64() // iOS 模拟器(arm64架构)
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "ComposeApp" // 设置framework名称
// 静态库 (isStatic = true) - 代码直接嵌入到最终应用中
// 动态库 (isStatic = false) - 运行时加载的库
isStatic = true // 设置framework为静态库
}
iosTarget.compilations.getByName("main") {
compilerOptions.configure {
freeCompilerArgs.add("-Xbinary=sanitizer=address")
freeCompilerArgs.add("-Xbinary=splitBCfile=1")
}
}
}
// 配置OHOS(华为鸿蒙)arm64目标
ohosArm64 {
binaries.sharedLib {
baseName = "kn" // 共享库名称为kn
export(libs.compose.multiplatform.export) // 导出compose多平台库的接口
}
val main by compilations.getting // 获取主编译内容
main.compilerOptions.configure {
freeCompilerArgs.add("-Xbinary=sanitizer=address")
freeCompilerArgs.add("-Xbinary=splitBCfile=1")
}
}
// 配置各平台的依赖关系
sourceSets {
val commonMain by getting {
dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation(compose.ui)
// 跨库依赖 - 指向下一个库
androidMain.dependencies {
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.lifecycle.viewmodelCompose)
implementation(libs.androidx.lifecycle.runtimeCompose)
}
commonMain.dependencies {
implementation(compose.runtime) // 添加compose runtime依赖
implementation(compose.foundation) // 添加compose基础依赖
implementation(compose.material) // 添加compose material依赖
implementation(compose.ui) // 添加compose ui依赖
implementation(compose.components.resources) // 添加compose组件资源依赖
implementation(compose.components.uiToolingPreview) // 添加compose ui工具预览依赖
implementation(libs.kotlinx.coroutines.core) // 官方协程核心库
implementation(libs.atomicFu)
implementation(project(":nestedlib3"))
}
val ohosArm64Main by getting {
dependencies {
api(libs.compose.multiplatform.export) // 导出compose多平台接口给依赖消费者
}
}
}
}
val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
val cmpVersion = versionCatalog.findVersion("composeMultiplatform")
.orElseThrow { IllegalStateException("Missing version composeMultiplatform in version catalog") }
.requiredVersion
val skikoOverrideByCmpVersion = mapOf(
"1.9.2-ez-001" to "0.9.22.2-ez-001",
)
val skikoOhosOverride = skikoOverrideByCmpVersion[cmpVersion]
/**
应用 AGP : Android Gradle Plugin
Android 应用构建 : .class → DEX(Dalvik 字节码) → APK │
由 androidApplication 插件提供
将 .class 文件转换为 DEX(Dalvik 字节码) 文件
Android 构建工具 → 打包成 APK
作用:
配置 Android 应用 的构建行为
控制 APK 生成、打包、签名等
*/
android {
namespace = "com.dong.n4.n4test010" // 设置包名
compileSdk = libs.versions.android.compileSdk.get().toInt() // 指定编译SDK版本
configurations.all {
val configName = name
if (configName.contains("ohos", ignoreCase = true)) {
incoming.afterResolve {
val resolvedSkiko = resolutionResult.allComponents
.mapNotNull { it.moduleVersion }
.firstOrNull { it.group == "org.jetbrains.skiko" && it.name == "skiko" }
logger.lifecycle(
"Resolved skiko for $configName: " +
(resolvedSkiko?.let { "${it.group}:${it.name}:${it.version}" } ?: "not found")
)
defaultConfig {
applicationId = "com.dong.n4.n4test010" // 应用ID
minSdk = libs.versions.android.minSdk.get().toInt() // 最低SDK版本
targetSdk = libs.versions.android.targetSdk.get().toInt()// 目标SDK版本
versionCode = 1 // 应用版本号
versionName = "1.0" // 应用版本名
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"// 排除打包时的冗余license资源文件
}
resolutionStrategy {
eachDependency {
if (requested.group == "org.jetbrains.skiko" && requested.name == "skiko") {
if (configName.contains("ohos", ignoreCase = true)) {
skikoOhosOverride?.let { useVersion(it) }
}
buildTypes {
getByName("release") {
isMinifyEnabled = false // 发布包不混淆代码
}
if (requested.group == "androidx.collection" && requested.name == "collection") {
useVersion(libs.versions.androidx.collection.get())
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11 // 源码兼容Java 11
targetCompatibility = JavaVersion.VERSION_11 // 输出兼容Java 11
}
}
dependencies {
debugImplementation(libs.compose.ui.tooling) // debug模式下依赖compose调试工具
}
compose{
ohos{
skia("0.9.22.2-ez-001")
// ohrender(" 0.9.22.2-ohrende")
}
}
// 为 ohosArm64 目标配置依赖处理
val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
val cmpVersion = versionCatalog.findVersion("composeMultiplatform")
.orElseThrow { IllegalStateException("Missing version composeMultiplatform in version catalog") }
.requiredVersion
configurations.all {
resolutionStrategy {
// TODO: 强制刷新 compose ui ohosarm64 依赖
force("org.jetbrains.compose.export:export-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.ui:ui-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.ui:ui-arkui-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.foundation:foundation-ohosarm64:${cmpVersion}")
}
exclude(group = "androidx.collection", module = "collection-jvm")
}
/**
能导入的包
1. 来源插件
在 当前的 build.gradle.kts 定义可以搭配的插件
plugins {
kotlin("multiplatform")
id("com.android.library")
id("org.jetbrains.compose")
id("org.jetbrains.kotlin.plugin.compose")
alias(libs.plugins.androidApplication) // 提供 android.* 相关类
alias(libs.plugins.kotlinMultiplatform) // 提供 org.jetbrains.kotlin.gradle.* 相关类
alias(libs.plugins.composeMultiplatform) // 提供 compose 相关类
}
插件的版本在 libs.versions.toml 中定义:
2.Gradle 核心类
Gradle 本身提供的核心类(如 Copy、JavaVersion 等)自动可用,无需额外配置
*/
// 导入大写工具(capitalizeUS),用于字符串首字母大写
import android.databinding.tool.ext.capitalizeUS
// 导入ExperimentalKotlinGradlePluginApi注解,用于开启Kotlin插件实验特性
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
// 导入JvmTarget,用于指定JVM的目标版本
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
android {
namespace = "com.dong.maxhap.nestedlib3"
compileSdk = 34
defaultConfig {
minSdk = 24
}
plugins {
// 应用Kotlin多平台插件
alias(libs.plugins.kotlinMultiplatform)
// 应用Android应用插件
alias(libs.plugins.androidApplication)
// 应用Compose多平台插件
alias(libs.plugins.composeMultiplatform)
// 应用Compose编译器插件
alias(libs.plugins.composeCompiler)
}
/**
Kotlin Multiplatform 配置
插件 libs.plugins.kotlinMultiplatform
负责 Kotlin 代码编译
Android: Kotlin/JVM → .class 文件 │
iOS: Kotlin/Native → LLVM IR │
OHOS: Kotlin/Native → LLVM IR
kotlin {
androidTarget()
iosX64()
iosArm64()
iosSimulatorArm64()
ohosArm64()
├── 目标平台 (androidTarget, jvm, iosX64, etc.)
│ ├── compilerOptions
│ └── binaries
├── cocoapods (iOS 特定)
├── sourceSets
│ ├── commonMain/commonTest
│ ├── platformMain/platformTest
│ └── customSourceSets
└── 其他配置
}
*/
kotlin {
// 配置Android目标
androidTarget {
@OptIn(ExperimentalKotlinGradlePluginApi::class) // 允许使用实验API
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11) // 设置JVM target为11
}
}
// 配置iOS三种架构目标
// 编译配置: Kotlin 源码 → LLVM IR -> 机器码
listOf(
iosX64(), // iOS 模拟器(x64架构)
iosArm64(), // iOS 真机(arm64架构)
iosSimulatorArm64() // iOS 模拟器(arm64架构)
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "ComposeApp" // 设置framework名称
// 静态库 (isStatic = true) - 代码直接嵌入到最终应用中
// 动态库 (isStatic = false) - 运行时加载的库
isStatic = true // 设置framework为静态库
}
iosTarget.compilations.getByName("main") {
compilerOptions.configure {
freeCompilerArgs.add("-Xbinary=sanitizer=address")
freeCompilerArgs.add("-Xbinary=splitBCfile=1")
}
}
}
// 配置OHOS(华为鸿蒙)arm64目标
ohosArm64 {
binaries.sharedLib {
baseName = "kn" // 共享库名称为kn
export(libs.compose.multiplatform.export) // 导出compose多平台库的接口
}
val main by compilations.getting // 获取主编译内容
main.compilerOptions.configure {
freeCompilerArgs.add("-Xbinary=sanitizer=address")
freeCompilerArgs.add("-Xbinary=splitBCfile=1")
}
}
// 配置各平台的依赖关系
sourceSets {
val commonMain by getting {
dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation(compose.ui)
// 跨库依赖 - 指向下一个库
androidMain.dependencies {
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.lifecycle.viewmodelCompose)
implementation(libs.androidx.lifecycle.runtimeCompose)
}
commonMain.dependencies {
implementation(compose.runtime) // 添加compose runtime依赖
implementation(compose.foundation) // 添加compose基础依赖
implementation(compose.material) // 添加compose material依赖
implementation(compose.ui) // 添加compose ui依赖
implementation(compose.components.resources) // 添加compose组件资源依赖
implementation(compose.components.uiToolingPreview) // 添加compose ui工具预览依赖
implementation(libs.kotlinx.coroutines.core) // 官方协程核心库
implementation(libs.atomicFu)
implementation(project(":nestedlib4"))
}
val ohosArm64Main by getting {
dependencies {
api(libs.compose.multiplatform.export) // 导出compose多平台接口给依赖消费者
}
}
}
}
val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
val cmpVersion = versionCatalog.findVersion("composeMultiplatform")
.orElseThrow { IllegalStateException("Missing version composeMultiplatform in version catalog") }
.requiredVersion
val skikoOverrideByCmpVersion = mapOf(
"1.9.2-ez-001" to "0.9.22.2-ez-001",
)
val skikoOhosOverride = skikoOverrideByCmpVersion[cmpVersion]
/**
应用 AGP : Android Gradle Plugin
Android 应用构建 : .class → DEX(Dalvik 字节码) → APK │
由 androidApplication 插件提供
将 .class 文件转换为 DEX(Dalvik 字节码) 文件
Android 构建工具 → 打包成 APK
作用:
配置 Android 应用 的构建行为
控制 APK 生成、打包、签名等
*/
android {
namespace = "com.dong.n4.n4test010" // 设置包名
compileSdk = libs.versions.android.compileSdk.get().toInt() // 指定编译SDK版本
configurations.all {
val configName = name
if (configName.contains("ohos", ignoreCase = true)) {
incoming.afterResolve {
val resolvedSkiko = resolutionResult.allComponents
.mapNotNull { it.moduleVersion }
.firstOrNull { it.group == "org.jetbrains.skiko" && it.name == "skiko" }
logger.lifecycle(
"Resolved skiko for $configName: " +
(resolvedSkiko?.let { "${it.group}:${it.name}:${it.version}" } ?: "not found")
)
defaultConfig {
applicationId = "com.dong.n4.n4test010" // 应用ID
minSdk = libs.versions.android.minSdk.get().toInt() // 最低SDK版本
targetSdk = libs.versions.android.targetSdk.get().toInt()// 目标SDK版本
versionCode = 1 // 应用版本号
versionName = "1.0" // 应用版本名
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"// 排除打包时的冗余license资源文件
}
resolutionStrategy {
eachDependency {
if (requested.group == "org.jetbrains.skiko" && requested.name == "skiko") {
if (configName.contains("ohos", ignoreCase = true)) {
skikoOhosOverride?.let { useVersion(it) }
}
buildTypes {
getByName("release") {
isMinifyEnabled = false // 发布包不混淆代码
}
if (requested.group == "androidx.collection" && requested.name == "collection") {
useVersion(libs.versions.androidx.collection.get())
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11 // 源码兼容Java 11
targetCompatibility = JavaVersion.VERSION_11 // 输出兼容Java 11
}
}
dependencies {
debugImplementation(libs.compose.ui.tooling) // debug模式下依赖compose调试工具
}
compose{
ohos{
skia("0.9.22.2-ez-001")
// ohrender(" 0.9.22.2-ohrende")
}
}
// 为 ohosArm64 目标配置依赖处理
val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
val cmpVersion = versionCatalog.findVersion("composeMultiplatform")
.orElseThrow { IllegalStateException("Missing version composeMultiplatform in version catalog") }
.requiredVersion
configurations.all {
resolutionStrategy {
// TODO: 强制刷新 compose ui ohosarm64 依赖
force("org.jetbrains.compose.export:export-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.ui:ui-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.ui:ui-arkui-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.foundation:foundation-ohosarm64:${cmpVersion}")
}
exclude(group = "androidx.collection", module = "collection-jvm")
}
/**
能导入的包
1. 来源插件
在 当前的 build.gradle.kts 定义可以搭配的插件
plugins {
kotlin("multiplatform")
id("com.android.library")
id("org.jetbrains.compose")
id("org.jetbrains.kotlin.plugin.compose")
alias(libs.plugins.androidApplication) // 提供 android.* 相关类
alias(libs.plugins.kotlinMultiplatform) // 提供 org.jetbrains.kotlin.gradle.* 相关类
alias(libs.plugins.composeMultiplatform) // 提供 compose 相关类
}
插件的版本在 libs.versions.toml 中定义:
2.Gradle 核心类
Gradle 本身提供的核心类(如 Copy、JavaVersion 等)自动可用,无需额外配置
*/
// 导入大写工具(capitalizeUS),用于字符串首字母大写
import android.databinding.tool.ext.capitalizeUS
// 导入ExperimentalKotlinGradlePluginApi注解,用于开启Kotlin插件实验特性
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
// 导入JvmTarget,用于指定JVM的目标版本
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
android {
namespace = "com.dong.maxhap.nestedlib4"
compileSdk = 34
defaultConfig {
minSdk = 24
}
plugins {
// 应用Kotlin多平台插件
alias(libs.plugins.kotlinMultiplatform)
// 应用Android应用插件
alias(libs.plugins.androidApplication)
// 应用Compose多平台插件
alias(libs.plugins.composeMultiplatform)
// 应用Compose编译器插件
alias(libs.plugins.composeCompiler)
}
/**
Kotlin Multiplatform 配置
插件 libs.plugins.kotlinMultiplatform
负责 Kotlin 代码编译
Android: Kotlin/JVM → .class 文件 │
iOS: Kotlin/Native → LLVM IR │
OHOS: Kotlin/Native → LLVM IR
kotlin {
androidTarget()
iosX64()
iosArm64()
iosSimulatorArm64()
ohosArm64()
├── 目标平台 (androidTarget, jvm, iosX64, etc.)
│ ├── compilerOptions
│ └── binaries
├── cocoapods (iOS 特定)
├── sourceSets
│ ├── commonMain/commonTest
│ ├── platformMain/platformTest
│ └── customSourceSets
└── 其他配置
}
*/
kotlin {
// 配置Android目标
androidTarget {
@OptIn(ExperimentalKotlinGradlePluginApi::class) // 允许使用实验API
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11) // 设置JVM target为11
}
}
// 配置iOS三种架构目标
// 编译配置: Kotlin 源码 → LLVM IR -> 机器码
listOf(
iosX64(), // iOS 模拟器(x64架构)
iosArm64(), // iOS 真机(arm64架构)
iosSimulatorArm64() // iOS 模拟器(arm64架构)
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "ComposeApp" // 设置framework名称
// 静态库 (isStatic = true) - 代码直接嵌入到最终应用中
// 动态库 (isStatic = false) - 运行时加载的库
isStatic = true // 设置framework为静态库
}
iosTarget.compilations.getByName("main") {
compilerOptions.configure {
freeCompilerArgs.add("-Xbinary=sanitizer=address")
freeCompilerArgs.add("-Xbinary=splitBCfile=1")
}
}
}
// 配置OHOS(华为鸿蒙)arm64目标
ohosArm64 {
binaries.sharedLib {
baseName = "kn" // 共享库名称为kn
export(libs.compose.multiplatform.export) // 导出compose多平台库的接口
}
val main by compilations.getting // 获取主编译内容
main.compilerOptions.configure {
freeCompilerArgs.add("-Xbinary=sanitizer=address")
freeCompilerArgs.add("-Xbinary=splitBCfile=1")
}
}
// 配置各平台的依赖关系
sourceSets {
val commonMain by getting {
dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation(compose.ui)
// 跨库依赖 - 指向下一个库
androidMain.dependencies {
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.lifecycle.viewmodelCompose)
implementation(libs.androidx.lifecycle.runtimeCompose)
}
commonMain.dependencies {
implementation(compose.runtime) // 添加compose runtime依赖
implementation(compose.foundation) // 添加compose基础依赖
implementation(compose.material) // 添加compose material依赖
implementation(compose.ui) // 添加compose ui依赖
implementation(compose.components.resources) // 添加compose组件资源依赖
implementation(compose.components.uiToolingPreview) // 添加compose ui工具预览依赖
implementation(libs.kotlinx.coroutines.core) // 官方协程核心库
implementation(libs.atomicFu)
implementation(project(":nestedlib5"))
}
val ohosArm64Main by getting {
dependencies {
api(libs.compose.multiplatform.export) // 导出compose多平台接口给依赖消费者
}
}
}
}
val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
val cmpVersion = versionCatalog.findVersion("composeMultiplatform")
.orElseThrow { IllegalStateException("Missing version composeMultiplatform in version catalog") }
.requiredVersion
val skikoOverrideByCmpVersion = mapOf(
"1.9.2-ez-001" to "0.9.22.2-ez-001",
)
val skikoOhosOverride = skikoOverrideByCmpVersion[cmpVersion]
/**
应用 AGP : Android Gradle Plugin
Android 应用构建 : .class → DEX(Dalvik 字节码) → APK │
由 androidApplication 插件提供
将 .class 文件转换为 DEX(Dalvik 字节码) 文件
Android 构建工具 → 打包成 APK
作用:
配置 Android 应用 的构建行为
控制 APK 生成、打包、签名等
*/
android {
namespace = "com.dong.n4.n4test010" // 设置包名
compileSdk = libs.versions.android.compileSdk.get().toInt() // 指定编译SDK版本
configurations.all {
val configName = name
if (configName.contains("ohos", ignoreCase = true)) {
incoming.afterResolve {
val resolvedSkiko = resolutionResult.allComponents
.mapNotNull { it.moduleVersion }
.firstOrNull { it.group == "org.jetbrains.skiko" && it.name == "skiko" }
logger.lifecycle(
"Resolved skiko for $configName: " +
(resolvedSkiko?.let { "${it.group}:${it.name}:${it.version}" } ?: "not found")
)
defaultConfig {
applicationId = "com.dong.n4.n4test010" // 应用ID
minSdk = libs.versions.android.minSdk.get().toInt() // 最低SDK版本
targetSdk = libs.versions.android.targetSdk.get().toInt()// 目标SDK版本
versionCode = 1 // 应用版本号
versionName = "1.0" // 应用版本名
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"// 排除打包时的冗余license资源文件
}
resolutionStrategy {
eachDependency {
if (requested.group == "org.jetbrains.skiko" && requested.name == "skiko") {
if (configName.contains("ohos", ignoreCase = true)) {
skikoOhosOverride?.let { useVersion(it) }
}
buildTypes {
getByName("release") {
isMinifyEnabled = false // 发布包不混淆代码
}
if (requested.group == "androidx.collection" && requested.name == "collection") {
useVersion(libs.versions.androidx.collection.get())
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11 // 源码兼容Java 11
targetCompatibility = JavaVersion.VERSION_11 // 输出兼容Java 11
}
}
dependencies {
debugImplementation(libs.compose.ui.tooling) // debug模式下依赖compose调试工具
}
compose{
ohos{
skia("0.9.22.2-ez-001")
// ohrender(" 0.9.22.2-ohrende")
}
}
// 为 ohosArm64 目标配置依赖处理
val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
val cmpVersion = versionCatalog.findVersion("composeMultiplatform")
.orElseThrow { IllegalStateException("Missing version composeMultiplatform in version catalog") }
.requiredVersion
configurations.all {
resolutionStrategy {
// TODO: 强制刷新 compose ui ohosarm64 依赖
force("org.jetbrains.compose.export:export-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.ui:ui-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.ui:ui-arkui-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.foundation:foundation-ohosarm64:${cmpVersion}")
}
exclude(group = "androidx.collection", module = "collection-jvm")
}
/**
能导入的包
1. 来源插件
在 当前的 build.gradle.kts 定义可以搭配的插件
plugins {
kotlin("multiplatform")
id("com.android.library")
id("org.jetbrains.compose")
id("org.jetbrains.kotlin.plugin.compose")
alias(libs.plugins.androidApplication) // 提供 android.* 相关类
alias(libs.plugins.kotlinMultiplatform) // 提供 org.jetbrains.kotlin.gradle.* 相关类
alias(libs.plugins.composeMultiplatform) // 提供 compose 相关类
}
插件的版本在 libs.versions.toml 中定义:
2.Gradle 核心类
Gradle 本身提供的核心类(如 Copy、JavaVersion 等)自动可用,无需额外配置
*/
// 导入大写工具(capitalizeUS),用于字符串首字母大写
import android.databinding.tool.ext.capitalizeUS
// 导入ExperimentalKotlinGradlePluginApi注解,用于开启Kotlin插件实验特性
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
// 导入JvmTarget,用于指定JVM的目标版本
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
android {
namespace = "com.dong.maxhap.nestedlib5"
compileSdk = 34
defaultConfig {
minSdk = 24
}
plugins {
// 应用Kotlin多平台插件
alias(libs.plugins.kotlinMultiplatform)
// 应用Android应用插件
alias(libs.plugins.androidApplication)
// 应用Compose多平台插件
alias(libs.plugins.composeMultiplatform)
// 应用Compose编译器插件
alias(libs.plugins.composeCompiler)
}
/**
Kotlin Multiplatform 配置
插件 libs.plugins.kotlinMultiplatform
负责 Kotlin 代码编译
Android: Kotlin/JVM → .class 文件 │
iOS: Kotlin/Native → LLVM IR │
OHOS: Kotlin/Native → LLVM IR
kotlin {
├── 目标平台 (androidTarget, jvm, iosX64, etc.)
│ ├── compilerOptions
│ └── binaries
├── cocoapods (iOS 特定)
├── sourceSets
│ ├── commonMain/commonTest
│ ├── platformMain/platformTest
│ └── customSourceSets
└── 其他配置
}
*/
kotlin {
androidTarget()
iosX64()
iosArm64()
iosSimulatorArm64()
ohosArm64()
// 配置Android目标
androidTarget {
@OptIn(ExperimentalKotlinGradlePluginApi::class) // 允许使用实验API
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11) // 设置JVM target为11
}
}
// 配置iOS三种架构目标
// 编译配置: Kotlin 源码 → LLVM IR -> 机器码
listOf(
iosX64(), // iOS 模拟器(x64架构)
iosArm64(), // iOS 真机(arm64架构)
iosSimulatorArm64() // iOS 模拟器(arm64架构)
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "ComposeApp" // 设置framework名称
// 静态库 (isStatic = true) - 代码直接嵌入到最终应用中
// 动态库 (isStatic = false) - 运行时加载的库
isStatic = true // 设置framework为静态库
}
iosTarget.compilations.getByName("main") {
compilerOptions.configure {
freeCompilerArgs.add("-Xbinary=sanitizer=address")
freeCompilerArgs.add("-Xbinary=splitBCfile=1")
}
}
}
// 配置OHOS(华为鸿蒙)arm64目标
ohosArm64 {
binaries.sharedLib {
baseName = "kn" // 共享库名称为kn
export(libs.compose.multiplatform.export) // 导出compose多平台库的接口
}
val main by compilations.getting // 获取主编译内容
main.compilerOptions.configure {
freeCompilerArgs.add("-Xbinary=sanitizer=address")
freeCompilerArgs.add("-Xbinary=splitBCfile=1")
}
}
// 配置各平台的依赖关系
sourceSets {
val commonMain by getting {
androidMain.dependencies {
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.lifecycle.viewmodelCompose)
implementation(libs.androidx.lifecycle.runtimeCompose)
}
commonMain.dependencies {
implementation(compose.runtime) // 添加compose runtime依赖
implementation(compose.foundation) // 添加compose基础依赖
implementation(compose.material) // 添加compose material依赖
implementation(compose.ui) // 添加compose ui依赖
implementation(compose.components.resources) // 添加compose组件资源依赖
implementation(compose.components.uiToolingPreview) // 添加compose ui工具预览依赖
implementation(libs.kotlinx.coroutines.core) // 官方协程核心库
implementation(libs.atomicFu)
}
val ohosArm64Main by getting {
dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation(compose.ui)
// 最后一个库,无需跨库依赖
api(libs.compose.multiplatform.export) // 导出compose多平台接口给依赖消费者
}
}
}
}
val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
val cmpVersion = versionCatalog.findVersion("composeMultiplatform")
.orElseThrow { IllegalStateException("Missing version composeMultiplatform in version catalog") }
.requiredVersion
val skikoOverrideByCmpVersion = mapOf(
"1.9.2-ez-001" to "0.9.22.2-ez-001",
)
val skikoOhosOverride = skikoOverrideByCmpVersion[cmpVersion]
/**
应用 AGP : Android Gradle Plugin
Android 应用构建 : .class → DEX(Dalvik 字节码) → APK │
由 androidApplication 插件提供
将 .class 文件转换为 DEX(Dalvik 字节码) 文件
Android 构建工具 → 打包成 APK
作用:
配置 Android 应用 的构建行为
控制 APK 生成、打包、签名等
*/
android {
namespace = "com.dong.n4.n4test010" // 设置包名
compileSdk = libs.versions.android.compileSdk.get().toInt() // 指定编译SDK版本
configurations.all {
val configName = name
if (configName.contains("ohos", ignoreCase = true)) {
incoming.afterResolve {
val resolvedSkiko = resolutionResult.allComponents
.mapNotNull { it.moduleVersion }
.firstOrNull { it.group == "org.jetbrains.skiko" && it.name == "skiko" }
logger.lifecycle(
"Resolved skiko for $configName: " +
(resolvedSkiko?.let { "${it.group}:${it.name}:${it.version}" } ?: "not found")
)
defaultConfig {
applicationId = "com.dong.n4.n4test010" // 应用ID
minSdk = libs.versions.android.minSdk.get().toInt() // 最低SDK版本
targetSdk = libs.versions.android.targetSdk.get().toInt()// 目标SDK版本
versionCode = 1 // 应用版本号
versionName = "1.0" // 应用版本名
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"// 排除打包时的冗余license资源文件
}
resolutionStrategy {
eachDependency {
if (requested.group == "org.jetbrains.skiko" && requested.name == "skiko") {
if (configName.contains("ohos", ignoreCase = true)) {
skikoOhosOverride?.let { useVersion(it) }
}
buildTypes {
getByName("release") {
isMinifyEnabled = false // 发布包不混淆代码
}
if (requested.group == "androidx.collection" && requested.name == "collection") {
useVersion(libs.versions.androidx.collection.get())
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11 // 源码兼容Java 11
targetCompatibility = JavaVersion.VERSION_11 // 输出兼容Java 11
}
}
dependencies {
debugImplementation(libs.compose.ui.tooling) // debug模式下依赖compose调试工具
}
compose{
ohos{
skia("0.9.22.2-ez-001")
// ohrender(" 0.9.22.2-ohrende")
}
}
// 为 ohosArm64 目标配置依赖处理
val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
val cmpVersion = versionCatalog.findVersion("composeMultiplatform")
.orElseThrow { IllegalStateException("Missing version composeMultiplatform in version catalog") }
.requiredVersion
configurations.all {
resolutionStrategy {
// TODO: 强制刷新 compose ui ohosarm64 依赖
force("org.jetbrains.compose.export:export-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.ui:ui-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.ui:ui-arkui-ohosarm64:${cmpVersion}")
force("org.jetbrains.compose.foundation:foundation-ohosarm64:${cmpVersion}")
}
exclude(group = "androidx.collection", module = "collection-jvm")
}
#!/bin/bash
#
# Eazytec is pleased to support the open source community by making CPF-KMP-CMP available.
# Copyright (C) 2026 Eazytec. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
set -e
# Record script start time
START_TIME=$(date +%s)
# ====================== [1. Default Configuration and Parameter Parsing] ======================
DEFAULT_PLATFORM="ohosArm64"
DEFAULT_TARGET_ID="127.0.0.1:5555"
DEFAULT_BUNDLE_NAME="com.example.harmonyapp"
DEFAULT_ABILITY_NAME="EntryAbility"
LOCAL_OHOS_PATH=""
usage() {
echo "Usage: $0 [options] [PLATFORM] [TARGET_ID]"
echo ""
echo "Parameters:"
echo " PLATFORM Build platform (default: $DEFAULT_PLATFORM)"
echo " TARGET_ID Device ID (default: $DEFAULT_TARGET_ID)"
echo ""
echo "Options:"
echo " -m MODE Build mode: debug or release (default: debug)"
echo " -b BUNDLE Set bundle name (current: $DEFAULT_BUNDLE_NAME)"
echo " -a ABILITY Set Ability name (current: $DEFAULT_ABILITY_NAME)"
echo " -d MODE Debug mode: debug or attach (default: attach)"
echo " -p PATH Set external OHOS project path (localOhosPath)"
echo " -h Show this help message"
echo ""
echo "Examples:"
echo " $0 ohosArm64 127.0.0.1:5555"
echo " $0 -m release # Release build"
echo " $0 -b com.test.app -a MainAbility"
echo " $0 -p /path/to/external/ohos/project"
exit 0
}
# Preset variables
BUNDLE_NAME=$DEFAULT_BUNDLE_NAME
ABILITY_NAME=$DEFAULT_ABILITY_NAME
BUILD_MODE="debug"
DEBUG_MODE="attach"
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
# Parse options (supports options in any position, e.g. ohosArm64 62Q0226107024702 -m release)
POSITIONALS=()
while [[ $# -gt 0 ]]; do
case $1 in
-m) BUILD_MODE="$2"; shift 2 ;;
-b) BUNDLE_NAME="$2"; shift 2 ;;
-a) ABILITY_NAME="$2"; shift 2 ;;
-d) DEBUG_MODE="$2"; shift 2 ;;
-p) LOCAL_OHOS_PATH="$2"; shift 2 ;;
-h) usage ;;
-*)
echo "Unknown option: $1"
usage
;;
*)
POSITIONALS+=("$1")
shift
;;
esac
done
PLATFORM=${POSITIONALS[0]:-$DEFAULT_PLATFORM}
TARGET_ID=${POSITIONALS[1]:-$DEFAULT_TARGET_ID}
echo -e "\033[32m▶ Run environment configuration:\033[0m"
echo " - Platform: $PLATFORM"
echo " - Device: $TARGET_ID"
echo " - Build mode: $BUILD_MODE"
echo " - Debug mode: $DEBUG_MODE"
echo " - Bundle: $BUNDLE_NAME"
echo " - Ability: $ABILITY_NAME"
if [ -n "$LOCAL_OHOS_PATH" ]; then
echo " - External OHOS path: $LOCAL_OHOS_PATH"
fi
echo "------------------------------------------------------------"
# --- Configuration ---
DEVECO_PATH="${DEVECO_PATH:-/Applications/DevEco-Studio.app}"
MIN_VERSION="6.0.0"
echo "🔍 Checking environment configuration..."
# 1. Check if DevEco exists
if [ ! -d "$DEVECO_PATH" ]; then
echo "❌ Error: DevEco Studio not found at $DEVECO_PATH."
exit 1
fi
# 2. Get version (from Info.plist CFBundleShortVersionString)
# Output example: 5.0.3.406
CURRENT_VERSION=$(defaults read "$DEVECO_PATH/Contents/Info.plist" CFBundleShortVersionString)
echo "Current DevEco version: $CURRENT_VERSION"
echo "Minimum required version: $MIN_VERSION"
CUR_MAJOR=$(echo "$CURRENT_VERSION" | cut -d. -f1)
CUR_MINOR=$(echo "$CURRENT_VERSION" | cut -d. -f2)
REQ_MAJOR=$(echo "$MIN_VERSION" | cut -d. -f1)
REQ_MINOR=$(echo "$MIN_VERSION" | cut -d. -f2)
if [ "$CUR_MAJOR" -lt "$REQ_MAJOR" ] 2>/dev/null || \
{ [ "$CUR_MAJOR" -eq "$REQ_MAJOR" ] && [ "$CUR_MINOR" -lt "$REQ_MINOR" ]; }; then
echo "-------------------------------------------------------"
echo -e "${RED}⛔️ Error: DevEco version is too low!${NC}"
echo -e "${RED}Current version: $CURRENT_VERSION${NC}"
echo -e "${RED}Minimum required: $MIN_VERSION+${NC}"
echo -e "${RED}Please upgrade DevEco Studio and run this script again.${NC}"
echo "-------------------------------------------------------"
exit 5
fi
echo "✅ DevEco version meets requirements ($CURRENT_VERSION)"
# ====================== [2. Environment Path and SDK Configuration] ======================
DEVECO_HOME="${DEVECO_HOME:-$DEVECO_PATH/Contents}"
HDC_BIN="$DEVECO_HOME/sdk/default/openharmony/toolchains/hdc"
export DEVECO_SDK_HOME="$DEVECO_HOME/sdk"
export PATH="$DEVECO_SDK_HOME:$DEVECO_HOME/jbr/Contents/Home/bin:$DEVECO_HOME/tools/node/bin:$DEVECO_HOME/tools/ohpm/bin:$DEVECO_HOME/tools/hvigor/bin:$PATH"
"$HDC_BIN" -t "$TARGET_ID" shell aa force-stop "$BUNDLE_NAME" >/dev/null 2>&1 || true
# ====================== [3. Gradle Build] ======================
echo "Working path: $(pwd)"
echo "Building OpenHarmony ARM64..."
if [ "$PLATFORM" = "ohosArm64" ]; then
# Execute Gradle build in project root
if [ "$BUILD_MODE" = "release" ]; then
if [ -n "$LOCAL_OHOS_PATH" ]; then
echo "Using external OHOS path: $LOCAL_OHOS_PATH"
./gradlew :composeApp:publishReleaseBinariesToHarmonyApp -PharmonyAppPath="$LOCAL_OHOS_PATH"
else
echo "/gradlew :composeApp:publishReleaseBinariesToHarmonyApp"
./gradlew :composeApp:publishReleaseBinariesToHarmonyApp
fi
else
if [ -n "$LOCAL_OHOS_PATH" ]; then
echo "Using external OHOS path: $LOCAL_OHOS_PATH"
./gradlew :composeApp:publishDebugBinariesToHarmonyApp -PharmonyAppPath="$LOCAL_OHOS_PATH"
else
echo "/gradlew :composeApp:publishDebugBinariesToHarmonyApp"
./gradlew :composeApp:publishDebugBinariesToHarmonyApp
fi
fi
elif [ "$PLATFORM" = "iosSimulatorArm64" ]; then
./gradlew :composeApp:linkDebugFrameworkIosSimulatorArm64
else
echo -e "\033[31mError: Unsupported platform '$PLATFORM'\033[0m"
exit 4
fi
# SO packaging end time
HAP_START_TIME=$(date +%s)
# --- Subsequent install logic (hdc install etc.) ---
# ====================== [4. HAP Package Build] ======================
# Switch to harmonyApp directory for subsequent OHOS commands
# Use external path if specified, otherwise use default harmonyApp directory
if [ -n "$LOCAL_OHOS_PATH" ]; then
HARMONY_APP_DIR="$LOCAL_OHOS_PATH"
else
HARMONY_APP_DIR="harmonyApp"
fi
if [ ! -d "$HARMONY_APP_DIR" ]; then
echo -e "\033[31mError: harmonyApp directory not found: $HARMONY_APP_DIR\033[0m"
exit 4
fi
cd "$HARMONY_APP_DIR"
echo "Switched to harmonyApp directory: $(pwd)"
echo "Running Hvigor sync and HAP packaging (buildMode=$BUILD_MODE)..."
ohpm install --all
node "$DEVECO_HOME/tools/hvigor/bin/hvigorw.js" --sync -p product=default -p buildMode="$BUILD_MODE" --analyze=normal --parallel --incremental --daemon
if [ "$BUILD_MODE" = "release" ]; then
node "$DEVECO_HOME/tools/hvigor/bin/hvigorw.js" --mode module -p module=entry -p product=default -p buildMode=release -p requiredDeviceType=phone assembleHap compileNative --analyze=normal --parallel --incremental --daemon
else
node "$DEVECO_HOME/tools/hvigor/bin/hvigorw.js" --mode module -p module=entry@default -p product=default -p buildMode=debug -p requiredDeviceType=phone assembleHap --analyze=normal --parallel --incremental --daemon
fi
# ====================== [5. Install and Push Debug Components] ======================
AVAILABLE_TARGETS=$("$HDC_BIN" list targets)
HAP_DIR="./entry/build/default/outputs/default"
SIGNED_HAP="entry-default-signed.hap"
HAP_FILE="$HAP_DIR/$SIGNED_HAP"
echo "Package path: $HAP_DIR/$SIGNED_HAP"
# Check if signed HAP package exists
if [ ! -f "$HAP_FILE" ]; then
echo -e "\033[31mError: Signed HAP package not found!\033[0m"
echo ""
echo -e "\033[33mExpected path:\033[0m"
echo " $HARMONY_APP_DIR/entry/build/default/outputs/default/entry-default-signed.hap"
echo ""
echo -e "\033[33mPossible causes:\033[0m"
echo " • HAP package has not been built yet"
echo " • Build process failed"
echo " • HAP package is not signed"
echo ""
echo -e "\033[36mSuggested actions:\033[0m"
echo " 1. Check the build logs above for errors"
echo " 2. Verify DevEco Studio signing configuration is correct"
echo " 3. Manually build and sign HAP package in DevEco Studio"
echo " 4. Check files in entry/build/default/outputs/default/ directory"
exit 6
fi
AVAILABLE_TARGETS=$("$HDC_BIN" list targets)
if ! echo "$AVAILABLE_TARGETS" | grep -q "$TARGET_ID"; then
echo -e "\033[31mError: Device $TARGET_ID is offline!\033[0m"
exit 5
fi
echo "Pushing debug components and installing HAP..."
echo " - Device: $TARGET_ID"
# Install HAP (using temp directory)
REMOTE_HAP_DIR="/data/local/tmp/debug_install"
"$HDC_BIN" -t "$TARGET_ID" shell mkdir -p "$REMOTE_HAP_DIR"
"$HDC_BIN" -t "$TARGET_ID" file send "$HAP_FILE" "$REMOTE_HAP_DIR"
INSTALL_OUTPUT=$("$HDC_BIN" -t "$TARGET_ID" shell bm install -p "$REMOTE_HAP_DIR/$SIGNED_HAP" 2>&1)
sleep 1
INSTALL_RESULT=$?
echo "Install status: $INSTALL_OUTPUT"
if echo "$INSTALL_OUTPUT" | grep -qE "failed"; then
echo "Install failed detected, uninstalling and reinstalling..."
"$HDC_BIN" -t "$TARGET_ID" shell bm uninstall -n "$BUNDLE_NAME" >/dev/null 2>&1 || true
sleep 5
INSTALL_OUTPUT=$("$HDC_BIN" -t "$TARGET_ID" shell bm install -p "$REMOTE_HAP_DIR/$SIGNED_HAP" 2>&1)
sleep 5
fi
# ====================== [6. App Launch and Debug Mount] ======================
echo -e "\033[33mLaunching app and starting debug listener...\033[0m"
"$HDC_BIN" -t "$TARGET_ID" shell rm -rf "$REMOTE_HAP_DIR"
sleep 1
# Get system version
#SYSTEM_VERSION=$($HDC_BIN -t $TARGET_ID shell param get const.ohos.apiversion 2>/dev/null || echo "unknown")
#echo "Detected system version: $SYSTEM_VERSION"
# Check screen lock status and prompt
echo ""
echo -e "\033[33m⚠ Important:\033[0m"
echo -e " If device screen is locked, please unlock it manually"
echo -e " System cannot auto-unlock in developer mode (security restriction)"
echo ""
# Step 1: Start app (with -D if debug mode enabled)
echo " -> Executing aa start (launch app)..."
if [ "$DEBUG_MODE" = "debug" ]; then
echo " -> Debug mode, starting with -D flag"
AA_START_OUTPUT=$("$HDC_BIN" -t "$TARGET_ID" shell aa start -a "$ABILITY_NAME" -b "$BUNDLE_NAME" -D 2>&1)
else
echo " -> Attach mode, starting without -D flag"
AA_START_OUTPUT=$("$HDC_BIN" -t "$TARGET_ID" shell aa start -a "$ABILITY_NAME" -b "$BUNDLE_NAME" 2>&1)
fi
# Package push complete time
END_TIME=$(date +%s)
AA_START_RESULT=$?
# Check if screen lock error
if echo "$AA_START_OUTPUT" | grep -q "10106102\|screen is locked"; then
echo -e "\033[31mError: Device screen is locked!\033[0m"
echo ""
echo -e "\033[33mPlease follow these steps:\033[0m"
echo " 1. Manually unlock device screen"
echo " 2. Keep screen awake (recommended for dev: Settings -> Display & Brightness -> Screen timeout -> Never)"
echo " 3. Run this script again"
echo ""
echo -e "\033[36mNote: Auto-unlock is not available in developer mode (system security restriction)\033[0m"
exit 1
fi
# If start failed but not screen lock error, continue anyway
if [ $AA_START_RESULT -ne 0 ]; then
echo -e "\033[33m⚠ App start command returned non-zero exit code, but continuing...\033[0m"
fi
# Push lldb-server
"$HDC_BIN" -t "$TARGET_ID" shell mkdir -p /data/local/tmp/debugserver
"$HDC_BIN" -t "$TARGET_ID" shell rm -f /data/local/tmp/debugserver/lldb-server
"$HDC_BIN" -t "$TARGET_ID" file send "$DEVECO_HOME/sdk/default/hms/native/lldb/aarch64-linux-ohos/lldb-server" /data/local/tmp/debugserver
"$HDC_BIN" -t "$TARGET_ID" shell chmod 755 /data/local/tmp/debugserver/lldb-server
# Step 2: Get app PID
get_pid_func() {
"$HDC_BIN" -t "$TARGET_ID" shell "pidof $BUNDLE_NAME" 2>/dev/null | tr -d '\r' | tr -d '\n' | awk '{print $1}'
}
echo -n "Waiting for app to start"
MAX_WAIT=20
COUNT=0
APP_PID=""
while [ $COUNT -lt $MAX_WAIT ]; do
APP_PID=$(get_pid_func)
if [[ "$APP_PID" =~ ^[0-9]+$ ]]; then
echo -e "\nApp started (PID: $APP_PID)"
break
fi
echo -n "."
sleep 1
let COUNT=COUNT+1
done
if [ -z "$APP_PID" ]; then
echo -e "\n\033[31mFailed: App did not start within expected time!\033[0m"
echo ""
echo -e "\033[33mPossible causes:\033[0m"
echo " • Device screen is locked (most common)"
echo " • App installation failed"
echo " • Device performance issue causing startup timeout"
echo ""
echo -e "\033[36mSuggested actions:\033[0m"
echo " 1. Ensure device screen is unlocked"
echo " 2. Check device connection: hdc list targets"
echo " 3. Manually launch app to verify it runs"
exit 1
fi
"$HDC_BIN" -t "$TARGET_ID" shell aa attach -b "$BUNDLE_NAME"
# Step 3: Start lldb-server and attach to process
echo " -> Starting lldb-server and attaching to process (PID: $APP_PID)..."
"$HDC_BIN" -t "$TARGET_ID" shell aa process -a "$ABILITY_NAME" -b "$BUNDLE_NAME" -D "/data/local/tmp/debugserver/lldb-server platform --listen unix-abstract:///lldb-server/platform.sock"
echo "------------------------------------------------------------"
echo -e "\033[32mBuild, install and app launch completed!\033[0m"
# Calculate total duration
ELAPSED_TIME=$((END_TIME - START_TIME))
MINUTES=$((ELAPSED_TIME / 60))
SECONDS=$((ELAPSED_TIME % 60))
echo -e "App info:"
echo -e " - Bundle: $BUNDLE_NAME"
echo -e " - PID: $APP_PID"
echo -e " - Device: $TARGET_ID"
ELAPSED_TIME=$((HAP_START_TIME - START_TIME))
MINUTES=$((ELAPSED_TIME / 60))
SECONDS=$((ELAPSED_TIME % 60))
echo -e " - SO build time: ${MINUTES}m${SECONDS}s (${ELAPSED_TIME}s)"
ELAPSED_TIME=$((END_TIME - HAP_START_TIME))
MINUTES=$((ELAPSED_TIME / 60))
SECONDS=$((ELAPSED_TIME % 60))
echo -e " - HAP package and push time: ${MINUTES}m${SECONDS}s (${ELAPSED_TIME}s)"
ELAPSED_TIME=$((END_TIME - START_TIME))
MINUTES=$((ELAPSED_TIME / 60))
SECONDS=$((ELAPSED_TIME % 60))
echo -e " - Total time: ${MINUTES}m${SECONDS}s (${ELAPSED_TIME}s)"
echo -e "\033[36mNote: You can now connect via LLDB to debug on the device\033[0m"
echo "------------------------------------------------------------"
\ No newline at end of file
@echo off
setlocal EnableDelayedExpansion
REM Run OHOS app and debug on Windows (paths and commands differ from Mac)
REM Usage: runDebugOhosApp-Win.bat [options] [PLATFORM] [TARGET_ID]
REM Options: -b BUNDLE -a ABILITY -p LOCAL_OHOS_PATH
REM Example: runDebugOhosApp-Win.bat ohosArm64 127.0.0.1:5555
set DEFAULT_PLATFORM=ohosArm64
set DEFAULT_TARGET_ID=127.0.0.1:5555
set DEFAULT_BUNDLE_NAME=com.example.harmonyapp
set DEFAULT_ABILITY_NAME=EntryAbility
set BUNDLE_NAME=%DEFAULT_BUNDLE_NAME%
set ABILITY_NAME=%DEFAULT_ABILITY_NAME%
set BUILD_MODE=debug
set DEBUG_MODE=attach
set LOCAL_OHOS_PATH=
set PLATFORM=
set TARGET_ID=
REM Parse options (supports options in any position, e.g. ohosArm64 62Q0226107024702 -m release)
:parse
if "%~1"=="" goto done_parse
if "%~1"=="-m" (set "BUILD_MODE=%~2" & shift & shift & goto parse)
if "%~1"=="-b" (set "BUNDLE_NAME=%~2" & shift & shift & goto parse)
if "%~1"=="-a" (set "ABILITY_NAME=%~2" & shift & shift & goto parse)
if "%~1"=="-d" (set "DEBUG_MODE=%~2" & shift & shift & goto parse)
if "%~1"=="-p" (set "LOCAL_OHOS_PATH=%~2" & shift & shift & goto parse)
if "%~1"=="-h" goto show_help
REM Positional: first=PLATFORM, second=TARGET_ID
if "!PLATFORM!"=="" (set "PLATFORM=%~1") else if "!TARGET_ID!"=="" (set "TARGET_ID=%~1")
shift
goto parse
:done_parse
if "!PLATFORM!"=="" set "PLATFORM=%DEFAULT_PLATFORM%"
if "!TARGET_ID!"=="" set "TARGET_ID=%DEFAULT_TARGET_ID%"
REM Record script start time (epoch seconds for elapsed calculation)
for /f %%t in ('powershell -NoProfile -Command "[int][double]::Parse((Get-Date -UFormat '%%s'))"') do set START_TIME=%%t
echo Run environment configuration:
echo - Platform: %PLATFORM%
echo - Device: %TARGET_ID%
echo - Build mode: %BUILD_MODE%
echo - Debug mode: %DEBUG_MODE%
echo - Bundle: %BUNDLE_NAME%
echo - Ability: %ABILITY_NAME%
if not "%LOCAL_OHOS_PATH%"=="" echo - External OHOS path: %LOCAL_OHOS_PATH%
echo ------------------------------------------------------------
REM ====================== [2. Environment Path and SDK Configuration] ======================
REM DevEco/SDK path: OHOS_SDK_HOME env or default Windows location
if not "%OHOS_SDK_HOME%"=="" (
set "SDK_HOME=%OHOS_SDK_HOME%"
) else (
if exist "C:\Program Files\Huawei\DevEco Studio" (
set "SDK_HOME=C:\Program Files\Huawei\DevEco Studio"
) else if exist "D:\Program Files\Huawei\DevEco Studio" (
set "SDK_HOME=D:\Program Files\Huawei\DevEco Studio"
) else (
echo Error: DevEco Studio not found. Set OHOS_SDK_HOME or install to default path.
exit /b 1
)
)
echo DevEco Studio Path: %SDK_HOME%
echo Checking environment configuration...
set "MIN_VERSION=6.0.0"
set "PRODUCT_INFO=%SDK_HOME%\product-info.json"
if exist "%PRODUCT_INFO%" (
for /f "tokens=*" %%v in ('powershell -NoProfile -Command "(Get-Content '%PRODUCT_INFO%' | ConvertFrom-Json).version"') do set "CURRENT_VERSION=%%v"
) else (
echo Warning: product-info.json not found, skipping version check.
set "CURRENT_VERSION=unknown"
)
if not "%CURRENT_VERSION%"=="unknown" (
echo Current DevEco version: %CURRENT_VERSION%
echo Minimum required version: %MIN_VERSION%
for /f "tokens=1,2 delims=." %%a in ("%CURRENT_VERSION%") do (
set "CUR_MAJOR=%%a"
set "CUR_MINOR=%%b"
)
for /f "tokens=1,2 delims=." %%a in ("%MIN_VERSION%") do (
set "REQ_MAJOR=%%a"
set "REQ_MINOR=%%b"
)
if !CUR_MAJOR! lss !REQ_MAJOR! (
echo -------------------------------------------------------
echo Error: DevEco version is too low!
echo Current version: %CURRENT_VERSION%
echo Minimum required: %MIN_VERSION%+
echo Please upgrade DevEco Studio and run this script again.
echo -------------------------------------------------------
exit /b 5
)
if !CUR_MAJOR! equ !REQ_MAJOR! if !CUR_MINOR! lss !REQ_MINOR! (
echo -------------------------------------------------------
echo Error: DevEco version is too low!
echo Current version: %CURRENT_VERSION%
echo Minimum required: %MIN_VERSION%+
echo Please upgrade DevEco Studio and run this script again.
echo -------------------------------------------------------
exit /b 5
)
echo DevEco version meets requirements (%CURRENT_VERSION%)
)
set "HDC_BIN=%SDK_HOME%\sdk\default\openharmony\toolchains\hdc.exe"
set "DEVECO_SDK_HOME=%SDK_HOME%\sdk"
set "PATH=%SDK_HOME%\tools\node;%SDK_HOME%\tools\ohpm\bin;%SDK_HOME%\tools\hvigor\bin;%DEVECO_SDK_HOME%;%PATH%"
if not exist "%HDC_BIN%" (
echo Error: hdc not found at %HDC_BIN%
exit /b 1
)
"%HDC_BIN%" -t %TARGET_ID% shell aa force-stop %BUNDLE_NAME% 2>nul
REM ====================== Gradle Build ======================
echo Working path: %CD%
echo Building OpenHarmony (%PLATFORM%)...
if "%PLATFORM%"=="ohosArm64" (
REM for ohosArm64 ohos in windows x86_64 build
if "%BUILD_MODE%"=="release" (
if not "%LOCAL_OHOS_PATH%"=="" (
call gradlew.bat :composeApp:publishReleaseBinariesToHarmonyApp -PharmonyAppPath="%LOCAL_OHOS_PATH%"
) else (
call gradlew.bat :composeApp:publishReleaseBinariesToHarmonyApp
)
) else (
if not "%LOCAL_OHOS_PATH%"=="" (
call gradlew.bat :composeApp:publishDebugBinariesToHarmonyApp -PharmonyAppPath="%LOCAL_OHOS_PATH%"
) else (
call gradlew.bat :composeApp:publishDebugBinariesToHarmonyApp
)
)
) else if "%PLATFORM%"=="ohosX86_64" (
REM for simulate ohos in windows x86_64
if "%BUILD_MODE%"=="release" (
if not "%LOCAL_OHOS_PATH%"=="" (
call gradlew.bat :composeApp:publishReleaseBinariesToHarmonyAppX64 -PharmonyAppPath="%LOCAL_OHOS_PATH%"
) else (
call gradlew.bat :composeApp:publishReleaseBinariesToHarmonyAppX64
)
) else (
if not "%LOCAL_OHOS_PATH%"=="" (
call gradlew.bat :composeApp:publishDebugBinariesToHarmonyAppX64 -PharmonyAppPath="%LOCAL_OHOS_PATH%"
) else (
call gradlew.bat :composeApp:publishDebugBinariesToHarmonyAppX64
)
)
) else (
echo Error: Unsupported platform '%PLATFORM%'
exit /b 4
)
if errorlevel 1 exit /b %errorlevel%
REM SO packaging end time / HAP build start time
for /f %%t in ('powershell -NoProfile -Command "[int][double]::Parse((Get-Date -UFormat '%%s'))"') do set HAP_START_TIME=%%t
REM ====================== HAP build ======================
if not "%LOCAL_OHOS_PATH%"=="" (
set "HARMONY_APP_DIR=%LOCAL_OHOS_PATH%"
) else (
set "HARMONY_APP_DIR=harmonyApp"
)
if not exist "%HARMONY_APP_DIR%" (
echo Error: harmonyApp directory not found: %HARMONY_APP_DIR%
exit /b 4
)
cd /d "%HARMONY_APP_DIR%"
echo Switched to harmonyApp directory: %CD%
echo Running ohpm and Hvigor...
call ohpm install --all
if errorlevel 1 (echo ohpm install failed & exit /b 1)
call node "%SDK_HOME%\tools\hvigor\bin\hvigorw.js" --sync -p product=default -p buildMode=%BUILD_MODE% --analyze=normal --parallel --incremental --daemon
if "%BUILD_MODE%"=="release" (
call node "%SDK_HOME%\tools\hvigor\bin\hvigorw.js" --mode module -p module=entry -p product=default -p buildMode=release -p requiredDeviceType=phone assembleHap compileNative --analyze=normal --parallel --incremental --daemon
) else (
call node "%SDK_HOME%\tools\hvigor\bin\hvigorw.js" --mode module -p module=entry@default -p product=default -p buildMode=debug -p requiredDeviceType=phone assembleHap --analyze=normal --parallel --incremental --daemon
)
if errorlevel 1 (echo Hvigor build failed & exit /b 1)
REM ====================== Install HAP ======================
set "HAP_DIR=entry\build\default\outputs\default"
set "SIGNED_HAP=entry-default-signed.hap"
set "HAP_FILE=%HAP_DIR%\%SIGNED_HAP%"
if not exist "%HAP_FILE%" (
echo Error: Signed HAP package not found!
echo.
echo Expected path: %HARMONY_APP_DIR%\%HAP_DIR%\%SIGNED_HAP%
echo.
echo Possible causes: build not done, build failed, or HAP not signed.
echo Suggested: check build logs, verify signing in DevEco Studio.
exit /b 6
)
set DEVICE_FOUND=
for /f "delims=" %%i in ('"%HDC_BIN%" list targets 2^>nul') do echo %%i | findstr /C:"%TARGET_ID%" >nul && set DEVICE_FOUND=1
if not defined DEVICE_FOUND (
echo Error: Device %TARGET_ID% is offline!
exit /b 5
)
echo Pushing debug components and installing HAP...
echo - Device: %TARGET_ID%
set "REMOTE_HAP_DIR=/data/local/tmp/debug_install"
set "REMOTE_HAP_PATH=%REMOTE_HAP_DIR%/%SIGNED_HAP%"
"%HDC_BIN%" -t %TARGET_ID% shell mkdir -p %REMOTE_HAP_DIR%
"%HDC_BIN%" -t %TARGET_ID% file send "%HAP_FILE%" %REMOTE_HAP_DIR%
"%HDC_BIN%" -t %TARGET_ID% shell bm install -p "%REMOTE_HAP_PATH%" 2>nul
if errorlevel 1 (
echo Reinstall: uninstall then install again...
"%HDC_BIN%" -t %TARGET_ID% shell bm uninstall -n %BUNDLE_NAME% 2>nul
timeout /t 5 /nobreak >nul
"%HDC_BIN%" -t %TARGET_ID% shell bm install -p "%REMOTE_HAP_PATH%"
timeout /t 5 /nobreak >nul
)
REM ====================== Launch and LLDB ======================
"%HDC_BIN%" -t %TARGET_ID% shell rm -rf %REMOTE_HAP_DIR%
timeout /t 1 /nobreak >nul
echo Launching app and starting debug listener...
echo If device screen is locked, please unlock it manually.
echo.
if "%DEBUG_MODE%"=="debug" (
echo Debug mode, starting with -D flag
"%HDC_BIN%" -t %TARGET_ID% shell aa start -a %ABILITY_NAME% -b %BUNDLE_NAME% -D
) else (
echo Attach mode, starting without -D flag
"%HDC_BIN%" -t %TARGET_ID% shell aa start -a %ABILITY_NAME% -b %BUNDLE_NAME%
)
REM Package push complete time
for /f %%t in ('powershell -NoProfile -Command "[int][double]::Parse((Get-Date -UFormat '%%s'))"') do set END_TIME=%%t
"%HDC_BIN%" -t %TARGET_ID% shell rm -rf /data/local/tmp/debugserver/lldb-server
"%HDC_BIN%" -t %TARGET_ID% shell mkdir -p /data/local/tmp/debugserver
"%HDC_BIN%" -t %TARGET_ID% file send "%SDK_HOME%\sdk\default\hms\native\lldb\aarch64-linux-ohos\lldb-server" /data/local/tmp/debugserver/
"%HDC_BIN%" -t %TARGET_ID% shell chmod 755 /data/local/tmp/debugserver/lldb-server
set /a COUNT=0
:wait_pid
set APP_PID=
for /f "tokens=1" %%i in ('"%HDC_BIN%" -t %TARGET_ID% shell pidof %BUNDLE_NAME% 2^>nul') do set "APP_PID=%%i"
if not "%APP_PID%"=="" goto got_pid
timeout /t 1 /nobreak >nul
set /a COUNT+=1
if %COUNT% lss 25 goto wait_pid
echo Error: App did not start within expected time
exit /b 1
:got_pid
echo App started (PID: %APP_PID%)
"%HDC_BIN%" -t %TARGET_ID% shell aa attach -b %BUNDLE_NAME%
"%HDC_BIN%" -t %TARGET_ID% shell aa process -a %ABILITY_NAME% -b %BUNDLE_NAME% -D "/data/local/tmp/debugserver/lldb-server platform --listen unix-abstract:///lldb-server/platform.sock"
echo ------------------------------------------------------------
echo Build, install and app launch completed!
echo.
echo App info:
echo - Bundle: %BUNDLE_NAME%
echo - PID: %APP_PID%
echo - Device: %TARGET_ID%
set /a ELAPSED=HAP_START_TIME-START_TIME
set /a MINUTES=ELAPSED/60
set /a SECONDS=ELAPSED%%60
echo - SO build time: !MINUTES!m!SECONDS!s (!ELAPSED!s)
set /a ELAPSED=END_TIME-HAP_START_TIME
set /a MINUTES=ELAPSED/60
set /a SECONDS=ELAPSED%%60
echo - HAP package and push time: !MINUTES!m!SECONDS!s (!ELAPSED!s)
set /a ELAPSED=END_TIME-START_TIME
set /a MINUTES=ELAPSED/60
set /a SECONDS=ELAPSED%%60
echo - Total time: !MINUTES!m!SECONDS!s (!ELAPSED!s)
echo Note: You can now connect via LLDB to debug on the device
echo ------------------------------------------------------------
:show_help
echo Usage: %~nx0 [options] [PLATFORM] [TARGET_ID]
echo.
echo Parameters:
echo PLATFORM Build platform (default: %DEFAULT_PLATFORM%)
echo TARGET_ID Device ID (default: %DEFAULT_TARGET_ID%)
echo.
echo Options:
echo -m MODE Build mode: debug or release (default: debug)
echo -b BUNDLE Set bundle name (current: %DEFAULT_BUNDLE_NAME%)
echo -a ABILITY Set Ability name (current: %DEFAULT_ABILITY_NAME%)
echo -d MODE Debug mode: debug or attach (default: attach)
echo -p PATH Set external OHOS project path (localOhosPath)
echo -h Show this help
echo.
echo Examples:
echo %~nx0 ohosArm64 127.0.0.1:5555
echo %~nx0 -m release
echo %~nx0 -b com.test.app -a MainAbility
echo %~nx0 -p D:\path\to\external\ohos\project
exit /b 0
#!/bin/bash
#
# Eazytec is pleased to support the open source community by making CPF-KMP-CMP available.
# Copyright (C) 2026 Eazytec. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
set -e
# Record script start time
START_TIME=$(date +%s)
# ====================== [1. Default Configuration and Parameter Parsing] ======================
DEFAULT_PLATFORM="ohosArm64"
DEFAULT_TARGET_ID="127.0.0.1:5555"
DEFAULT_BUNDLE_NAME="com.example.harmonyapp"
DEFAULT_ABILITY_NAME="EntryAbility"
LOCAL_OHOS_PATH=""
usage() {
echo "Usage: $0 [options] [PLATFORM] [TARGET_ID]"
echo ""
echo "Parameters:"
echo " PLATFORM Build platform (default: $DEFAULT_PLATFORM)"
echo " TARGET_ID Device ID (default: $DEFAULT_TARGET_ID)"
echo ""
echo "Options:"
echo " -m MODE Build mode: debug or release (default: debug)"
echo " -b BUNDLE Set bundle name (current: $DEFAULT_BUNDLE_NAME)"
echo " -a ABILITY Set Ability name (current: $DEFAULT_ABILITY_NAME)"
echo " -d MODE Debug mode: debug or attach (default: attach)"
echo " -p PATH Set external OHOS project path (localOhosPath)"
echo " -h Show this help message"
echo ""
echo "Examples:"
echo " $0 ohosArm64 127.0.0.1:5555"
echo " $0 -m release # Release build"
echo " $0 -b com.test.app -a MainAbility"
echo " $0 -p /path/to/external/ohos/project"
exit 0
}
# Preset variables
BUNDLE_NAME=$DEFAULT_BUNDLE_NAME
ABILITY_NAME=$DEFAULT_ABILITY_NAME
BUILD_MODE="debug"
DEBUG_MODE="attach"
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
# Parse options (supports options in any position, e.g. ohosArm64 62Q0226107024702 -m release)
POSITIONALS=()
while [[ $# -gt 0 ]]; do
case $1 in
-m) BUILD_MODE="$2"; shift 2 ;;
-b) BUNDLE_NAME="$2"; shift 2 ;;
-a) ABILITY_NAME="$2"; shift 2 ;;
-d) DEBUG_MODE="$2"; shift 2 ;;
-p) LOCAL_OHOS_PATH="$2"; shift 2 ;;
-h) usage ;;
-*)
echo "Unknown option: $1"
usage
;;
*)
POSITIONALS+=("$1")
shift
;;
esac
done
PLATFORM=${POSITIONALS[0]:-$DEFAULT_PLATFORM}
TARGET_ID=${POSITIONALS[1]:-$DEFAULT_TARGET_ID}
echo -e "\033[32m▶ Run environment configuration:\033[0m"
echo " - Platform: $PLATFORM"
echo " - Device: $TARGET_ID"
echo " - Build mode: $BUILD_MODE"
echo " - Debug mode: $DEBUG_MODE"
echo " - Bundle: $BUNDLE_NAME"
echo " - Ability: $ABILITY_NAME"
if [ -n "$LOCAL_OHOS_PATH" ]; then
echo " - External OHOS path: $LOCAL_OHOS_PATH"
fi
echo "------------------------------------------------------------"
# --- Configuration ---
DEVECO_PATH="${DEVECO_PATH:-/Applications/DevEco-Studio.app}"
MIN_VERSION="6.0.0"
echo " DevEco Studio Path ${DEVECO_PATH}"
echo "🔍 Checking environment configuration..."
# 1. Check if DevEco exists
if [ ! -d "$DEVECO_PATH" ]; then
echo "❌ Error: DevEco Studio not found at $DEVECO_PATH."
exit 1
fi
# 2. Get version (from Info.plist CFBundleShortVersionString)
# Output example: 5.0.3.406
CURRENT_VERSION=$(defaults read "$DEVECO_PATH/Contents/Info.plist" CFBundleShortVersionString)
echo "Current DevEco version: $CURRENT_VERSION"
echo "Minimum required version: $MIN_VERSION"
CUR_MAJOR=$(echo "$CURRENT_VERSION" | cut -d. -f1)
CUR_MINOR=$(echo "$CURRENT_VERSION" | cut -d. -f2)
REQ_MAJOR=$(echo "$MIN_VERSION" | cut -d. -f1)
REQ_MINOR=$(echo "$MIN_VERSION" | cut -d. -f2)
if [ "$CUR_MAJOR" -lt "$REQ_MAJOR" ] 2>/dev/null || \
{ [ "$CUR_MAJOR" -eq "$REQ_MAJOR" ] && [ "$CUR_MINOR" -lt "$REQ_MINOR" ]; }; then
echo "-------------------------------------------------------"
echo -e "${RED}⛔️ Error: DevEco version is too low!${NC}"
echo -e "${RED}Current version: $CURRENT_VERSION${NC}"
echo -e "${RED}Minimum required: $MIN_VERSION+${NC}"
echo -e "${RED}Please upgrade DevEco Studio and run this script again.${NC}"
echo "-------------------------------------------------------"
exit 5
fi
echo "✅ DevEco version meets requirements ($CURRENT_VERSION)"
# ====================== [2. Environment Path and SDK Configuration] ======================
DEVECO_HOME="${DEVECO_HOME:-$DEVECO_PATH/Contents}"
echo "✅ ($DEVECO_HOME)"
HDC_BIN="$DEVECO_HOME/sdk/default/openharmony/toolchains/hdc"
export DEVECO_SDK_HOME="$DEVECO_HOME/sdk"
export PATH="$DEVECO_SDK_HOME:$DEVECO_HOME/jbr/Contents/Home/bin:$DEVECO_HOME/tools/node/bin:$DEVECO_HOME/tools/ohpm/bin:$DEVECO_HOME/tools/hvigor/bin:$PATH"
"$HDC_BIN" -t "$TARGET_ID" shell aa force-stop "$BUNDLE_NAME" >/dev/null 2>&1 || true
# ====================== [3. Gradle Build] ======================
echo "Working path: $(pwd)"
echo "Building OpenHarmony ARM64..."
if [ "$PLATFORM" = "ohosArm64" ]; then
# Execute Gradle build in project root
if [ "$BUILD_MODE" = "release" ]; then
if [ -n "$LOCAL_OHOS_PATH" ]; then
echo "Using external OHOS path: $LOCAL_OHOS_PATH"
echo "/gradlew :composeApp:publishReleaseBinariesToHarmonyApp"
./gradlew :composeApp:publishReleaseBinariesToHarmonyApp -PharmonyAppPath="$LOCAL_OHOS_PATH"
else
echo "/gradlew :composeApp:publishReleaseBinariesToHarmonyApp"
./gradlew :composeApp:publishReleaseBinariesToHarmonyApp
fi
else
if [ -n "$LOCAL_OHOS_PATH" ]; then
echo "Using external OHOS path: $LOCAL_OHOS_PATH"
./gradlew :composeApp:publishDebugBinariesToHarmonyApp -PharmonyAppPath="$LOCAL_OHOS_PATH"
else
echo "/gradlew :composeApp:publishDebugBinariesToHarmonyApp"
./gradlew :composeApp:publishDebugBinariesToHarmonyApp
fi
fi
elif [ "$PLATFORM" = "iosSimulatorArm64" ]; then
./gradlew :composeApp:linkDebugFrameworkIosSimulatorArm64
else
echo -e "\033[31mError: Unsupported platform '$PLATFORM'\033[0m"
exit 4
fi
# SO packaging end time
HAP_START_TIME=$(date +%s)
# --- Subsequent install logic (hdc install etc.) ---
# ====================== [4. HAP Package Build] ======================
# Switch to harmonyApp directory for subsequent OHOS commands
# Use external path if specified, otherwise use default harmonyApp directory
if [ -n "$LOCAL_OHOS_PATH" ]; then
HARMONY_APP_DIR="$LOCAL_OHOS_PATH"
else
HARMONY_APP_DIR="harmonyApp"
fi
if [ ! -d "$HARMONY_APP_DIR" ]; then
echo -e "\033[31mError: harmonyApp directory not found: $HARMONY_APP_DIR\033[0m"
exit 4
fi
cd "$HARMONY_APP_DIR"
echo "Switched to harmonyApp directory: $(pwd)"
echo "Running Hvigor sync and HAP packaging (buildMode=$BUILD_MODE)..."
ohpm install --all
node "$DEVECO_HOME/tools/hvigor/bin/hvigorw.js" --sync -p product=default -p buildMode="$BUILD_MODE" --analyze=normal --parallel --incremental --daemon
if [ "$BUILD_MODE" = "release" ]; then
node "$DEVECO_HOME/tools/hvigor/bin/hvigorw.js" --mode module -p module=entry -p product=default -p buildMode=release -p requiredDeviceType=phone assembleHap compileNative --analyze=normal --parallel --incremental --daemon
else
node "$DEVECO_HOME/tools/hvigor/bin/hvigorw.js" --mode module -p module=entry@default -p product=default -p buildMode=debug -p requiredDeviceType=phone assembleHap --analyze=normal --parallel --incremental --daemon
fi
# ====================== [5. Install and Push Debug Components] ======================
AVAILABLE_TARGETS=$("$HDC_BIN" list targets)
HAP_DIR="./entry/build/default/outputs/default"
SIGNED_HAP="entry-default-signed.hap"
HAP_FILE="$HAP_DIR/$SIGNED_HAP"
echo "Package path: $HAP_DIR/$SIGNED_HAP"
# Check if signed HAP package exists
if [ ! -f "$HAP_FILE" ]; then
echo -e "\033[31mError: Signed HAP package not found!\033[0m"
echo ""
echo -e "\033[33mExpected path:\033[0m"
echo " $HARMONY_APP_DIR/entry/build/default/outputs/default/entry-default-signed.hap"
echo ""
echo -e "\033[33mPossible causes:\033[0m"
echo " • HAP package has not been built yet"
echo " • Build process failed"
echo " • HAP package is not signed"
echo ""
echo -e "\033[36mSuggested actions:\033[0m"
echo " 1. Check the build logs above for errors"
echo " 2. Verify DevEco Studio signing configuration is correct"
echo " 3. Manually build and sign HAP package in DevEco Studio"
echo " 4. Check files in entry/build/default/outputs/default/ directory"
exit 6
fi
AVAILABLE_TARGETS=$("$HDC_BIN" list targets)
if ! echo "$AVAILABLE_TARGETS" | grep -q "$TARGET_ID"; then
echo -e "\033[31mError: Device $TARGET_ID is offline!\033[0m"
exit 5
fi
echo "Pushing debug components and installing HAP..."
echo " - Device: $TARGET_ID"
# Install HAP (using temp directory)
REMOTE_HAP_DIR="/data/local/tmp/debug_install"
"$HDC_BIN" -t "$TARGET_ID" shell mkdir -p "$REMOTE_HAP_DIR"
"$HDC_BIN" -t "$TARGET_ID" file send "$HAP_FILE" "$REMOTE_HAP_DIR"
INSTALL_OUTPUT=$("$HDC_BIN" -t "$TARGET_ID" shell bm install -p "$REMOTE_HAP_DIR/$SIGNED_HAP" 2>&1)
sleep 1
INSTALL_RESULT=$?
echo "Install status: $INSTALL_OUTPUT"
if echo "$INSTALL_OUTPUT" | grep -qE "failed"; then
echo "Install failed detected, uninstalling and reinstalling..."
"$HDC_BIN" -t "$TARGET_ID" shell bm uninstall -n "$BUNDLE_NAME" >/dev/null 2>&1 || true
sleep 5
INSTALL_OUTPUT=$("$HDC_BIN" -t "$TARGET_ID" shell bm install -p "$REMOTE_HAP_DIR/$SIGNED_HAP" 2>&1)
sleep 5
fi
# ====================== [6. App Launch and Debug Mount] ======================
echo -e "\033[33mLaunching app and starting debug listener...\033[0m"
"$HDC_BIN" -t "$TARGET_ID" shell rm -rf "$REMOTE_HAP_DIR"
sleep 1
# Get system version
#SYSTEM_VERSION=$($HDC_BIN -t $TARGET_ID shell param get const.ohos.apiversion 2>/dev/null || echo "unknown")
#echo "Detected system version: $SYSTEM_VERSION"
# Check screen lock status and prompt
echo ""
echo -e "\033[33m⚠ Important:\033[0m"
echo -e " If device screen is locked, please unlock it manually"
echo -e " System cannot auto-unlock in developer mode (security restriction)"
echo ""
# Step 1: Start app (with -D if debug mode enabled)
echo " -> Executing aa start (launch app)..."
if [ "$DEBUG_MODE" = "debug" ]; then
echo " -> Debug mode, starting with -D flag"
AA_START_OUTPUT=$("$HDC_BIN" -t "$TARGET_ID" shell aa start -a "$ABILITY_NAME" -b "$BUNDLE_NAME" -D 2>&1)
else
echo " -> Attach mode, starting without -D flag"
AA_START_OUTPUT=$("$HDC_BIN" -t "$TARGET_ID" shell aa start -a "$ABILITY_NAME" -b "$BUNDLE_NAME" 2>&1)
fi
# Package push complete time
END_TIME=$(date +%s)
AA_START_RESULT=$?
# Check if screen lock error
if echo "$AA_START_OUTPUT" | grep -q "10106102\|screen is locked"; then
echo -e "\033[31mError: Device screen is locked!\033[0m"
echo ""
echo -e "\033[33mPlease follow these steps:\033[0m"
echo " 1. Manually unlock device screen"
echo " 2. Keep screen awake (recommended for dev: Settings -> Display & Brightness -> Screen timeout -> Never)"
echo " 3. Run this script again"
echo ""
echo -e "\033[36mNote: Auto-unlock is not available in developer mode (system security restriction)\033[0m"
exit 1
fi
# If start failed but not screen lock error, continue anyway
if [ $AA_START_RESULT -ne 0 ]; then
echo -e "\033[33m⚠ App start command returned non-zero exit code, but continuing...\033[0m"
fi
echo "------------------------------------------------------------"
echo -e "\033[32mBuild, install and app launch completed!\033[0m"
#------------------will delete next version start--------------------
# Step 2: Get app PID
get_pid_func() {
"$HDC_BIN" -t "$TARGET_ID" shell "pidof $BUNDLE_NAME" 2>/dev/null | tr -d '\r' | tr -d '\n' | awk '{print $1}'
}
echo -n "Waiting for app to start"
MAX_WAIT=20
COUNT=0
APP_PID=""
while [ $COUNT -lt $MAX_WAIT ]; do
APP_PID=$(get_pid_func)
if [[ "$APP_PID" =~ ^[0-9]+$ ]]; then
echo -e "\nApp started (PID: $APP_PID)"
break
fi
echo -n "."
sleep 1
let COUNT=COUNT+1
done
if [ -z "$APP_PID" ]; then
echo -e "\n\033[31mFailed: App did not start within expected time!\033[0m"
echo ""
echo -e "\033[33mPossible causes:\033[0m"
echo " • Device screen is locked (most common)"
echo " • App installation failed"
echo " • Device performance issue causing startup timeout"
echo ""
echo -e "\033[36mSuggested actions:\033[0m"
echo " 1. Ensure device screen is unlocked"
echo " 2. Check device connection: hdc list targets"
echo " 3. Manually launch app to verify it runs"
exit 1
fi
# Step 3: Start lldb-server and attach to process
echo -e " - Bundle: $BUNDLE_NAME"
echo " ->(PID: $APP_PID)..."
#------------------will delete next version end--------------------
# Calculate total duration
ELAPSED_TIME=$((END_TIME - START_TIME))
MINUTES=$((ELAPSED_TIME / 60))
SECONDS=$((ELAPSED_TIME % 60))
echo -e "App info:"
echo -e " - Bundle: $BUNDLE_NAME"
echo -e " - Device: $TARGET_ID"
ELAPSED_TIME=$((HAP_START_TIME - START_TIME))
MINUTES=$((ELAPSED_TIME / 60))
SECONDS=$((ELAPSED_TIME % 60))
echo -e " - SO build time: ${MINUTES}m${SECONDS}s (${ELAPSED_TIME}s)"
ELAPSED_TIME=$((END_TIME - HAP_START_TIME))
MINUTES=$((ELAPSED_TIME / 60))
SECONDS=$((ELAPSED_TIME % 60))
echo -e " - HAP package and push time: ${MINUTES}m${SECONDS}s (${ELAPSED_TIME}s)"
ELAPSED_TIME=$((END_TIME - START_TIME))
MINUTES=$((ELAPSED_TIME / 60))
SECONDS=$((ELAPSED_TIME % 60))
echo -e " - Total time: ${MINUTES}m${SECONDS}s (${ELAPSED_TIME}s)"
\ No newline at end of file
@echo off
setlocal EnableDelayedExpansion
REM Run OHOS app on Windows (no debug / LLDB)
REM Usage: runOhosApp-Win.bat [options] [PLATFORM] [TARGET_ID]
REM Options: -b BUNDLE -a ABILITY -p LOCAL_OHOS_PATH
REM Example: runOhosApp-Win.bat ohosArm64 127.0.0.1:5555
set DEFAULT_PLATFORM=ohosArm64
set DEFAULT_TARGET_ID=127.0.0.1:5555
set DEFAULT_BUNDLE_NAME=com.example.harmonyapp
set DEFAULT_ABILITY_NAME=EntryAbility
set BUNDLE_NAME=%DEFAULT_BUNDLE_NAME%
set ABILITY_NAME=%DEFAULT_ABILITY_NAME%
set BUILD_MODE=debug
set DEBUG_MODE=attach
set LOCAL_OHOS_PATH=
set PLATFORM=
set TARGET_ID=
REM Parse options (supports options in any position, e.g. ohosArm64 62Q0226107024702 -m release)
:parse
if "%~1"=="" goto done_parse
if "%~1"=="-m" (set "BUILD_MODE=%~2" & shift & shift & goto parse)
if "%~1"=="-b" (set "BUNDLE_NAME=%~2" & shift & shift & goto parse)
if "%~1"=="-a" (set "ABILITY_NAME=%~2" & shift & shift & goto parse)
if "%~1"=="-d" (set "DEBUG_MODE=%~2" & shift & shift & goto parse)
if "%~1"=="-p" (set "LOCAL_OHOS_PATH=%~2" & shift & shift & goto parse)
if "%~1"=="-h" goto show_help
REM Positional: first=PLATFORM, second=TARGET_ID
if "!PLATFORM!"=="" (set "PLATFORM=%~1") else if "!TARGET_ID!"=="" (set "TARGET_ID=%~1")
shift
goto parse
:done_parse
if "!PLATFORM!"=="" set "PLATFORM=%DEFAULT_PLATFORM%"
if "!TARGET_ID!"=="" set "TARGET_ID=%DEFAULT_TARGET_ID%"
REM Record script start time (epoch seconds for elapsed calculation)
for /f %%t in ('powershell -NoProfile -Command "[int][double]::Parse((Get-Date -UFormat '%%s'))"') do set START_TIME=%%t
echo Run environment configuration:
echo - Platform: %PLATFORM%
echo - Device: %TARGET_ID%
echo - Build mode: %BUILD_MODE%
echo - Debug mode: %DEBUG_MODE%
echo - Bundle: %BUNDLE_NAME%
echo - Ability: %ABILITY_NAME%
if not "%LOCAL_OHOS_PATH%"=="" echo - External OHOS path: %LOCAL_OHOS_PATH%
echo ------------------------------------------------------------
REM ====================== [2. Environment Path and SDK Configuration] ======================
REM DevEco/SDK path: OHOS_SDK_HOME env or default Windows location
if "%DEVECO_PATH%"=="" (
if exist "C:\Program Files\Huawei\DevEco Studio" (
set "DEVECO_PATH=C:\Program Files\Huawei\DevEco Studio"
) else if exist "D:\Program Files\Huawei\DevEco Studio" (
set "DEVECO_PATH=D:\Program Files\Huawei\DevEco Studio"
) else (
echo Error: DevEco Studio not found. Set OHOS_SDK_HOME or install to default path.
exit /b 1
)
)
echo DevEco Studio Path: %DEVECO_PATH%
echo Checking environment configuration...
set "MIN_VERSION=6.0.0"
set "PRODUCT_INFO=%DEVECO_PATH%\product-info.json"
if exist "%PRODUCT_INFO%" (
for /f "tokens=*" %%v in ('powershell -NoProfile -Command "(Get-Content '%PRODUCT_INFO%' | ConvertFrom-Json).version"') do set "CURRENT_VERSION=%%v"
) else (
echo Warning: product-info.json not found, skipping version check.
set "CURRENT_VERSION=unknown"
)
if not "%CURRENT_VERSION%"=="unknown" (
echo Current DevEco version: %CURRENT_VERSION%
echo Minimum required version: %MIN_VERSION%
for /f "tokens=1,2 delims=." %%a in ("%CURRENT_VERSION%") do (
set "CUR_MAJOR=%%a"
set "CUR_MINOR=%%b"
)
for /f "tokens=1,2 delims=." %%a in ("%MIN_VERSION%") do (
set "REQ_MAJOR=%%a"
set "REQ_MINOR=%%b"
)
if !CUR_MAJOR! lss !REQ_MAJOR! (
echo -------------------------------------------------------
echo Error: DevEco version is too low!
echo Current version: %CURRENT_VERSION%
echo Minimum required: %MIN_VERSION%+
echo Please upgrade DevEco Studio and run this script again.
echo -------------------------------------------------------
exit /b 5
)
if !CUR_MAJOR! equ !REQ_MAJOR! if !CUR_MINOR! lss !REQ_MINOR! (
echo -------------------------------------------------------
echo Error: DevEco version is too low!
echo Current version: %CURRENT_VERSION%
echo Minimum required: %MIN_VERSION%+
echo Please upgrade DevEco Studio and run this script again.
echo -------------------------------------------------------
exit /b 5
)
echo DevEco version meets requirements (%CURRENT_VERSION%)
)
set "HDC_BIN=%DEVECO_PATH%\sdk\default\openharmony\toolchains\hdc.exe"
set "DEVECO_SDK_HOME=%DEVECO_PATH%\sdk"
set "PATH=%DEVECO_PATH%\tools\node;%DEVECO_PATH%\tools\ohpm\bin;%DEVECO_PATH%\tools\hvigor\bin;%DEVECO_SDK_HOME%;%PATH%"
if not exist "%HDC_BIN%" (
echo Error: hdc not found at %HDC_BIN%
exit /b 1
)
"%HDC_BIN%" -t %TARGET_ID% shell aa force-stop %BUNDLE_NAME% 2>nul
REM ====================== Gradle Build ======================
echo Working path: %CD%
echo Building OpenHarmony (%PLATFORM%)...
if "%PLATFORM%"=="ohosArm64" (
REM for ohosArm64 ohos in windows x86_64 build
if "%BUILD_MODE%"=="release" (
if not "%LOCAL_OHOS_PATH%"=="" (
call gradlew.bat :composeApp:publishReleaseBinariesToHarmonyApp -PharmonyAppPath="%LOCAL_OHOS_PATH%"
) else (
call gradlew.bat :composeApp:publishReleaseBinariesToHarmonyApp
)
) else (
if not "%LOCAL_OHOS_PATH%"=="" (
call gradlew.bat :composeApp:publishDebugBinariesToHarmonyApp -PharmonyAppPath="%LOCAL_OHOS_PATH%"
) else (
call gradlew.bat :composeApp:publishDebugBinariesToHarmonyApp
)
)
) else if "%PLATFORM%"=="ohosX86_64" (
REM for simulate ohos in windows x86_64
if "%BUILD_MODE%"=="release" (
if not "%LOCAL_OHOS_PATH%"=="" (
call gradlew.bat :composeApp:publishReleaseBinariesToHarmonyAppX64 -PharmonyAppPath="%LOCAL_OHOS_PATH%"
) else (
call gradlew.bat :composeApp:publishReleaseBinariesToHarmonyAppX64
)
) else (
if not "%LOCAL_OHOS_PATH%"=="" (
call gradlew.bat :composeApp:publishDebugBinariesToHarmonyAppX64 -PharmonyAppPath="%LOCAL_OHOS_PATH%"
) else (
call gradlew.bat :composeApp:publishDebugBinariesToHarmonyAppX64
)
)
) else (
echo Error: Unsupported platform '%PLATFORM%'
exit /b 4
)
if errorlevel 1 exit /b %errorlevel%
REM SO packaging end time / HAP build start time
for /f %%t in ('powershell -NoProfile -Command "[int][double]::Parse((Get-Date -UFormat '%%s'))"') do set HAP_START_TIME=%%t
REM ====================== HAP build ======================
if not "%LOCAL_OHOS_PATH%"=="" (
set "HARMONY_APP_DIR=%LOCAL_OHOS_PATH%"
) else (
set "HARMONY_APP_DIR=harmonyApp"
)
if not exist "%HARMONY_APP_DIR%" (
echo Error: harmonyApp directory not found: %HARMONY_APP_DIR%
exit /b 4
)
cd /d "%HARMONY_APP_DIR%"
echo Switched to harmonyApp directory: %CD%
echo Running ohpm and Hvigor...
call ohpm install --all
if errorlevel 1 (echo ohpm install failed & exit /b 1)
call node "%DEVECO_PATH%\tools\hvigor\bin\hvigorw.js" --sync -p product=default -p buildMode=%BUILD_MODE% --analyze=normal --parallel --incremental --daemon
if "%BUILD_MODE%"=="release" (
call node "%DEVECO_PATH%\tools\hvigor\bin\hvigorw.js" --mode module -p module=entry -p product=default -p buildMode=release -p requiredDeviceType=phone assembleHap compileNative --analyze=normal --parallel --incremental --daemon
) else (
call node "%DEVECO_PATH%\tools\hvigor\bin\hvigorw.js" --mode module -p module=entry@default -p product=default -p buildMode=debug -p requiredDeviceType=phone assembleHap --analyze=normal --parallel --incremental --daemon
)
if errorlevel 1 (echo Hvigor build failed & exit /b 1)
REM ====================== Install HAP ======================
set "HAP_DIR=entry\build\default\outputs\default"
set "SIGNED_HAP=entry-default-signed.hap"
set "HAP_FILE=%HAP_DIR%\%SIGNED_HAP%"
if not exist "%HAP_FILE%" (
echo Error: Signed HAP package not found!
echo.
echo Expected path: %HARMONY_APP_DIR%\%HAP_DIR%\%SIGNED_HAP%
echo.
echo Possible causes: build not done, build failed, or HAP not signed.
echo Suggested: check build logs, verify signing in DevEco Studio.
exit /b 6
)
set DEVICE_FOUND=
for /f "delims=" %%i in ('"%HDC_BIN%" list targets 2^>nul') do echo %%i | findstr /C:"%TARGET_ID%" >nul && set DEVICE_FOUND=1
if not defined DEVICE_FOUND (
echo Error: Device %TARGET_ID% is offline!
exit /b 5
)
echo Pushing and installing HAP...
echo - Device: %TARGET_ID%
set "REMOTE_HAP_DIR=/data/local/tmp/debug_install"
set "REMOTE_HAP_PATH=%REMOTE_HAP_DIR%/%SIGNED_HAP%"
"%HDC_BIN%" -t %TARGET_ID% shell mkdir -p %REMOTE_HAP_DIR%
"%HDC_BIN%" -t %TARGET_ID% file send "%HAP_FILE%" %REMOTE_HAP_DIR%
"%HDC_BIN%" -t %TARGET_ID% shell bm install -p "%REMOTE_HAP_PATH%" 2>nul
if errorlevel 1 (
echo Reinstall: uninstall then install again...
"%HDC_BIN%" -t %TARGET_ID% shell bm uninstall -n %BUNDLE_NAME% 2>nul
timeout /t 5 /nobreak >nul
"%HDC_BIN%" -t %TARGET_ID% shell bm install -p "%REMOTE_HAP_PATH%"
timeout /t 5 /nobreak >nul
)
REM ====================== Launch App ======================
"%HDC_BIN%" -t %TARGET_ID% shell rm -rf %REMOTE_HAP_DIR%
timeout /t 1 /nobreak >nul
echo Launching app...
echo If device screen is locked, please unlock it manually.
echo.
if "%DEBUG_MODE%"=="debug" (
echo Debug mode, starting with -D flag
"%HDC_BIN%" -t %TARGET_ID% shell aa start -a %ABILITY_NAME% -b %BUNDLE_NAME% -D
) else (
echo Attach mode, starting without -D flag
"%HDC_BIN%" -t %TARGET_ID% shell aa start -a %ABILITY_NAME% -b %BUNDLE_NAME%
)
REM ------------------will delete next version start--------------------
set /a COUNT=0
:wait_pid
set APP_PID=
for /f "tokens=1" %%i in ('"%HDC_BIN%" -t %TARGET_ID% shell pidof %BUNDLE_NAME% 2^>nul') do set "APP_PID=%%i"
if not "%APP_PID%"=="" goto got_pid
timeout /t 1 /nobreak >nul
set /a COUNT+=1
if %COUNT% lss 25 goto wait_pid
echo Error: App did not start within expected time
exit /b 1
:got_pid
REM ------------------will delete next version end--------------------
echo App started (PID: %APP_PID%)
REM Package push complete time
for /f %%t in ('powershell -NoProfile -Command "[int][double]::Parse((Get-Date -UFormat '%%s'))"') do set END_TIME=%%t
echo ------------------------------------------------------------
echo Build, install and app launch completed!
echo.
echo App info:
echo - Bundle: %BUNDLE_NAME%
echo - Device: %TARGET_ID%
set /a ELAPSED=HAP_START_TIME-START_TIME
set /a MINUTES=ELAPSED/60
set /a SECONDS=ELAPSED%%60
echo - SO build time: !MINUTES!m!SECONDS!s (!ELAPSED!s)
set /a ELAPSED=END_TIME-HAP_START_TIME
set /a MINUTES=ELAPSED/60
set /a SECONDS=ELAPSED%%60
echo - HAP package and push time: !MINUTES!m!SECONDS!s (!ELAPSED!s)
set /a ELAPSED=END_TIME-START_TIME
set /a MINUTES=ELAPSED/60
set /a SECONDS=ELAPSED%%60
echo - Total time: !MINUTES!m!SECONDS!s (!ELAPSED!s)
echo ------------------------------------------------------------
:show_help
echo Usage: %~nx0 [options] [PLATFORM] [TARGET_ID]
echo.
echo Parameters:
echo PLATFORM Build platform (default: %DEFAULT_PLATFORM%)
echo TARGET_ID Device ID (default: %DEFAULT_TARGET_ID%)
echo.
echo Options:
echo -m MODE Build mode: debug or release (default: debug)
echo -b BUNDLE Set bundle name (current: %DEFAULT_BUNDLE_NAME%)
echo -a ABILITY Set Ability name (current: %DEFAULT_ABILITY_NAME%)
echo -d MODE Debug mode: debug or attach (default: attach)
echo -p PATH Set external OHOS project path (localOhosPath)
echo -h Show this help
echo.
echo Examples:
echo %~nx0 ohosArm64 127.0.0.1:5555
echo %~nx0 -m release
echo %~nx0 -b com.test.app -a MainAbility
echo %~nx0 -p D:\path\to\external\ohos\project
exit /b 0
......@@ -43,38 +43,3 @@ include("nestedlib2")
include("nestedlib3")
include("nestedlib4")
include("nestedlib5")
// 嵌套页面库模块
include("nestedlib1")
include("nestedlib2")
include("nestedlib3")
include("nestedlib4")
include("nestedlib5")
// 嵌套页面库模块
include("nestedlib1")
include("nestedlib2")
include("nestedlib3")
include("nestedlib4")
include("nestedlib5")
// 嵌套页面库模块
include("nestedlib1")
include("nestedlib2")
include("nestedlib3")
include("nestedlib4")
include("nestedlib5")
// 嵌套页面库模块
include("nestedlib1")
include("nestedlib2")
include("nestedlib3")
include("nestedlib4")
include("nestedlib5")
// 嵌套页面库模块
include("nestedlib1")
include("nestedlib2")
include("nestedlib3")
include("nestedlib4")
include("nestedlib5")
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment