You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Compose Multiplatform跨Android/iOS共享Lottie资源的生产级方案及桥接实现问询

Compose Multiplatform跨Android/iOS共享Lottie资源的生产级方案及桥接实现问询

嘿,我刚好在几个生产级Compose Multiplatform项目里解决过完全一样的问题——既要把Lottie动画文件只存一份在common层,又要让Android和iOS用原生Lottie库渲染,还要配合你现有的expect/actual桥接方案。咱们一步步拆解:

一、先搞定Gradle构建配置,让两端自动复用Common层资源

你的现有目录结构已经很合理了,只需要在composeApp模块的build.gradle.kts里加几行配置,就能让Android和iOS自动读取commonMain/composeResources/lottie下的文件,完全不用复制:

Android端配置(映射到Assets目录)

在android代码块里的sourceSets中,把Common层的Lottie目录映射为Android的Assets子目录,这样Android原生Lottie库可以直接通过Assets路径访问:

android {
    sourceSets {
        main {
            // 把Common层的lottie目录映射到Android Assets的根目录(或子目录,按需调整)
            assets.srcDirs += file("src/commonMain/composeResources/lottie")
        }
    }
}

配置后Android端的Assets目录会直接引用Common层的文件(无复制操作),原生Lottie可以直接通过文件名访问。

iOS端配置(打包到App Bundle)

在kotlin代码块的Native Target配置里,把Common层的Lottie目录添加为iOS的资源目录,构建时会自动把这些文件打包到iOS App的Bundle中:

kotlin {
    targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
        binaries.all {
            // 告诉Kotlin Native把Common层的lottie目录作为资源目录
            freeCompilerArgs += "-Xresource-dir=${project.file("src/commonMain/composeResources/lottie").absolutePath}"
        }
    }
    // 或者更简洁的方式,直接给iOS Main配置资源源
    sourceSets["iosMain"].resources.srcDirs += file("src/commonMain/composeResources/lottie")
}

配置后iOS端的App Bundle会包含Common层的Lottie文件,SwiftUI可以直接通过文件名加载。

二、Android端Actual实现(用Lottie-Compose)

基于你定义的expect函数,Android端的actual实现直接用官方的Lottie-Compose库,因为资源已经映射到Assets,直接通过文件名加载即可:

// androidMain下的实现文件
@Composable
actual fun LottieAnimView(assetName: String, modifier: Modifier) {
    val composition by rememberLottieComposition(
        LottieCompositionSpec.Asset(assetName)
    )
    LottieAnimation(
        composition = composition,
        modifier = modifier,
        iterations = LottieConstants.IterateForever
    )
}

这里的assetName直接传"animation.json"就行,和Common层的文件名完全对应。

三、iOS端Actual实现(含SwiftUI桥接)

iOS端需要通过Kotlin/Native桥接调用SwiftUI的Lottie视图,分两步走:

1. Kotlin端的Actual实现

在iosMain下写actual函数,用UIKitView包裹我们桥接的SwiftUI Lottie视图:

// iosMain下的实现文件
@Composable
actual fun LottieAnimView(assetName: String, modifier: Modifier) {
    UIKitView(
        modifier = modifier,
        factory = {
            // 桥接Swift端的Lottie宿主控制器,传入资源文件名
            LottieHostingController(assetName: assetName).view
        }
    )
}

2. Swift端的桥接代码

在iosMain/swift目录下创建LottieHostingController.swift,用SwiftUI的Lottie库实现渲染(记得先通过CocoaPods添加Lottie依赖到iOS目标):

import UIKit
import SwiftUI
import Lottie

// 包裹SwiftUI视图的UIKit控制器,用于Kotlin/Native桥接
class LottieHostingController: UIHostingController<LottieSwiftUIView> {
    init(assetName: String) {
        super.init(rootView: LottieSwiftUIView(assetName: assetName))
    }
    
    @objc required dynamic init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

// SwiftUI的Lottie视图实现
struct LottieSwiftUIView: View {
    let assetName: String
    
    var body: some View {
        LottieView(animation: .named(assetName))
            .looping()
            .scaledToFit()
    }
}

这里的assetName同样直接传"animation.json",和Common层的文件名保持一致即可。

四、Common层调用示例

现在在CommonMain的Composable里,你可以直接调用这个跨平台的Lottie视图,完全不用关心两端的实现细节:

// commonMain下的页面Composable
@Composable
fun HomeScreen() {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        LottieAnimView(
            assetName = "animation.json",
            modifier = Modifier.size(200.dp)
        )
    }
}

生产环境注意事项

  1. 文件名大小写一致性:iOS对文件名大小写敏感,Android不敏感,所以Common层的文件名要统一大小写,比如全小写或固定驼峰,避免两端加载失败。
  2. 资源验证:可以在Gradle里加自定义任务,检查Common层的Lottie文件是否存在,构建时提前报错,避免运行时问题。
  3. Lottie版本对齐:确保Android的lottie-compose和iOS的Lottie Swift库版本尽量接近,避免动画渲染效果不一致。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 14:24:32