Commit 5105997c authored by dsq's avatar dsq

oh.0.1.0-02

parent 157d150f
/**
能导入的包
1. 来源插件
在 当前的 build.gradle.kts 定义可以搭配的插件
plugins {
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.gradle.api.file.DuplicatesStrategy
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
// 导入JvmTarget,用于指定JVM的目标版本
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
// 应用Kotlin多平台插件
alias(libs.plugins.kotlinMultiplatform)
// 应用Android应用插件
alias(libs.plugins.androidApplication)
// 应用Compose多平台插件
alias(libs.plugins.composeMultiplatform)
// 应用Compose编译器插件
alias(libs.plugins.composeCompiler)
// 开启 kotlinx.serialization(用于 navigation 类型安全路由)
alias(libs.plugins.kotlinSerialization)
}
/**
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 {
// 配置Android目标
androidTarget {
@OptIn(ExperimentalKotlinGradlePluginApi::class) // 允许使用实验API
@OptIn(ExperimentalKotlinGradlePluginApi::class)
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11) // 设置JVM target为11
jvmTarget.set(JvmTarget.JVM_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")
}
}
}
// listOf(
// iosX64(),
// iosArm64(),
// iosSimulatorArm64()
// ).forEach { iosTarget ->
// iosTarget.binaries.framework {
// baseName = "ComposeApp"
// isStatic = true
// }
// iosTarget.compilations.getByName("main") {
// compilerOptions.configure {
// freeCompilerArgs.add("-Xbinary=sanitizer=address")
// }
// }
// }
// 配置OHOS(华为鸿蒙)arm64目标
ohosArm64 {
binaries.sharedLib {
baseName = "kn" // 共享库名称为kn
export(libs.compose.multiplatform.export) // 导出compose多平台库的接口
// 确保链接系统 zlib,使 libkn.so 的 NEEDED 包含 libz.so
linkerOpts("-lz")
}
val main by compilations.getting // 获取主编译内容
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定义文件
includeDirs(file("src/ohosArm64Main/cinterop/include")) // cinterop包含目录
//val resource by main.cinterops.creating {
// defFile(file("src/ohosArm64Main/cinterop/resource.def"))
// includeDirs(file("src/ohosArm64Main/cinterop/include"))
// }
}
ohosX64 {
binaries.sharedLib {
baseName = "kn"
export(libs.compose.multiplatform.export)
linkerOpts("-lz")
}
val main by compilations.getting
main.compilerOptions.configure {
freeCompilerArgs.add("-Xbinary=sanitizer=address")
}
// val resource by main.cinterops.creating {
// defFile(file("src/ohosX64Main/cinterop/resource.def"))
// includeDirs(file("src/ohosX64Main/cinterop/include"))
// }
}
// 配置各平台的依赖关系
sourceSets {
androidMain.dependencies {
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.lifecycle.viewmodelCompose)
implementation(libs.androidx.lifecycle.runtimeCompose)
implementation(libs.androidx.collection)
implementation(libs.compose.ui.backhandler) //需要单独依赖
}
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) // Kotlin AtomicFu原子库
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation(compose.material3)
implementation(compose.ui)
implementation(compose.components.resources)
implementation(compose.components.uiToolingPreview)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.atomicFu)
// Navigation 库测试 Demo:使用 Maven 依赖(版本见 libs.versions.toml 的 androidx-navigation)
implementation(libs.compose.navigation)
}
val ohosArm64Main by getting {
dependencies {
api(libs.compose.multiplatform.export) // 导出compose多平台接口给依赖消费者
api(libs.compose.multiplatform.export)
//导出skiko api 用于demo中测试
implementation("org.jetbrains.skiko:skiko-ohosarm64")
}
}
val ohosX64Main by getting {
dependencies {
api(libs.compose.multiplatform.export)
implementation("org.jetbrains.skiko:skiko-ohosx64")
}
}
}
}
/**
应用 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版本
namespace = "com.example.toolchain" // 设置包名
compileSdk = libs.versions.android.compileSdk.get().toInt()
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" // 应用版本名
applicationId = "com.example.toolchain" // 应用ID
minSdk = libs.versions.android.minSdk.get().toInt()
targetSdk = libs.versions.android.targetSdk.get().toInt()
versionCode = 1
versionName = "1.0"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"// 排除打包时的冗余license资源文件
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
buildTypes {
getByName("release") {
isMinifyEnabled = false // 发布包不混淆代码
isMinifyEnabled = false
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11 // 源码兼容Java 11
targetCompatibility = JavaVersion.VERSION_11 // 输出兼容Java 11
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}
dependencies {
debugImplementation(libs.compose.ui.tooling) // debug模式下依赖compose调试工具
debugImplementation(libs.compose.ui.tooling)
}
compose{
ohos{
skia("0.9.22.2-ez-001")
// ohrender(" 0.9.22.2-ohrende")
skia("0.9.22.2-OH.0.1.2-06") // 启用自渲染
// 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 依赖
......@@ -186,37 +162,37 @@ configurations.all {
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}")
// ohosX64
force("org.jetbrains.compose.export:export-ohosx64:${cmpVersion}")
force("org.jetbrains.compose.ui:ui-ohosx64:${cmpVersion}")
force("org.jetbrains.compose.ui:ui-arkui-ohosx64:${cmpVersion}")
force("org.jetbrains.compose.foundation:foundation-ohosx64:${cmpVersion}")
}
}
// Harmony App 输出目录(支持命令行 --harmonyAppPath)
val harmonyAppDir: File = run {
val cliPath = project.findProperty("harmonyAppPath") as String?
if (cliPath.isNullOrBlank()) {
// 默认:项目根目录 /harmonyApp
rootProject.file("harmonyApp")
} else {
// 命令行传入的路径
file(cliPath)
}
}
// 字符串首字母大写工具函数
fun String.capitalizeUS(): String = this.replaceFirstChar {
if (it.isLowerCase()) it.titlecase() else it.toString()
}
// 为不同类型(debug、release)OHOS构建注册Copy任务并发布到Harmony App目录
arrayOf("debug", "release").forEach { type ->
tasks.register<Copy>("publish${type.capitalizeUS()}BinariesToHarmonyApp") {
group = "harmony" // 归类到harmony任务组
dependsOn("link${type.capitalizeUS()}SharedOhosArm64") // 依赖于OHOS shared lib的链接任务
into(harmonyAppDir) // 输出目标目录
from("build/bin/ohosArm64/${type}Shared/libkn_api.h") { // 复制头文件
into("entry/src/main/cpp/include/") // 指定目录
dependsOn("link${type.capitalizeUS()}SharedOhosArm64", "link${type.capitalizeUS()}SharedOhosX64")
duplicatesStrategy = DuplicatesStrategy.INCLUDE
into(rootProject.file("harmonyApp"))
from("build/bin/ohosArm64/${type}Shared/libkn_api.h") {
into("entry/src/main/cpp/include/")
}
from(project.file("build/bin/ohosArm64/${type}Shared/libkn.so")) {
into("entry/libs/arm64-v8a/")
}
from("build/bin/ohosX64/${type}Shared/libkn_api.h") {
into("entry/src/main/cpp/include/")
}
from(project.file("build/bin/ohosX64/${type}Shared/libkn.so")) {
into("entry/libs/x86_64/")
}
from(project.file("build/bin/ohosArm64/${type}Shared/libkn.so")) { // 复制共享库文件
into("/entry/libs/arm64-v8a/") // 指定目标目录
val composeResourcePackage = "${rootProject.name}.${project.name.lowercase()}.generated.resources"
from("src/commonMain/composeResources") {
into("entry/src/main/resources/rawfile/composeResources/$composeResourcePackage/")
}
}
}
package com.dong.demo013
import android.os.Build
class AndroidPlatform : Platform {
override val name: String = "Android ${Build.VERSION.SDK_INT}"
}
actual fun getPlatform(): Platform = AndroidPlatform()
internal actual fun getPlatformDemoList(): List<PlatformDemoItem> = emptyList()
@androidx.compose.runtime.Composable
internal actual fun PlatformDemo(id: String) {
}
package com.dong.demo013
actual fun createTimer(): TimerController {
TODO("Not yet implemented")
}
actual fun startLog(
speed: Int,
onLogGenerated: ((Int) -> Unit)?,
onTimerUpdated: ((Long) -> Unit)?
): LogController {
TODO("Not yet implemented")
}
actual fun pirntAllLevelHiLog() {
}
actual fun pirntSingleHiLog() {
}
actual fun pirntRandomHiLog() {
}
\ No newline at end of file
package com.dong.demo013
class Greeting {
private val platform = getPlatform()
fun greet(): String {
return "Hello, ${platform.name}!"
}
}
\ No newline at end of file
......@@ -10,8 +10,6 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import com.dong.demo013.LogController
import com.dong.demo013.TimerController
import com.dong.demo013.createTimer
import com.dong.demo013.startLog
import kotlinx.coroutines.delay
@OptIn(ExperimentalLayoutApi::class)
......@@ -29,7 +27,7 @@ internal fun HighLogDemo() {
// 初始化计时器
LaunchedEffect(Unit) {
timerController = createTimer()
}
// 定期更新显示时间
......@@ -132,16 +130,7 @@ internal fun HighLogDemo() {
timerController?.reset()
timerController?.start()
// 启动日志生成
isGenerating = true
logController = startLog(speed,
onLogGenerated = { count ->
logCount = count
},
onTimerUpdated = { time ->
// 日志生成的计时现在只用于内部统计,不更新UI
}
)
},
modifier = Modifier.weight(1f),
enabled = logSpeed.isNotEmpty() && !isGenerating
......
package com.dong.demo013
interface Platform {
val name: String
}
expect fun getPlatform(): Platform
internal data class PlatformDemoItem(val id: String, val title: String)
internal expect fun getPlatformDemoList(): List<PlatformDemoItem>
@androidx.compose.runtime.Composable
internal expect fun PlatformDemo(id: String)
package com.dong.demo013
expect fun startLog(speed: Int, onLogGenerated: ((Int) -> Unit)? = null, onTimerUpdated: ((Long) -> Unit)? = null): LogController
// 创建独立的计时器控制器
expect fun createTimer(): TimerController
//所有层级日志打印
expect fun pirntAllLevelHiLog();
//单次日志打印
expect fun pirntSingleHiLog();
//打印随机日志
expect fun pirntRandomHiLog();
\ No newline at end of file
package com.dong.demo013
import kotlin.test.Test
import kotlin.test.assertEquals
class ComposeAppCommonTest {
@Test
fun example() {
assertEquals(3, 1 + 2)
}
}
\ No newline at end of file
package com.dong.demo013
import platform.UIKit.UIDevice
class IOSPlatform: Platform {
override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
}
actual fun getPlatform(): Platform = IOSPlatform()
internal actual fun getPlatformDemoList(): List<PlatformDemoItem> = emptyList()
@androidx.compose.runtime.Composable
internal actual fun PlatformDemo(id: String) {
}
\ No newline at end of file
package com.dong.demo013
actual fun createTimer(): TimerController {
TODO("Not yet implemented")
}
actual fun startLog(
speed: Int,
onLogGenerated: ((Int) -> Unit)?,
onTimerUpdated: ((Long) -> Unit)?
): LogController {
TODO("Not yet implemented")
}
actual fun pirntAllLevelHiLog() {
}
......
package com.dong.demo013
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.arkui.ArkUIView
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.interop.AdaptiveParams
import androidx.compose.ui.interop.InteropContainer
import androidx.compose.ui.napi.JsObject
import androidx.compose.ui.napi.js
private val NoOp: Any.() -> Unit = {}
@Composable
internal fun ArkUIView(
name: String,
modifier: Modifier,
parameter: JsObject = js(),
update: (JsObject) -> Unit = NoOp,
background: Color = Color.Unspecified,
updater: (ArkUIView) -> Unit = NoOp,
onCreate: (ArkUIView) -> Unit = NoOp,
onRelease: (ArkUIView) -> Unit = NoOp,
interactive: Boolean = true,
adaptiveParams: AdaptiveParams? = null,
tag: String? = null,
container: InteropContainer = InteropContainer.BACK
) = androidx.compose.ui.interop.ArkUIView(
name = name,
modifier = modifier,
parameter = parameter,
update = update,
background = background,
updater = updater,
onCreate = onCreate,
onRelease = onRelease,
interactive = interactive,
adaptiveParams = adaptiveParams,
tag = tag,
container = container,
)
package com.dong.demo013
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.napi.js
import androidx.compose.ui.unit.dp
@Composable
internal fun InteropListNested() {
LazyColumn(Modifier.fillMaxSize()) {
items(20) { index ->
when {
index == 3 -> {
// Nested Vertical List (ArkUI)
ArkUIView(
name = "verticalList",
modifier = Modifier.fillMaxWidth().height(300.dp).background(Color.LightGray),
parameter = js { }
)
}
index == 7 -> {
// Horizontal List (ArkUI) - assuming horizontalList exists and works similar
ArkUIView(
name = "horizontalList",
modifier = Modifier.fillMaxWidth().height(150.dp).background(Color.LightGray),
parameter = js { }
)
}
index % 3 == 0 -> {
// Button (ArkUI)
ArkUIView(
name = "button",
modifier = Modifier.fillMaxWidth().height(60.dp),
parameter = js {
"text"("ArkUI Button $index")
"backgroundColor"("#FF0000FF")
}
)
}
else -> {
// Compose Text
Text("Compose Item $index", Modifier.padding(16.dp))
}
}
}
}
}
package com.dong.demo013
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.napi.js
import androidx.compose.ui.unit.dp
@Composable
internal fun InteropListSimple() {
Box {
Column(Modifier.background(Color.LightGray).fillMaxSize()) {
LazyColumn(Modifier.background(Color.Red).fillMaxSize()) {
items(80) { index ->
Column {
ArkUIView(
name = "label",
modifier = Modifier.width(250.dp).height(100.dp),
parameter = js {
"text"("ArkUI Button $index")
"backgroundColor"("#FF0000FF")
},
)
Button({
println("Compose Button $index clicked")
}, modifier = Modifier.height(30.dp).fillMaxWidth()) {
Text("Compose Button $index")
}
}
}
}
}
}
}
package com.dong.demo013
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.napi.js
import androidx.compose.ui.unit.dp
@Composable
internal fun InteropRenderOrder() {
var interLayer by remember { mutableStateOf(false) }
Column {
Box {
ArkUIView(
"layer", Modifier.width(400.dp).height(300.dp),
js {
"text"("1")
"backgroundColor"("#FF0000FF")
},
)
ArkUIView(
"layer", Modifier.width(350.dp).height(250.dp),
js {
"text"("2")
"backgroundColor"("#FF00FF00")
},
)
if (interLayer) {
ArkUIView(
"layer", Modifier.width(300.dp).height(200.dp),
js {
"text"("3")
"backgroundColor"("#FFFF0000")
},
)
}
ArkUIView(
"layer", Modifier.width(250.dp).height(150.dp),
js {
"text"("4")
"backgroundColor"("#FF00FFFF")
},
)
ArkUIView(
"layer", Modifier.width(200.dp).height(100.dp),
js {
"text"("5")
"backgroundColor"("#FFFFFF00")
},
)
}
Button({ interLayer = !interLayer }) {
Text("Show / Hide")
}
}
}
package com.dong.demo013
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.napi.asString
import androidx.compose.ui.napi.js
import androidx.compose.ui.unit.dp
import kotlinx.cinterop.ExperimentalForeignApi
@OptIn(ExperimentalForeignApi::class)
@Composable
internal fun InteropTextInput() {
Column(
Modifier
.fillMaxWidth()
.fillMaxHeight()
.verticalScroll(rememberScrollState())
.padding(30.dp)
) {
var inputText by remember { mutableStateOf("混排状态变量双向通信 输入文本...") }
val state = remember(inputText) {
js { "text"(inputText) }
}
ArkUIView(
name = "textInput",
modifier = Modifier.width(450.dp).wrapContentHeight(),
parameter = state,
update = {
inputText = it["text"].asString().toString()
}
)
Spacer(modifier = Modifier.height(50.dp))
Text(text = "Compose组件更新:", color = Color.Gray)
Text(
text = inputText,
modifier = Modifier.fillMaxWidth()
.border(width = 1.dp, color = Color.Gray)
.padding(10.dp)
)
Button(onClick = { inputText += "[文本]" }) {
Text("Append Text")
}
}
}
package com.dong.demo013
import kotlinx.atomicfu.AtomicBoolean
import kotlinx.atomicfu.atomic
class LogControllerImpl : LogController {
private val _isRunning = atomic(true)
override val isRunning: Boolean
get() = _isRunning.value
override fun stop() {
_isRunning.value = false
}
}
\ No newline at end of file
package com.dong.demo013
class OhosPlatform : Platform {
override val name: String = "HarmonyOS"
}
actual fun getPlatform(): Platform = OhosPlatform()
internal actual fun getPlatformDemoList(): List<PlatformDemoItem> = listOf(
PlatformDemoItem("interop_list_nested", "混排嵌滑"),
PlatformDemoItem("interop_list_simple", "混排列表"),
PlatformDemoItem("interop_render_order", "混排层级"),
PlatformDemoItem("interop_text_input", "混排输入"),
)
@androidx.compose.runtime.Composable
internal actual fun PlatformDemo(id: String) {
when (id) {
"interop_list_nested" -> InteropListNested()
"interop_list_simple" -> InteropListSimple()
"interop_render_order" -> InteropRenderOrder()
"interop_text_input" -> InteropTextInput()
}
}
package com.dong.demo013
import com.dong.demo013.TimerControllerImpl
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import platform.PerformanceAnalysisKit.HiLog.OH_LOG_PrintMsg
import platform.ohos.OH_LOG_Print
@OptIn(DelicateCoroutinesApi::class)
actual fun startLog(
speed: Int,
onLogGenerated: ((Int) -> Unit)?,
onTimerUpdated: ((Long) -> Unit)?
): LogController {
val controller = LogControllerImpl()
// 启动协程在后台执行日志生成
GlobalScope.launch {
generateLogs(speed, onLogGenerated, onTimerUpdated, controller)
}
return controller
}
actual fun createTimer(): TimerController {
return TimerControllerImpl()
}
private suspend fun generateLogs(speed: Int, onLogGenerated: ((Int) -> Unit)?, onTimerUpdated: ((Long) -> Unit)?, controller: LogControllerImpl) {
val startTime = getTimeMillis()
var count = 0
// 发送开始日志 (fatal级别)
hiLogPrintMsg(
type = 0u,
level = 4u, // FATAL level
domain = 0x1234u,
tag = "LogGenerator",
message = "日志生成开始,间隔 ${speed} 毫秒,手动停止模式"
)
// 手动停止模式:持续运行直到用户停止
while (controller.isRunning) {
val currentTime = getTimeMillis()
val elapsedSeconds = (currentTime - startTime) / 1000
// 每秒更新一次计时器显示
if (elapsedSeconds > count) {
onTimerUpdated?.invoke(elapsedSeconds)
}
// 发送普通info日志
hiLogPrintMsg(
type = 0u,
level = 1u, // INFO level
domain = 0x1234u,
tag = "LogGenerator",
message = "生成第 ${++count} 条日志,运行时间: $elapsedSeconds 秒"
)
// 通知UI更新计数
onLogGenerated?.invoke(count)
// 等待指定间隔
kotlinx.coroutines.delay(speed.toLong())
}
// 发送结束日志
val finalTime = (getTimeMillis() - startTime) / 1000
hiLogPrintMsg(
type = 0u,
level = 4u, // FATAL level
domain = 0x1234u,
tag = "LogGenerator",
message = "日志生成手动停止,总运行时间: $finalTime 秒,总共生成: $count 条日志"
)
}
// 获取当前时间戳(毫秒)
private fun getTimeMillis(): Long {
return kotlin.time.TimeSource.Monotonic.markNow().elapsedNow().inWholeMilliseconds
}
@OptIn(kotlinx.cinterop.ExperimentalForeignApi::class, kotlin.experimental.ExperimentalNativeApi::class)
@CName("hiLogPrintMsg")
fun hiLogPrintMsg(type: UInt, level: UInt, domain: UInt, tag: String, message: String): Int {
......@@ -120,3 +42,8 @@ actual fun pirntAllLevelHiLog(){
// LOG_FATAL = 7 (致命级别)
hiLogPrintMsg(0u, 7u, 4660u, "TestTag", "This is a FATAL log from PrintMsg");
}
actual fun pirntRandomHiLog(){
hiLogPrintMsg(0u, 6u, 4660u, "TestTag", "随机日志打印");
}
package com.dong.demo013
import com.dong.demo013.TimerController
import kotlinx.atomicfu.AtomicBoolean
import kotlinx.atomicfu.atomic
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.delay
class TimerControllerImpl : TimerController {
private val _isRunning = atomic(false)
private val _elapsedTime = atomic(0L)
private var timerJob: Job? = null
private val scope = CoroutineScope(Dispatchers.Default)
override val isRunning: Boolean
get() = _isRunning.value
override val elapsedTime: Long
get() = _elapsedTime.value
override fun start() {
if (!_isRunning.value) {
_isRunning.value = true
startTimer()
}
}
override fun stop() {
if (_isRunning.value) {
_isRunning.value = false
timerJob?.cancel()
}
}
override fun reset() {
stop()
_elapsedTime.value = 0L
}
private fun startTimer() {
timerJob = scope.launch {
while (isRunning) {
delay(1000) // 每秒递增1
_elapsedTime.incrementAndGet()
}
}
}
}
\ No newline at end of file
#ifndef GLOBAL_RAW_FILE_H
#define GLOBAL_RAW_FILE_H
#ifdef __cplusplus
extern "C" {
#endif
struct RawFile;
typedef struct RawFile RawFile;
int OH_ResourceManager_ReadRawFile(const RawFile *rawFile, void *buf, size_t length);
long OH_ResourceManager_GetRawFileSize(RawFile *rawFile);
void OH_ResourceManager_CloseRawFile(RawFile *rawFile);
#ifdef __cplusplus
};
#endif
/** @} */
#endif // GLOBAL_RAW_FILE_H
#ifndef GLOBAL_NATIVE_RESOURCE_MANAGER_H
#define GLOBAL_NATIVE_RESOURCE_MANAGER_H
#include "napi/native_api.h"
#include "raw_file.h"
#ifdef __cplusplus
extern "C" {
#endif
struct NativeResourceManager;
typedef struct NativeResourceManager NativeResourceManager;
NativeResourceManager *OH_ResourceManager_InitNativeResourceManager(napi_env env, napi_value jsResMgr);
void OH_ResourceManager_ReleaseNativeResourceManager(NativeResourceManager *resMgr);
RawFile *OH_ResourceManager_OpenRawFile(const NativeResourceManager *mgr, const char *fileName);
#ifdef __cplusplus
};
#endif
/** @} */
#endif // GLOBAL_NATIVE_RESOURCE_MANAGER_H
package = platform.resource
headers = raw_file_manager.h raw_file.h
\ No newline at end of file
package com.dong.demo013
import androidx.compose.ui.window.ComposeArkUIViewController
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.coroutines.initMainHandler
import platform.ohos.napi_env
import platform.ohos.napi_value
import kotlin.experimental.ExperimentalNativeApi
@OptIn(ExperimentalNativeApi::class, ExperimentalForeignApi::class)
@CName("MainArkUIViewController")
fun MainArkUIViewController(env: napi_env): napi_value {
initMainHandler(env)
return ComposeArkUIViewController(env) {
App()
}
}
package com.dong.demo013
import platform.ohos.OH_LOG_Print
@OptIn(kotlinx.cinterop.ExperimentalForeignApi::class, kotlin.experimental.ExperimentalNativeApi::class)
@CName("hiLogPrintMsg")
fun hiLogPrintMsg(type: UInt, level: UInt, domain: UInt, tag: String, message: String): Int {
return try {
OH_LOG_Print(type, level, domain, tag, message)
} catch (_: Throwable) {
-1
}
}
actual fun pirntSingleHiLog(){
hiLogPrintMsg(0u, 6u, 4660u, "TestTag", "单次日志打印");
}
actual fun pirntAllLevelHiLog(){
// 输出 DEBUG 级别
// LOG_APP = 0 (应用日志类型)
// LOG_DEBUG = 3 (调试级别)
// domain = 0x1234 (任意自定义值,范围0x0000-0xFFFF)
// tag = "TestTag" (自定义标签)
hiLogPrintMsg(0u, 3u, 4660u, "TestTag", "This is a DEBUG log from PrintMsg");
// 输出 INFO 级别
// LOG_INFO = 4 (信息级别)
hiLogPrintMsg(0u, 4u, 4660u, "TestTag", "This is an INFO log from PrintMsg");
// 输出 WARN 级别
// LOG_WARN = 5 (警告级别)
hiLogPrintMsg(0u, 5u, 4660u, "TestTag", "This is a WARN log from PrintMsg");
// 输出 ERROR 级别
// LOG_ERROR = 6 (错误级别)
hiLogPrintMsg(0u, 6u, 4660u, "TestTag", "This is an ERROR log from PrintMsg");
// 输出 FATAL 级别
// LOG_FATAL = 7 (致命级别)
hiLogPrintMsg(0u, 7u, 4660u, "TestTag", "This is a FATAL log from PrintMsg");
}
actual fun pirntRandomHiLog(){
hiLogPrintMsg(0u, 6u, 4660u, "TestTag", "随机日志打印");
}
[versions]
agp = "8.11.2"
# Build & Android
agp = "8.6.0"
android-compileSdk = "36"
android-minSdk = "24"
android-targetSdk = "36"
androidx-activity = "1.12.2"
# AndroidX
androidx-activity = "1.9.2"
androidx-appcompat = "1.7.1"
androidx-collection = "1.5.0"
androidx-constraintlayout = "2.2.1"
androidx-core = "1.17.0"
androidx-core = "1.15.0"
androidx-espresso = "3.7.0"
androidx-lifecycle = "2.9.6"
androidx-material = "1.12.0"
androidx-testExt = "1.3.0"
# Compose
compose = "1.9.4"
composeMultiplatform = "1.9.2-OH.0.1.0-01"
compose-material3 = "1.4.0"
composeMultiplatform = "1.9.2-OH.0.1.2-14"
compose-navigation = "2.9.4-OH.0.1.2-14"
compose-ui-backhandler = "1.9.2-OH.0.1.2-14"
# Kotlin & testing
junit = "4.13.2"
kotlin = "2.2.21-OH.0.1.0-01"
kotlinx-coroutines = "1.8.0-KBA-001"
atomicFu = "0.23.2-KBA-001"
kotlin = "2.2.21-OH.0.1.0-02"
kotlinx-coroutines = "1.10.2-OH-103"
atomicFu = "0.31.0-OH-001"
[libraries]
# ----- Testing -----
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
kotlin-testJunit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
junit = { module = "junit:junit", version.ref = "junit" }
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }
androidx-testExt-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-testExt" }
androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidx-espresso" }
# ----- AndroidX core -----
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
androidx-collection = { module = "androidx.collection:collection", version.ref = "androidx-collection" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout" }
androidx-material = { group = "com.google.android.material", name = "material", version.ref = "androidx-material" }
# ----- Lifecycle & Compose (Android / multiplatform) -----
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity" }
androidx-lifecycle-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" }
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" }
# ----- Compose multiplatform -----
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" }
androidx-lifecycle-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" }
# ----- Kotlin multiplatform / concurrency -----
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
atomicFu = { module = "org.jetbrains.kotlinx:atomicfu", version.ref = "atomicFu" }
# AndroidX compose, only used by android target.
# ----- Compose Android (androidx.compose, Android target only) -----
compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" }
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" }
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose" }
compose-runtime = { module = "androidx.compose.runtime:runtime", version.ref = "compose" }
compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "compose" }
compose-material = { module = "androidx.compose.material:material", version.ref = "compose" }
compose-material3 = { module = "androidx.compose.material:material3", version.ref = "compose-material3" }
# Navigation(Maven 依赖,用于「Navigation 库测试」Demo;版本请与已发布的 navigation-compose 一致)
compose-navigation = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "compose-navigation" }
compose-ui-backhandler = { module = "org.jetbrains.compose.ui:ui-backhandler", version.ref = "compose-ui-backhandler" }
[plugins]
# Android
androidApplication = { id = "com.android.application", version.ref = "agp" }
androidLibrary = { id = "com.android.library", version.ref = "agp" }
# Compose
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "composeMultiplatform" }
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
# Kotlin
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
cocoapods = { id = "org.jetbrains.kotlin.native.cocoapods", version.ref = "kotlin" }
......@@ -6,6 +6,7 @@
"versionName": "1.0.0",
"icon": "$media:layered_image",
"label": "$string:app_name",
"hwasanEnabled": true
//"hwasanEnabled": true
//"asanEnabled": true
}
}
......@@ -5,13 +5,13 @@
"name": "default",
"type": "HarmonyOS",
"material": {
"certpath": "/Users/dongsq/.ohos/config/default_harmonyApp_GthGxfoFAEmCFfCK6Yj5azdigDZk5Ro7gO2DpXptcpU=.cer",
"certpath": "/Users/dongsq/.ohos/config/default_harmonyApp_QJHIBcJpooGCtzydxcmexruNykCONVuY3oaYN7QkN58=.cer",
"keyAlias": "debugKey",
"keyPassword": "0000001B7819C2F0053B9ECCCE6CDCB862E00AE039F04BD559BAFADA3DD213CA03DE0A8CE172CBB9FA209C",
"profile": "/Users/dongsq/.ohos/config/default_harmonyApp_GthGxfoFAEmCFfCK6Yj5azdigDZk5Ro7gO2DpXptcpU=.p7b",
"keyPassword": "0000001B773A687EB8B426063B8C7BC27E68B8FA349E41CAD370B97512B179CE289C3B0DDCD47EB10BCC28",
"profile": "/Users/dongsq/.ohos/config/default_harmonyApp_QJHIBcJpooGCtzydxcmexruNykCONVuY3oaYN7QkN58=.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": "/Users/dongsq/.ohos/config/default_harmonyApp_GthGxfoFAEmCFfCK6Yj5azdigDZk5Ro7gO2DpXptcpU=.p12",
"storePassword": "0000001BAE501502025D5B6E11A6B76286DF01D3499187AF3CBA1A6542FB3FF0BE98A423D21AC88F775752"
"storeFile": "/Users/dongsq/.ohos/config/default_harmonyApp_QJHIBcJpooGCtzydxcmexruNykCONVuY3oaYN7QkN58=.p12",
"storePassword": "0000001BD05AD8D73D2818F53D96C1CA26F228D6422AEA4346EE4BA3141A4FCB956EA8F95DFD223C3CB1F8"
}
}
],
......@@ -19,8 +19,7 @@
{
"name": "default",
"signingConfig": "default",
"targetSdkVersion": "6.0.0(20)",
"compatibleSdkVersion": "6.0.0(20)",
"compatibleSdkVersion": "5.0.5(17)",
"runtimeOS": "HarmonyOS",
"buildOption": {
"nativeCompiler": "BiSheng",
......
......@@ -8,8 +8,10 @@
},
"externalNativeOptions": {
"path": "./src/main/cpp/CMakeLists.txt",
"arguments": "-DOHOS_ENABLE_HWASAN=ON",
//"arguments": "-DOHOS_ENABLE_HWASAN=ON",
//"arguments": "-DOH0S_ENABLE_ASAN=ON",
"cppFlags": "",
"abiFilters": ["arm64-v8a"]
},
},
"buildOptionSet": [
......@@ -20,7 +22,7 @@
"ruleOptions": {
"enable": false,
"files": [
"./obfuscation-rules.txt"
]
}
}
......
......@@ -7,10 +7,9 @@
"ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
"specifiers": {
"compose@libs/compose.har": "compose@libs/compose.har",
"libcompose_arkui_utils.so@../oh_modules/.ohpm/compose@h5xuwfo6vqe0fkvy6j77dndaihorlv4+5iu+h2krdy8=/oh_modules/compose/src/main/cpp/types/libcompose_arkui_utils": "libcompose_arkui_utils.so@../oh_modules/.ohpm/compose@h5xuwfo6vqe0fkvy6j77dndaihorlv4+5iu+h2krdy8=/oh_modules/compose/src/main/cpp/types/libcompose_arkui_utils",
"libcompose_arkui_utils.so@../oh_modules/.ohpm/compose@ma2je3shc8wd1ay4sclgu8prv+0pyungmargnuaabae=/oh_modules/compose/src/main/cpp/types/libcompose_arkui_utils": "libcompose_arkui_utils.so@../oh_modules/.ohpm/compose@ma2je3shc8wd1ay4sclgu8prv+0pyungmargnuaabae=/oh_modules/compose/src/main/cpp/types/libcompose_arkui_utils",
"libentry.so@src/main/cpp/types/libentry": "libentry.so@src/main/cpp/types/libentry",
"libskikobridge.so@../oh_modules/.ohpm/skikobridge@y2fnhawohlg+q+eadhgpdonzjxt7nzphn6xzlfx6ile=/oh_modules/skikobridge/src/main/cpp/types/libskikobridge": "libskikobridge.so@../oh_modules/.ohpm/skikobridge@y2fnhawohlg+q+eadhgpdonzjxt7nzphn6xzlfx6ile=/oh_modules/skikobridge/src/main/cpp/types/libskikobridge",
"skikobridge@libs/skikobridge.har": "skikobridge@libs/skikobridge.har"
"libskikobridge.so@../oh_modules/.ohpm/compose@ma2je3shc8wd1ay4sclgu8prv+0pyungmargnuaabae=/oh_modules/compose/src/main/cpp/types/libskikobridge": "libskikobridge.so@../oh_modules/.ohpm/compose@ma2je3shc8wd1ay4sclgu8prv+0pyungmargnuaabae=/oh_modules/compose/src/main/cpp/types/libskikobridge"
},
"packages": {
"compose@libs/compose.har": {
......@@ -19,13 +18,14 @@
"resolved": "libs/compose.har",
"registryType": "local",
"dependencies": {
"libcompose_arkui_utils.so": "file:./src/main/cpp/types/libcompose_arkui_utils"
"libcompose_arkui_utils.so": "file:./src/main/cpp/types/libcompose_arkui_utils",
"libskikobridge.so": "file:./src/main/cpp/types/libskikobridge"
}
},
"libcompose_arkui_utils.so@../oh_modules/.ohpm/compose@h5xuwfo6vqe0fkvy6j77dndaihorlv4+5iu+h2krdy8=/oh_modules/compose/src/main/cpp/types/libcompose_arkui_utils": {
"libcompose_arkui_utils.so@../oh_modules/.ohpm/compose@ma2je3shc8wd1ay4sclgu8prv+0pyungmargnuaabae=/oh_modules/compose/src/main/cpp/types/libcompose_arkui_utils": {
"name": "libcompose_arkui_utils.so",
"version": "1.0.0",
"resolved": "../oh_modules/.ohpm/compose@h5xuwfo6vqe0fkvy6j77dndaihorlv4+5iu+h2krdy8=/oh_modules/compose/src/main/cpp/types/libcompose_arkui_utils",
"resolved": "../oh_modules/.ohpm/compose@ma2je3shc8wd1ay4sclgu8prv+0pyungmargnuaabae=/oh_modules/compose/src/main/cpp/types/libcompose_arkui_utils",
"registryType": "local"
},
"libentry.so@src/main/cpp/types/libentry": {
......@@ -34,20 +34,11 @@
"resolved": "src/main/cpp/types/libentry",
"registryType": "local"
},
"libskikobridge.so@../oh_modules/.ohpm/skikobridge@y2fnhawohlg+q+eadhgpdonzjxt7nzphn6xzlfx6ile=/oh_modules/skikobridge/src/main/cpp/types/libskikobridge": {
"libskikobridge.so@../oh_modules/.ohpm/compose@ma2je3shc8wd1ay4sclgu8prv+0pyungmargnuaabae=/oh_modules/compose/src/main/cpp/types/libskikobridge": {
"name": "libskikobridge.so",
"version": "0.0.0",
"resolved": "../oh_modules/.ohpm/skikobridge@y2fnhawohlg+q+eadhgpdonzjxt7nzphn6xzlfx6ile=/oh_modules/skikobridge/src/main/cpp/types/libskikobridge",
"resolved": "../oh_modules/.ohpm/compose@ma2je3shc8wd1ay4sclgu8prv+0pyungmargnuaabae=/oh_modules/compose/src/main/cpp/types/libskikobridge",
"registryType": "local"
},
"skikobridge@libs/skikobridge.har": {
"name": "skikobridge",
"version": "1.0.0",
"resolved": "libs/skikobridge.har",
"registryType": "local",
"dependencies": {
"libskikobridge.so": "file:./src/main/cpp/types/libskikobridge"
}
}
}
}
\ No newline at end of file
......@@ -9,7 +9,5 @@
"libentry.so": "file:./src/main/cpp/types/libentry",
// 添加 compose.har 依赖
"compose": "file:./libs/compose.har",
// 添加 skikobridge.har 依赖
"skikobridge": "file:./libs/skikobridge.har"
}
}
\ No newline at end of file
......@@ -11,7 +11,8 @@ endif()
include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include)
find_package(skikobridge)
# 从skikobridge 换成了 compose
find_package(compose)
add_library(entry SHARED napi_init.cpp)
# Link against ComposeApp shared library to resolve exported symbols
......@@ -21,9 +22,16 @@ target_link_libraries(entry PUBLIC libhilog_ndk.z.so)
target_link_libraries(entry PUBLIC libdeviceinfo_ndk.z.so)
target_link_libraries(entry PUBLIC librawfile.z.so)
#target_link_libraries(entry PUBLIC libicu.so)
target_link_libraries(entry PUBLIC skikobridge::skikobridge)
# 按 ABI 选 libkn.so 路径(当前 abiFilters 仅 x86_64 时只构建模拟器)
if(CMAKE_OHOS_ARCH_ABI STREQUAL "x86_64" OR OHOS_ARCH STREQUAL "x86_64")
set(LIBKN_ABI_DIR "x86_64")
else()
set(LIBKN_ABI_DIR "arm64-v8a")
endif()
set_target_properties(ComposeApp PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/arm64-v8a/libkn.so"
IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${LIBKN_ABI_DIR}/libkn.so"
)
target_link_libraries(entry PUBLIC ComposeApp)
# 先链接 libkn.so,再链接 compose里面的skikobridge
target_link_libraries(entry PUBLIC compose::skikobridge)
target_link_libraries(entry PUBLIC ${EGL-lib} ${GLES-lib} ${hilog-lib} ${libace-lib} ${libnapi-lib} ${libuv-lib} libc++_shared.so)
......@@ -63,18 +63,6 @@ typedef struct {
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_ULong;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_demo013_Platform;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_demo013_TimerController;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_Function1;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_demo013_LogController;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_demo013_debug_debug;
......@@ -113,16 +101,10 @@ typedef struct {
} libkn_kref_com_dong_demo013_navigation_Page_Detail;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_demo013_Greeting;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_demo013_LogControllerImpl;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_demo013_OhosPlatform;
} libkn_kref_com_dong_demo013_LogController;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_demo013_TimerControllerImpl;
} libkn_kref_com_dong_demo013_TimerController;
extern void* MainArkUIViewController(void* env);
extern libkn_KInt hiLogPrintMsg(libkn_KUInt type, libkn_KUInt level, libkn_KUInt domain, const char* tag, const char* message);
......@@ -154,6 +136,7 @@ extern const char* androidx_compose_ui_arkui_ArkUIViewController_sendMessage(voi
extern void androidx_compose_ui_arkui_ArkUIViewController_setContext(void* controllerRef, void* context);
extern void androidx_compose_ui_arkui_ArkUIViewController_setEnv(void* controllerRef, void* env);
extern void androidx_compose_ui_arkui_ArkUIViewController_setId(void* controllerRef, const char* id);
extern void androidx_compose_ui_arkui_ArkUIViewController_setLocaleAndStringProvider(void* controllerRef, void* provider);
extern void androidx_compose_ui_arkui_ArkUIViewController_setMessenger(void* controllerRef, void* messenger);
extern void androidx_compose_ui_arkui_ArkUIViewController_setRenderBackendId(void* controllerRef, libkn_KInt backendId);
extern void androidx_compose_ui_arkui_ArkUIViewController_setRootView(void* controllerRef, void* backRootView, void* foreRootView, void* touchableRootView);
......@@ -268,20 +251,11 @@ typedef struct {
libkn_KInt (*com_dong_demo013_navigation_Page_Detail$stableprop_getter)();
libkn_KInt (*com_dong_demo013_navigation_Page_Home$stableprop_getter)();
} navigation;
struct {
libkn_KType* (*_type)(void);
libkn_kref_com_dong_demo013_Greeting (*Greeting)();
const char* (*greet)(libkn_kref_com_dong_demo013_Greeting thiz);
} Greeting;
struct {
libkn_KType* (*_type)(void);
libkn_KBoolean (*get_isRunning)(libkn_kref_com_dong_demo013_LogController thiz);
void (*stop)(libkn_kref_com_dong_demo013_LogController thiz);
} LogController;
struct {
libkn_KType* (*_type)(void);
const char* (*get_name)(libkn_kref_com_dong_demo013_Platform thiz);
} Platform;
struct {
libkn_KType* (*_type)(void);
libkn_KLong (*get_elapsedTime)(libkn_kref_com_dong_demo013_TimerController thiz);
......@@ -290,97 +264,11 @@ typedef struct {
void (*start)(libkn_kref_com_dong_demo013_TimerController thiz);
void (*stop)(libkn_kref_com_dong_demo013_TimerController thiz);
} TimerController;
struct {
libkn_KType* (*_type)(void);
libkn_kref_com_dong_demo013_LogControllerImpl (*LogControllerImpl)();
libkn_KBoolean (*get_isRunning)(libkn_kref_com_dong_demo013_LogControllerImpl thiz);
void (*stop)(libkn_kref_com_dong_demo013_LogControllerImpl thiz);
} LogControllerImpl;
struct {
libkn_KType* (*_type)(void);
libkn_kref_com_dong_demo013_OhosPlatform (*OhosPlatform)();
const char* (*get_name)(libkn_kref_com_dong_demo013_OhosPlatform thiz);
} OhosPlatform;
struct {
libkn_KType* (*_type)(void);
libkn_kref_com_dong_demo013_TimerControllerImpl (*TimerControllerImpl)();
libkn_KLong (*get_elapsedTime)(libkn_kref_com_dong_demo013_TimerControllerImpl thiz);
libkn_KBoolean (*get_isRunning)(libkn_kref_com_dong_demo013_TimerControllerImpl thiz);
void (*reset)(libkn_kref_com_dong_demo013_TimerControllerImpl thiz);
void (*start)(libkn_kref_com_dong_demo013_TimerControllerImpl thiz);
void (*stop)(libkn_kref_com_dong_demo013_TimerControllerImpl thiz);
} TimerControllerImpl;
libkn_KInt (*com_dong_demo013_Greeting$stableprop_getter)();
libkn_KInt (*com_dong_demo013_LogControllerImpl$stableprop_getter)();
libkn_KInt (*com_dong_demo013_OhosPlatform$stableprop_getter)();
libkn_KInt (*com_dong_demo013_TimerControllerImpl$stableprop_getter)();
libkn_KInt (*com_dong_demo013_Greeting$stableprop_getter_)();
libkn_KInt (*com_dong_demo013_LogControllerImpl$stableprop_getter_)();
libkn_KInt (*com_dong_demo013_OhosPlatform$stableprop_getter_)();
libkn_KInt (*com_dong_demo013_TimerControllerImpl$stableprop_getter_)();
libkn_KInt (*com_dong_demo013_Greeting$stableprop_getter__)();
libkn_KInt (*com_dong_demo013_LogControllerImpl$stableprop_getter__)();
libkn_KInt (*com_dong_demo013_OhosPlatform$stableprop_getter__)();
libkn_KInt (*com_dong_demo013_TimerControllerImpl$stableprop_getter__)();
libkn_KInt (*com_dong_demo013_Greeting$stableprop_getter___)();
libkn_KInt (*com_dong_demo013_LogControllerImpl$stableprop_getter___)();
libkn_KInt (*com_dong_demo013_OhosPlatform$stableprop_getter___)();
libkn_KInt (*com_dong_demo013_TimerControllerImpl$stableprop_getter___)();
libkn_KInt (*com_dong_demo013_Greeting$stableprop_getter____)();
libkn_KInt (*com_dong_demo013_LogControllerImpl$stableprop_getter____)();
libkn_KInt (*com_dong_demo013_OhosPlatform$stableprop_getter____)();
libkn_KInt (*com_dong_demo013_TimerControllerImpl$stableprop_getter____)();
libkn_KInt (*com_dong_demo013_Greeting$stableprop_getter_____)();
libkn_KInt (*com_dong_demo013_LogControllerImpl$stableprop_getter_____)();
libkn_KInt (*com_dong_demo013_OhosPlatform$stableprop_getter_____)();
libkn_KInt (*com_dong_demo013_TimerControllerImpl$stableprop_getter_____)();
libkn_KInt (*com_dong_demo013_Greeting$stableprop_getter______)();
libkn_KInt (*com_dong_demo013_LogControllerImpl$stableprop_getter______)();
libkn_KInt (*com_dong_demo013_OhosPlatform$stableprop_getter______)();
libkn_KInt (*com_dong_demo013_TimerControllerImpl$stableprop_getter______)();
libkn_KInt (*com_dong_demo013_Greeting$stableprop_getter_______)();
libkn_KInt (*com_dong_demo013_LogControllerImpl$stableprop_getter_______)();
libkn_KInt (*com_dong_demo013_OhosPlatform$stableprop_getter_______)();
libkn_KInt (*com_dong_demo013_TimerControllerImpl$stableprop_getter_______)();
libkn_KInt (*com_dong_demo013_Greeting$stableprop_getter________)();
libkn_KInt (*com_dong_demo013_LogControllerImpl$stableprop_getter________)();
libkn_KInt (*com_dong_demo013_OhosPlatform$stableprop_getter________)();
libkn_KInt (*com_dong_demo013_TimerControllerImpl$stableprop_getter________)();
libkn_KInt (*com_dong_demo013_Greeting$stableprop_getter_________)();
libkn_KInt (*com_dong_demo013_LogControllerImpl$stableprop_getter_________)();
libkn_KInt (*com_dong_demo013_OhosPlatform$stableprop_getter_________)();
libkn_KInt (*com_dong_demo013_TimerControllerImpl$stableprop_getter_________)();
libkn_KInt (*com_dong_demo013_Greeting$stableprop_getter__________)();
libkn_KInt (*com_dong_demo013_LogControllerImpl$stableprop_getter__________)();
libkn_KInt (*com_dong_demo013_OhosPlatform$stableprop_getter__________)();
libkn_KInt (*com_dong_demo013_TimerControllerImpl$stableprop_getter__________)();
libkn_KInt (*com_dong_demo013_Greeting$stableprop_getter___________)();
libkn_KInt (*com_dong_demo013_LogControllerImpl$stableprop_getter___________)();
libkn_KInt (*com_dong_demo013_OhosPlatform$stableprop_getter___________)();
libkn_KInt (*com_dong_demo013_TimerControllerImpl$stableprop_getter___________)();
void* (*MainArkUIViewController_)(void* env);
libkn_KInt (*com_dong_demo013_Greeting$stableprop_getter____________)();
libkn_KInt (*com_dong_demo013_LogControllerImpl$stableprop_getter____________)();
libkn_KInt (*com_dong_demo013_OhosPlatform$stableprop_getter____________)();
libkn_KInt (*com_dong_demo013_TimerControllerImpl$stableprop_getter____________)();
libkn_KInt (*com_dong_demo013_Greeting$stableprop_getter_____________)();
libkn_KInt (*com_dong_demo013_LogControllerImpl$stableprop_getter_____________)();
libkn_KInt (*com_dong_demo013_OhosPlatform$stableprop_getter_____________)();
libkn_KInt (*com_dong_demo013_TimerControllerImpl$stableprop_getter_____________)();
libkn_kref_com_dong_demo013_Platform (*getPlatform)();
libkn_KInt (*com_dong_demo013_Greeting$stableprop_getter______________)();
libkn_KInt (*com_dong_demo013_LogControllerImpl$stableprop_getter______________)();
libkn_KInt (*com_dong_demo013_OhosPlatform$stableprop_getter______________)();
libkn_KInt (*com_dong_demo013_TimerControllerImpl$stableprop_getter______________)();
libkn_kref_com_dong_demo013_TimerController (*createTimer)();
libkn_KInt (*hiLogPrintMsg_)(libkn_KUInt type, libkn_KUInt level, libkn_KUInt domain, const char* tag, const char* message);
void (*pirntAllLevelHiLog)();
void (*pirntRandomHiLog)();
void (*pirntSingleHiLog)();
libkn_kref_com_dong_demo013_LogController (*startLog)(libkn_KInt speed, libkn_kref_kotlin_Function1 onLogGenerated, libkn_kref_kotlin_Function1 onTimerUpdated);
libkn_KInt (*com_dong_demo013_Greeting$stableprop_getter_______________)();
libkn_KInt (*com_dong_demo013_LogControllerImpl$stableprop_getter_______________)();
libkn_KInt (*com_dong_demo013_OhosPlatform$stableprop_getter_______________)();
libkn_KInt (*com_dong_demo013_TimerControllerImpl$stableprop_getter_______________)();
} demo013;
} dong;
} com;
......@@ -428,6 +316,7 @@ typedef struct {
void (*_Export_ArkUIViewController_setContext)(void* controllerRef, void* context);
void (*_Export_ArkUIViewController_setEnv)(void* controllerRef, void* env);
void (*_Export_ArkUIViewController_setId)(void* controllerRef, const char* id);
void (*_Export_ArkUIViewController_setLocaleAndStringProvider)(void* controllerRef, void* provider);
void (*_Export_ArkUIViewController_setMessenger)(void* controllerRef, void* messenger);
void (*_Export_ArkUIViewController_setRenderBackendId)(void* controllerRef, libkn_KInt backendId);
void (*_Export_ArkUIViewController_setRootView)(void* controllerRef, void* backRootView, void* foreRootView, void* touchableRootView);
......
#include "libkn_api.h"
#include "napi/native_api.h"
#include "hilog/log.h"
#include <rawfile/raw_file_manager.h>
#include <dlfcn.h>
// 避免工程侧未定义 LOG_DOMAIN 时编译失败
#ifndef LOG_DOMAIN
#define LOG_DOMAIN 0x0000
#endif
static napi_value MainArkUIViewController(napi_env env, napi_callback_info info) {
return reinterpret_cast<napi_value>(MainArkUIViewController(env));
}
static napi_value nativeCreateRootNode(napi_env env, napi_callback_info info) {
size_t argc = 2;
napi_value argv[2];
napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
return reinterpret_cast<napi_value>(createRootRenderNode());
}
static napi_value nativeOHRenderNodeDraw(napi_env env, napi_callback_info info) {
size_t argc = 2;
napi_value argv[2];
napi_status status;
status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (status != napi_ok || argc < 2) {
napi_throw_type_error(env, nullptr, "Expected canvas argument");
return nullptr;
}
renderNodeDraw(env, argv[0], argv[1]);
return nullptr;
}
static napi_value nativeOHRenderNotifyRedraw(napi_env env, napi_callback_info info) {
size_t argc = 1;
napi_value argv[1];
napi_status status;
status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (status != napi_ok || argc < 1) {
napi_throw_type_error(env, nullptr, "Expected renderNode argument");
return nullptr;
}
renderNodeNotifyRedraw(env, argv[0]);
return nullptr;
}
static napi_value nativeRegisterNodeConstructor(napi_env env, napi_callback_info info) {
size_t argc = 1;
napi_value argv[1];
napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
if (argc < 1) {
return nullptr;
}
setNodeConstructor(env, argv[0]);
return nullptr;
}
static napi_value nativeSetPixelRatio(napi_env env, napi_callback_info info) {
size_t argc = 1;
napi_value argv[1];
napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
double ratio = 1.0;
napi_get_value_double(env, argv[0], &ratio);
setPixelRatio(ratio);
return nullptr;
}
static napi_value nativeRegisterNodeStatusModifyConstructor(napi_env env, napi_callback_info info) {
size_t argc = 1;
napi_value argv[1];
napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
if (argc < 1) {
return nullptr;
}
buildInstance(env, argv[0]);
return nullptr;
}
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
androidx_compose_ui_arkui_init(env, exports);
napi_property_descriptor desc[] = {
{"MainArkUIViewController", nullptr, MainArkUIViewController, nullptr, nullptr, nullptr, napi_default, nullptr},
{"nativeCreateRootNode", nullptr, nativeCreateRootNode, nullptr, nullptr, nullptr, napi_default, nullptr},
{"nativeOHRenderNodeDraw", nullptr, nativeOHRenderNodeDraw, nullptr, nullptr, nullptr, napi_default, nullptr},
{"nativeOHRenderNotifyRedraw", nullptr, nativeOHRenderNotifyRedraw, nullptr, nullptr, nullptr, napi_default, nullptr},
{"nativeRegisterNodeConstructor", nullptr, nativeRegisterNodeConstructor, nullptr, nullptr, nullptr, napi_default, nullptr},
{"nativeRegisterNodeStatusModifyConstructor", nullptr, nativeRegisterNodeStatusModifyConstructor, nullptr, nullptr, nullptr, napi_default, nullptr },
{"nativeSetPixelRatio", nullptr, nativeSetPixelRatio, nullptr, nullptr, nullptr, napi_default, nullptr},
};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
......
import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
import { AbilityConstant, ConfigurationConstant, UIAbility, Want, abilityAccessCtrl, Permissions } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
......@@ -22,12 +22,20 @@ export default class EntryAbility extends UIAbility {
// Main window is created, set main page for this ability
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
windowStage.loadContent('pages/Index', (err) => {
windowStage.loadContent('pages/Index', async (err) => {
if (err.code) {
hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
return;
}
hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
// 申请剪贴板读权限,便于真机调试时 OH_Pasteboard_GetData 不再 201
try {
const atManager = abilityAccessCtrl.createAtManager();
const permissions: Permissions[] = ['ohos.permission.READ_PASTEBOARD'] as Permissions[];
await atManager.requestPermissionsFromUser(this.context, permissions);
} catch (e) {
hilog.error(DOMAIN, 'testTag', 'requestPermissionsFromUser failed: %{public}s', JSON.stringify(e));
}
});
}
......
import { promptAction } from '@kit.ArkUI';
interface ButtonArgs {
text: string
backgroundColor: string
}
@Builder
export function buttonBuilder(args: ButtonArgs) {
button()
}
@Component
export struct button {
@Consume compose_args: ButtonArgs
build() {
Column() {
Button(this.compose_args.text).backgroundColor(this.compose_args.backgroundColor).width('100%').onClick(e => {
console.log(`Button Clicked: ${this.compose_args.text}`)
}).height('70%')
Stack().height('10%')
}
}
}
interface TextArgs {
id: string
text: string
backgroundColor: string
}
@Builder
export function textBuilder(args: TextArgs) {
text()
}
@Component
export struct text {
@Consume compose_args: TextArgs
build() {
Text(this.compose_args.id + " " + this.compose_args.text)
.backgroundColor(this.compose_args.backgroundColor)
.width('100%')
.height('100%')
.borderRadius('5vp')
.onClick(e => {
console.log(`Text Clicked: ${JSON.stringify(this.compose_args)}`)
})
}
}
@Builder
export function labelBuilder(args: ButtonArgs) {
label()
}
@Component
export struct label {
@Consume compose_args: ButtonArgs
build() {
Column() {
Button(`+ ${this.compose_args.text}`, { type: ButtonType.Normal })
.backgroundColor(this.compose_args.backgroundColor)
.width('100%')
.height('50%')
.borderRadius(2)
.onClick(e => {
promptAction.showToast({
message: this.compose_args.text
})
})
Text(this.compose_args.text).backgroundColor(Color.Orange).width('100%').height('50%')
}
}
}
@Builder
export function layerBuilder(args: ButtonArgs) {
layer()
}
@Component
export struct layer {
@Consume compose_args: ButtonArgs
build() {
Stack({ alignContent: Alignment.BottomEnd }) {
Text(this.compose_args.text)
}
.width('100%')
.height('100%')
.backgroundColor(this.compose_args.backgroundColor)
.onClick(() => {
promptAction.showToast({ message: `${this.compose_args.text} Clicked` })
})
.onTouch(e => {
console.log(`layer ${this.compose_args.text} onTouch`)
})
}
}
@Builder
export function buttonWrapContentBuilder(args: ButtonArgs) {
buttonWrapContent()
}
@Component
export struct buttonWrapContent {
@Consume compose_args: ButtonArgs
build() {
Column() {
Button(this.compose_args.text).backgroundColor(this.compose_args.backgroundColor).width('100%').onClick(e => {
console.log(`Button Clicked: ${this.compose_args.text}`)
})
Text(this.compose_args.text).backgroundColor(this.compose_args.backgroundColor).width('100%').onClick(e => {
console.log(`Text Clicked: ${this.compose_args.text}`)
})
}
}
}
interface InputArgs {
text: string
}
@Builder
export function textInputBuilder(args: InputArgs) {
textInput()
}
@Component
export struct textInput {
@Consume compose_args: InputArgs
build() {
Column() {
TextInput({ text: $$this.compose_args.text }).onChange(value => {
console.log(`/// onChange: ${value}`)
})
Text("ArkUI组件更新:").fontColor(Color.Gray).margin({ top: 30 })
Text(this.compose_args.text)
.width('100%')
.padding(10)
.border({ width: 1, color: Color.Gray })
}.alignItems(HorizontalAlign.Start)
}
}
@Builder
export function verticalListBuilder(args?: object) {
verticalList()
}
@Component
export struct verticalList {
build() {
Row() {
List() {
ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (item: number, index) => {
ListItem() {
Button({ type: ButtonType.Normal }) {
Text(`Ark Button ${index}`)
.fontSize(16)
.fontColor(Color.White)
}
.borderRadius(2)
.height('100vp')
.padding(10)
}.padding(10)
})
}.listDirection(Axis.Vertical).height('100%').width('40%')
Stack().width('20%').height('100%').borderWidth(1)
Scroll() {
Column() {
ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (item: number, index) => {
ListItem() {
Button({ type: ButtonType.Normal }) {
Text(`Ark Button ${index}`).fontSize(16).fontColor(Color.White)
}
.borderRadius(2).height('100vp').padding(10)
}.padding(10)
})
}
}.scrollable(ScrollDirection.Vertical).height('100%').width('40%')
}
}
}
@Builder
export function horizontalListBuilder(args?: object) {
horizontalList()
}
@Component
export struct horizontalList {
build() {
Column() {
List() {
ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (item: number, index) => {
ListItem() {
Button({ type: ButtonType.Normal }) {
Text(`Ark Button ${index}`).fontSize(16).fontColor(Color.White)
}
.borderRadius(2).height('100vp')
}.padding(10)
})
}.listDirection(Axis.Horizontal).height('40%').width('100%')
Stack().width('100%').height('20%').borderWidth(1)
Scroll() {
Row() {
ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (item: number, index) => {
ListItem() {
Button({ type: ButtonType.Normal }) {
Text(`Ark Button ${index}`).fontSize(16).fontColor(Color.White)
}
.borderRadius(2).height('100vp')
}.padding(10)
})
}
}.scrollable(ScrollDirection.Horizontal).height('40%').width('100%')
}
}
}
import { registerComposeInteropBuilder } from 'compose/src/main/ets/compose/ArkUIView';
import {
buttonBuilder,
textBuilder,
labelBuilder,
textInputBuilder,
buttonWrapContentBuilder,
layerBuilder,
verticalListBuilder,
horizontalListBuilder,
} from './ComposeInterops';
export function registerComposeInteropBuilders() {
registerComposeInteropBuilder('button', buttonBuilder)
registerComposeInteropBuilder('label', labelBuilder)
registerComposeInteropBuilder('buttonWrapContent', buttonWrapContentBuilder)
registerComposeInteropBuilder('textInput', textInputBuilder)
registerComposeInteropBuilder('layer', layerBuilder)
registerComposeInteropBuilder('text', textBuilder)
registerComposeInteropBuilder('verticalList', verticalListBuilder)
registerComposeInteropBuilder('horizontalList', horizontalListBuilder)
}
import { ArkUIViewController, Compose } from 'compose';
import { hilog } from '@kit.PerformanceAnalysisKit';
import nativeApi from 'libentry.so';
import { registerComposeInteropBuilders } from './ComposeSample';
registerComposeInteropBuilders();
const DOMAIN = 0x0000;
@Entry
......@@ -38,7 +36,8 @@ struct Index {
Compose({
controller: this.controller,
libraryName: 'entry',
onBackPressed: () => this.controller!.onBackPress()
onBackPressed: () => false
// onBackPressed: () => this.controller!.onBackPress() 不能使用这个 会出现无限循环
})
} else {
Text(this.errorMessage)
......@@ -54,7 +53,7 @@ struct Index {
}
}
onBackPressed(): boolean {
onBackPress(): boolean {
return this.controller ? this.controller.onBackPress() : false;
}
}
......@@ -10,6 +10,28 @@
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"requestPermissions": [
{
"name": "ohos.permission.VIBRATE",
"reason": "$string:vibrate_permission_reason",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "inuse"
}
},
{
"name": "ohos.permission.READ_PASTEBOARD",
"reason": "$string:read_pasteboard_permission_reason",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "inuse"
}
}
],
"abilities": [
{
"name": "EntryAbility",
......
......@@ -11,6 +11,14 @@
{
"name": "EntryAbility_label",
"value": "label"
},
{
"name": "vibrate_permission_reason",
"value": "用于触控反馈功能"
},
{
"name": "read_pasteboard_permission_reason",
"value": "用于读取系统剪贴板内容以支持粘贴功能"
}
]
}
\ No newline at end of file
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="450dp"
android:height="450dp"
android:viewportWidth="64"
android:viewportHeight="64">
<path
android:pathData="M56.25,18V46L32,60 7.75,46V18L32,4Z"
android:fillColor="#6075f2"/>
<path
android:pathData="m41.5,26.5v11L32,43V60L56.25,46V18Z"
android:fillColor="#6b57ff"/>
<path
android:pathData="m32,43 l-9.5,-5.5v-11L7.75,18V46L32,60Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="23.131"
android:centerY="18.441"
android:gradientRadius="42.132"
android:type="radial">
<item android:offset="0" android:color="#FF5383EC"/>
<item android:offset="0.867" android:color="#FF7F52FF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M22.5,26.5 L32,21 41.5,26.5 56.25,18 32,4 7.75,18Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="44.172"
android:startY="4.377"
android:endX="17.973"
android:endY="34.035"
android:type="linear">
<item android:offset="0" android:color="#FF33C3FF"/>
<item android:offset="0.878" android:color="#FF5383EC"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="m32,21 l9.526,5.5v11L32,43 22.474,37.5v-11z"
android:fillColor="#000000"/>
</vector>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="450dp"
android:height="450dp"
android:viewportWidth="64"
android:viewportHeight="64">
<path
android:pathData="M56.25,18V46L32,60 7.75,46V18L32,4Z"
android:fillColor="#6075f2"/>
<path
android:pathData="m41.5,26.5v11L32,43V60L56.25,46V18Z"
android:fillColor="#6b57ff"/>
<path
android:pathData="m32,43 l-9.5,-5.5v-11L7.75,18V46L32,60Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="23.131"
android:centerY="18.441"
android:gradientRadius="42.132"
android:type="radial">
<item android:offset="0" android:color="#FF5383EC"/>
<item android:offset="0.867" android:color="#FF7F52FF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M22.5,26.5 L32,21 41.5,26.5 56.25,18 32,4 7.75,18Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="44.172"
android:startY="4.377"
android:endX="17.973"
android:endY="34.035"
android:type="linear">
<item android:offset="0" android:color="#FF33C3FF"/>
<item android:offset="0.878" android:color="#FF5383EC"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="m32,21 l9.526,5.5v11L32,43 22.474,37.5v-11z"
android:fillColor="#000000"/>
</vector>
\ No newline at end of file
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