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

如何将第三方Android/iOS SDK集成到KMM并封装为通用模块?

在KMM中封装双端第三方SDK(以Zego SDK为例)

针对你用KMM开发交友App,需要集成仅支持Android/iOS的第三方SDK的场景,核心方案是利用KMM的expect/actual机制封装平台特定实现,在Common层提供统一接口供业务逻辑调用。以下是具体步骤:

一、在Common模块定义统一接口

先在commonMain下定义expect类和业务所需的核心接口,对齐两端SDK的API设计(因为你提到两端API基本一致,所以接口可以完全统一):

// commonMain/kotlin/com/yourapp/ZegoService.kt
expect class ZegoService {
    // 初始化SDK
    fun initialize(appId: Long, appSign: String)
    // 登录房间(异步转为协程)
    suspend fun loginRoom(roomId: String, userId: String): Boolean
    // 发送房间消息
    fun sendMessage(roomId: String, message: String)
    // 设置消息监听
    fun setMessageListener(listener: ZegoMessageListener)
    // 可选:销毁SDK实例
    fun destroy()
}

// 消息回调接口
interface ZegoMessageListener {
    fun onMessageReceived(roomId: String, userId: String, message: String)
}

二、Android端实现Actual类

  1. 先在Android模块的build.gradle.kts中添加Zego Android SDK依赖:
// androidApp/build.gradle.kts
dependencies {
    implementation("im.zego:zego-express-engine:latest.release")
}
  1. 在androidMain下实现actual类,直接调用Android SDK的API,注意将回调转为Kotlin协程:
// androidMain/kotlin/com/yourapp/ZegoService.kt
import im.zego.zegoexpress.ZegoExpressEngine
import im.zego.zegoexpress.callback.ZegoRoomCallback
import im.zego.zegoexpress.callback.ZegoRoomMessageListener
import im.zego.zegoexpress.entity.ZegoScenario
import im.zego.zegoexpress.entity.ZegoUser
import kotlinx.coroutines.suspendCancellableCoroutine

actual class ZegoService {
    private var engine: ZegoExpressEngine? = null

    actual fun initialize(appId: Long, appSign: String) {
        engine = ZegoExpressEngine.createEngine(appId, appSign, true, ZegoScenario.GENERAL, null)
    }

    actual suspend fun loginRoom(roomId: String, userId: String): Boolean {
        return suspendCancellableCoroutine { cont ->
            val user = ZegoUser(userId)
            engine?.loginRoom(roomId, user, object : ZegoRoomCallback {
                override fun onRoomLoginSuccess() {
                    cont.resume(true)
                }

                override fun onRoomLoginError(errorCode: Int, message: String?) {
                    cont.resume(false)
                }
            }) ?: cont.resume(false)
        }
    }

    actual fun sendMessage(roomId: String, message: String) {
        engine?.sendRoomMessage(roomId, message) { errorCode, _, _ ->
            // 可在这里处理发送结果,比如通知业务层
        }
    }

    actual fun setMessageListener(listener: ZegoMessageListener) {
        engine?.setRoomMessageListener(object : ZegoRoomMessageListener {
            override fun onRoomMessageReceived(roomId: String, messages: MutableList<*>?) {
                @Suppress("UNCHECKED_CAST")
                (messages as? List<im.zego.zegoexpress.entity.ZegoRoomMessage>)?.forEach { msg ->
                    listener.onMessageReceived(roomId, msg.user.userID, msg.message)
                }
            }
        })
    }

    actual fun destroy() {
        ZegoExpressEngine.destroyEngine(null)
        engine = null
    }
}

三、iOS端实现Actual类

  1. 在iOS模块的Podfile中添加Zego iOS SDK依赖,然后执行pod install:
# iosApp/Podfile
target 'iosApp' do
  use_frameworks!
  pod 'ZegoExpressEngine'
end
  1. 在iosMain下实现actual类,调用iOS SDK的API,同样处理协程和回调转换:
// iosMain/kotlin/com/yourapp/ZegoService.kt
import kotlinx.coroutines.suspendCancellableCoroutine
import platform.ZegoExpressEngine.ZegoExpressEngine
import platform.ZegoExpressEngine.ZegoRoomMessageDelegateProtocol
import platform.ZegoExpressEngine.ZegoScenario
import platform.ZegoExpressEngine.ZegoUser

actual class ZegoService {
    private var engine: ZegoExpressEngine? = null

    actual fun initialize(appId: Long, appSign: String) {
        engine = ZegoExpressEngine.createEngineWithAppID(
            appID = appId.toULong(),
            appSign = appSign,
            isTestEnv = true,
            scenario = ZegoScenario.ZegoScenarioGeneral,
            delegate = null
        )
    }

    actual suspend fun loginRoom(roomId: String, userId: String): Boolean {
        return suspendCancellableCoroutine { cont ->
            val user = ZegoUser.userWithUserID(userId, userName = userId)
            engine?.loginRoom(roomId, user = user, config = null) { error, _ ->
                cont.resume(error == 0)
            } ?: cont.resume(false)
        }
    }

    actual fun sendMessage(roomId: String, message: String) {
        engine?.sendRoomMessage(roomId, message) { error, _ ->
            // 处理发送结果
        }
    }

    actual fun setMessageListener(listener: ZegoMessageListener) {
        engine?.setRoomMessageDelegate(object : ZegoRoomMessageDelegateProtocol {
            override fun onRoomMessageReceived(roomID: String, messages: List<*>?) {
                @Suppress("UNCHECKED_CAST")
                (messages as? List<platform.ZegoExpressEngine.ZegoRoomMessage>)?.forEach { msg ->
                    listener.onMessageReceived(roomID, msg.user.userID, msg.message)
                }
            }
        })
    }

    actual fun destroy() {
        ZegoExpressEngine.destroyEngine(null)
        engine = null
    }
}

四、在业务逻辑中统一调用

封装完成后,你可以在Common层或业务模块中直接使用ZegoService,完全不用关心平台差异:

// commonMain/kotlin/com/yourapp/chat/ChatHandler.kt
class ChatHandler(private val zegoService: ZegoService) {
    fun setupZego(appId: Long, appSign: String) {
        zegoService.initialize(appId, appSign)
        zegoService.setMessageListener(object : ZegoMessageListener {
            override fun onMessageReceived(roomId: String, userId: String, message: String) {
                // 处理收到的消息,比如更新UI或存入本地数据库
            }
        })
    }

    suspend fun joinRoom(roomId: String, userId: String): Boolean {
        return zegoService.loginRoom(roomId, userId)
    }

    fun sendChatMessage(roomId: String, content: String) {
        zegoService.sendMessage(roomId, content)
    }

    fun cleanup() {
        zegoService.destroy()
    }
}

关键注意事项

  • 协程转换:平台SDK的异步回调必须用suspendCancellableCoroutine转为Kotlin协程,保证Common层的代码风格统一,同时处理取消逻辑。
  • 类型转换:注意Kotlin与Android/iOS平台的类型差异,比如Long转iOS的ULong,集合的类型强转(需添加@Suppress消除警告)。
  • 权限处理:Android端需在AndroidManifest.xml声明必要权限(如麦克风、网络);iOS端需在Info.plist添加权限描述(如NSMicrophoneUsageDescription)。
  • 生命周期绑定:SDK的初始化和销毁建议与App生命周期绑定,比如Android在Application的onCreate/onTerminate,iOS在AppDelegate的对应方法中调用。

内容的提问来源于stack exchange,提问作者laram

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 10:52:29