ovCompose创建项目
一、插件安装
# IDE 插件市场(推荐)
Android Studio → Settings → Plugins → Marketplace → 搜索 "ovCompose"
// Gradle 插件配置 (settings.gradle.kts)
pluginManagement {
repositories {
mavenCentral()
google()
gradlePluginPortal()
// 腾讯 Maven 仓库
maven("https://mirrors.tencent.com/nexus/repository/maven-public/")
}
}
二、创建项目
方式一:使用 IDE 模板(推荐)
-
File → New → New Project
-
选择 "ovCompose Multiplatform" 模板
-
配置项目:
-
Project name:
MyOvComposeApp -
Package name:
com.example.myapp -
Platforms: ☑ Android ☑ iOS ☑ HarmonyOS
-
UI Framework: Compose Multiplatform (默认)
-
-
点击 Finish,等待 Gradle 同步(约 5-10 分钟)
方式二:命令行创建
# 使用 ovCompose CLI(需先安装)
npx @tencent/ovcompose-cli create myapp --platforms=android,ios,harmony
cd myapp
./gradlew clean build
三、项目结构详解
myapp/
├── composeApp/ # 共享 Compose 代码
│ ├── src/
│ │ ├── commonMain/kotlin/ # 跨平台代码(UI + 逻辑)
│ │ │ ├── App.kt # 应用入口
│ │ │ ├── ui/
│ │ │ │ ├── screens/ # 页面级 Composable
│ │ │ │ ├── components/ # 可复用组件
│ │ │ │ └── theme/ # 主题配置
│ │ │ ├── viewmodel/ # 共享 ViewModel
│ │ │ └── data/ # 数据层(Repository、API)
│ │ ├── androidMain/kotlin/ # Android 特定代码(极少)
│ │ ├── iosMain/kotlin/ # iOS 特定代码(桥接)
│ │ └── harmonyMain/kotlin/ # 鸿蒙特定代码(桥接)
│ └── build.gradle.kts
├── androidApp/ # Android 壳工程
│ └── src/main/
│ └── MainActivity.kt # 启动 ovCompose
├── iosApp/ # iOS Xcode 工程
│ ├── iosApp.xcodeproj
│ └── ContentView.swift # 桥接 SwiftUI
├── harmonyApp/ # 鸿蒙 DevEco 工程
│ ├── entry/src/main/ets/
│ │ └── pages/Index.ets # 桥接 ArkTS
│ └── build-profile.json5
└── build.gradle.kts # 根构建配置
四、核心开发流程
1. 配置共享模块 (composeApp/build.gradle.kts)
plugins {
kotlin("multiplatform")
id("org.jetbrains.compose")
id("org.jetbrains.kotlin.plugin.compose")
id("com.tencent.ovcompose") version "1.0.2" // ovCompose 核心插件
}
kotlin {
// Android 目标
androidTarget {
compilations.all {
kotlinOptions {
jvmTarget = "17"
}
}
}
// iOS 目标
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "ComposeApp"
isStatic = true // ovCompose 推荐静态链接
}
}
// 鸿蒙目标(ovCompose 扩展)
harmonyOS {
// 使用 KuiklyBase 引擎作为渲染后端
engine = KuiklyBaseEngine(
// 可选:自定义渲染参数
renderMode = RenderMode.GPU_ACCELERATED,
enableInspector = true // 开发时启用布局检查
)
// 鸿蒙 API 级别
compileSdk = 5
minSdk = 5
}
sourceSets {
val commonMain by getting {
dependencies {
// Compose 基础
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3) // Material Design 3
implementation(compose.ui)
implementation(compose.components.resources)
implementation(compose.components.uiToolingPreview)
// ovCompose 鸿蒙适配库
implementation("com.tencent.ovcompose:core:1.0.2")
implementation("com.tencent.ovcompose:navigation:1.0.2")
implementation("com.tencent.ovcompose:material3-harmony:1.0.2")
// KMP 生态
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1")
implementation("io.ktor:ktor-client-core:3.1.0")
implementation("media.kamel:kamel-image:1.0.3") // 图片加载
}
}
val harmonyMain by getting {
dependencies {
// 鸿蒙特定依赖
implementation("com.tencent.ovcompose:harmony-bridge:1.0.2")
}
}
}
}
// ovCompose 专用配置
ovCompose {
// 鸿蒙资源映射
harmonyResources {
copyFrom(commonMain.resources)
// 自动转换 Compose 资源为鸿蒙资源格式
autoConvertSvg = true
}
// 性能优化
buildOptimization {
enableR8ForHarmony = true // 鸿蒙端代码压缩
shrinkSkia = true // 裁剪 Skia 库(减少 3-5MB)
}
}
2. 编写跨平台 UI 入口
// composeApp/src/commonMain/kotlin/App.kt
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.*
import com.tencent.ovcompose.navigation.OvNavHost
import com.tencent.ovcompose.navigation.rememberOvNavigator
@Composable
fun App() {
// ovCompose 提供的跨平台导航器
val navigator = rememberOvNavigator()
MaterialTheme(
colorScheme = if (isSystemInDarkTheme()) darkColorScheme() else lightColorScheme()
) {
OvNavHost(
navigator = navigator,
startDestination = "/home"
) {
// 定义路由
composable("/home") { HomeScreen() }
composable("/user/{id}") { backStackEntry ->
val userId = backStackEntry.arguments?.getString("id")!!
UserDetailScreen(userId)
}
composable("/settings") { SettingsScreen() }
}
}
}
3. 开发具体页面
// composeApp/src/commonMain/kotlin/ui/screens/HomeScreen.kt
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.tencent.ovcompose.ui.pullrefresh.*
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun HomeScreen(
viewModel: HomeViewModel = koinViewModel()
) {
val uiState by viewModel.uiState.collectAsState()
val pullRefreshState = rememberPullRefreshState(
refreshing = uiState.isLoading,
onRefresh = { viewModel.refresh() }
)
Scaffold(
topBar = {
TopAppBar(
title = { Text("ovCompose 示例") },
actions = {
IconButton(onClick = { /* 搜索 */ }) {
Icon(Icons.Default.Search, contentDescription = "搜索")
}
}
)
},
floatingActionButton = {
ExtendedFloatingActionButton(
onClick = { /* 新建 */ },
icon = { Icon(Icons.Default.Add, null) },
text = { Text("新建") }
)
}
) { padding ->
Box(
modifier = Modifier
.padding(padding)
.pullRefresh(pullRefreshState)
) {
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
items(
items = uiState.items,
key = { it.id }
) { item ->
ItemCard(
item = item,
onClick = { /* 点击处理 */ }
)
}
}
// 下拉刷新指示器(ovCompose 已适配鸿蒙)
PullRefreshIndicator(
refreshing = uiState.isLoading,
state = pullRefreshState,
modifier = Modifier.align(Alignment.TopCenter)
)
}
}
}
@Composable
private fun ItemCard(
item: Item,
onClick: () -> Unit
) {
Card(
onClick = onClick,
modifier = Modifier.fillMaxWidth()
) {
Row(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
// 异步图片(ovCompose 自动适配鸿蒙图片加载)
AsyncImage(
model = item.imageUrl,
contentDescription = null,
modifier = Modifier.size(64.dp),
placeholder = painterResource(Res.drawable.placeholder)
)
Column {
Text(
text = item.title,
style = MaterialTheme.typography.titleMedium
)
Text(
text = item.description,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
}
4. 编写 ViewModel(共享逻辑层)
// composeApp/src/commonMain/kotlin/viewmodel/HomeViewModel.kt
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
class HomeViewModel(
private val repository: ItemRepository
) : ViewModel() {
private val _uiState = MutableStateFlow(HomeUiState())
val uiState: StateFlow<HomeUiState> = _uiState.asStateFlow()
init {
loadData()
}
fun refresh() {
loadData(forceRefresh = true)
}
private fun loadData(forceRefresh: Boolean = false) {
viewModelScope.launch {
_uiState.update { it.copy(isLoading = true) }
try {
val items = repository.getItems(forceRefresh)
_uiState.update {
it.copy(
items = items,
isLoading = false,
error = null
)
}
} catch (e: Exception) {
_uiState.update {
it.copy(
isLoading = false,
error = e.message
)
}
}
}
}
}
data class HomeUiState(
val items: List<Item> = emptyList(),
val isLoading: Boolean = false,
val error: String? = null
)
5. 平台端桥接代码
Android 端
// androidApp/src/main/java/MainActivity.kt
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import com.example.myapp.composeApp.App
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
// 标准 CMP 启动方式
setContent {
App()
}
}
}
iOS 端(Swift 桥接)
// iosApp/iosApp/ContentView.swift
import SwiftUI
import ComposeApp
struct ContentView: View {
var body: some View {
// ovCompose 提供的 UIViewController 包装
OvComposeViewControllerRepresentable {
// 可配置启动参数
initialRoute: "/home"
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
鸿蒙端(ArkTS 桥接)
// harmonyApp/entry/src/main/ets/pages/Index.ets
import { OvComposeEngine } from '@tencent/ovcompose-harmony'
import { router } from '@kit.ArkUI'
@Entry
@Component
struct Index {
@State engineReady: boolean = false
aboutToAppear() {
// 初始化 ovCompose 引擎
// 内部复用 KuiklyBase 运行时
OvComposeEngine.getInstance().initialize({
// 指向 ComposeApp 模块
moduleName: "ComposeApp",
entryPoint: "AppKt.App",
// 生命周期绑定
lifecycleOwner: this,
// 性能配置
renderConfig: {
useGPU: true,
enableVSync: true,
maxFPS: 120
},
// 调试配置(开发阶段)
debugConfig: {
enableLayoutInspector: true,
showPerformanceOverlay: false
},
// 初始化完成回调
onReady: () => {
this.engineReady = true
}
})
}
aboutToDisappear() {
// 释放引擎资源
OvComposeEngine.getInstance().destroy()
}
build() {
Stack() {
if (this.engineReady) {
// ovCompose 渲染视图组件
OvComposeView()
.width('100%')
.height('100%')
// 鸿蒙系统手势配置
.gesture(
GestureGroup(
GestureMode.Parallel,
SwipeGesture({ direction: SwipeDirection.Left })
.onAction((event) => {
// 处理侧滑返回
router.back()
})
)
)
} else {
// 加载中
LoadingProgress()
.width(50)
.height(50)
.color(Color.Blue)
}
}
.width('100%')
.height('100%')
}
}
五、鸿蒙特定功能适配
1. 调用鸿蒙原生 API(expect/actual)
// commonMain - 声明期望
expect class PlatformVibrator {
fun vibrate(durationMs: Long)
fun cancel()
}
// harmonyMain - 鸿蒙实现
import ohos.vibrator.vibrator
import ohos.sensor.agent.CategoryOrientation
actual class PlatformVibrator actual constructor() {
actual fun vibrate(durationMs: Long) {
// 调用鸿蒙系统振动 API
vibrator.start({
type: "time",
duration: durationMs
})
}
actual fun cancel() {
vibrator.stop()
}
}
2. 处理鸿蒙生命周期
// harmonyMain/kotlin/HarmonyLifecycle.kt
import com.tencent.ovcompose.harmony.lifecycle.*
@Composable
fun rememberHarmonyLifecycle(): HarmonyLifecycleOwner {
val lifecycle = rememberHarmonyLifecycleOwner()
DisposableEffect(lifecycle) {
// 监听鸿蒙页面生命周期
val observer = HarmonyLifecycleEventObserver { event ->
when (event) {
HarmonyLifecycle.Event.ON_SHOW -> { /* 页面显示 */ }
HarmonyLifecycle.Event.ON_HIDE -> { /* 页面隐藏 */ }
HarmonyLifecycle.Event.ON_DESTROY -> { /* 页面销毁 */ }
}
}
lifecycle.addObserver(observer)
onDispose {
lifecycle.removeObserver(observer)
}
}
return lifecycle
}
六、构建与运行
1. 同步项目
./gradlew clean :composeApp:generateHarmonySources
./gradlew build
2. 运行各端
# Android
./gradlew :androidApp:installDebug
# iOS(需 Xcode 15+)
./gradlew :composeApp:assembleIOSBinaries
# 然后在 Xcode 中打开 iosApp.xcodeproj 运行
# 鸿蒙(需 DevEco Studio 5.0+)
./gradlew :composeApp:assembleHarmonyRelease
# 使用 DevEco Studio 打开 harmonyApp 目录,点击 Run
3. 鸿蒙真机/模拟器调试
# 安装 HAP 包到鸿蒙设备
hdc install entry/build/outputs/hap/release/entry-release-signed.hap
# 查看日志(类似 adb logcat)
hdc hilog | grep ovCompose
七、性能优化建议
|
优化项 |
配置 |
效果 |
|
Skia 裁剪 |
|
包体积 -3~5MB |
|
R8 压缩 |
|
代码体积 -30% |
|
图片格式 |
使用鸿蒙 HSP 格式 |
内存占用 -20% |
|
懒加载 |
|
滚动流畅度提升 |
|
状态管理 |
使用 |
页面恢复速度优化 |
八、常见问题排查
|
问题 |
原因 |
解决 |
|
鸿蒙端白屏 |
Skia 初始化失败 |
检查 GPU 加速配置,模拟器需关闭 GPU |
|
中文显示方框 |
字体未适配 |
添加 |
|
网络请求失败 |
鸿蒙权限未配置 |
在 |
|
路由跳转卡顿 |
主线程阻塞 |
使用 |
|
内存泄漏 |
生命周期未绑定 |
确保使用 |
总结
ovCompose 的开发体验与标准 Compose Multiplatform 几乎一致,主要差异在于:
配置层:添加 harmonyOS { } 目标和 ovCompose 插件
桥接层:鸿蒙端使用 ArkTS 初始化 OvComposeEngine
运行时:底层复用 KuiklyBase 的鸿蒙原生渲染能力
对于熟悉 CMP 的开发者,迁移成本极低 —— 主要是增加鸿蒙构建配置和桥接代码,业务逻辑和 UI 代码完全复用。
更多推荐


所有评论(0)