Kotlin端LiveKit RoomDelegateProtocol代理方法未触发求助
Kotlin Multiplatform iOS端LiveKit RoomDelegateProtocol代理方法未触发问题
问题描述
在Kotlin Multiplatform项目的iOS实现中,我尝试实现LiveKit的RoomDelegateProtocol,但所有代理方法都没有被调用。相同逻辑在Swift端直接实现时完全正常,且已通过iOS日志确认代理实例成功添加到Room对象中,尝试多种方案均无效,寻求解决思路。
相关代码如下:
@OptIn(ExperimentalForeignApi::class) class IosRoom() : RoomWrapper { private val scope = CoroutineScope( SupervisorJob() + Dispatchers.Main + CoroutineName("IosRoomCoroutine") ) private val delegate = IosRoomDelegate() private val room: Room = Room().apply { println("will add the room delegate") addDelegate(delegate) } override val localParticipant: LocalParticipantWrapper get() = IosLocalParticipant( liveKitLocalParticipant = room.localParticipant(), scope = scope, ) override val remoteParticipants = MutableSharedFlow<List<RemoteParticipantWrapper>>() override val activeSpeakers: Flow<List<ParticipantWrapper>> = flow { // 预留实现 } override suspend fun connect(url: String, token: String) { room.connectWithUrl( url = url, token = token, connectOptions = null, roomOptions = null, completionHandler = {}, ) } override fun disconnect() { room.disconnectWithCompletionHandler(completionHandler = {}) } fun updateRemoteParticipants() { // 预留实现 } } @OptIn(ExperimentalForeignApi::class) class IosRoomDelegate : NSObject(), RoomDelegateProtocol { override fun room(room: Room, participantDidConnect: RemoteParticipant) { println("remote participantDidConnect called") } override fun room(room: Room, participant: Participant, didUpdatePermissions: ParticipantPermissions) { println("didUpdatePermissions called") } override fun room(room: Room, localParticipant: LocalParticipant, didPublishTrack: LocalTrackPublication) { println("didPublishTrack called") } override fun room(room: Room, participant: Participant, didUpdateConnectionQuality: ConnectionQuality) { println("connection quality updated") } override fun roomDidConnect(room: Room) { println("delegate room did connect") } } interface RoomWrapper { val localParticipant: LocalParticipantWrapper val remoteParticipants: Flow<List<RemoteParticipantWrapper>> val activeSpeakers: Flow<List<ParticipantWrapper>> suspend fun connect(url: String, token: String) fun disconnect() } class SessionViewModel( private val roomId: String, isCameraEnabled: Boolean, isMicrophoneEnabled: Boolean, val room: RoomWrapper, private val scope: CoroutineScope, private val sessionRepository: SessionRepository, private val state: MutableStateFlow<SessionState>, ) { private val localParticipant get() = state.value.localParticipantState.localParticipant init { scope.launch { state.update { it.copy( roomId = roomId, ) } getRoomToken(roomId) launch { connect(state.value.roomToken) toggleCamera(isCameraEnabled) toggleMic(isMicrophoneEnabled) } state.update { it.copy( localParticipantState = it.localParticipantState.copy( localParticipant = room.localParticipant, ) ) } } } fun onEvent(event: SessionEvent) { when (event) { SessionEvent.OnDisconnect -> room.disconnect() SessionEvent.OnMicToggle -> scope.launch { toggleMic(!state.value.localParticipantState.isMicOn) } SessionEvent.OnSwitchCamera -> scope.launch { switchCamera() } SessionEvent.OnCameraToggle -> scope.launch { toggleCamera(!state.value.localParticipantState.isCameraOn) } is SessionEvent.OnConnect -> scope.launch { connect( token = event.token, ) } is SessionEvent.OnGetRoomToken -> scope.launch { getRoomToken(event.roomId) } is SessionEvent.OnChangeRoomId -> changeRoomId(event.roomId) } } suspend fun connect(token: String) { room.connect( url = "wss://livekit.cloudUrl", token = token, ) } suspend fun getRoomToken(roomId: String) { sessionRepository.getRoomToken(roomId).onSuccess { token -> state.update { it.copy( roomToken = token, ) } } } suspend fun toggleCamera(enabled: Boolean) { localParticipant.setCameraEnabled(enabled) state.update { it.copy( localParticipantState = it.localParticipantState.copy( isCameraOn = enabled, ) ) } } suspend fun toggleMic(enabled: Boolean) { localParticipant.setMicrophoneEnabled(enabled) state.update { it.copy( localParticipantState = it.localParticipantState.copy( isMicOn = enabled, ) ) } } suspend fun switchCamera() { localParticipant.videoTracksPublications.first().firstOrNull()?.second?.switchCamera() } fun changeRoomId(roomId: String) { state.update { it.copy( roomId = roomId, ) } } }
排查与解决方案
1. 确保Delegate实例持有强引用
iOS的代理通常是弱引用,Kotlin/Native中如果Delegate对象被GC回收,会直接导致代理方法无法触发。当前代码中IosRoom的delegate是强引用,但需确认:
- Room对象存活期间,
delegate没有被意外释放 - 可在
IosRoomDelegate中添加init和finalize日志,确认对象生命周期是否符合预期
2. 强制匹配Objective-C方法选择器
Kotlin到Objective-C的桥接可能存在自动生成的方法签名与预期不一致的情况,可手动用@ObjCName注解指定选择器,确保和Swift端完全匹配:
@OptIn(ExperimentalForeignApi::class) class IosRoomDelegate : NSObject(), RoomDelegateProtocol { @ObjCName("roomDidConnect:") override fun roomDidConnect(room: Room) { println("delegate room did connect") } @ObjCName("room:participantDidConnect:") override fun room(room: Room, participantDidConnect: RemoteParticipant) { println("remote participantDidConnect called") } // 其他代理方法同理添加@ObjCName注解 }
3. 检查Room对象生命周期
确认IosRoom中的room实例在连接后未被提前释放,可在IosRoom中添加日志跟踪room对象的创建与销毁时间,确保其生命周期覆盖整个会话过程。
4. 确保代理方法在主线程执行
LiveKit的代理方法通常在主线程触发,可在Delegate方法中强制切换到主线程处理:
override fun roomDidConnect(room: Room) { DispatchQueue.main.async { println("delegate room did connect on main thread") // 后续业务逻辑 } }
5. 验证LiveKit Kotlin绑定正确性
如果使用第三方提供的LiveKit Kotlin绑定,可直接在Kotlin中调用Objective-C的Delegate方法进行测试,或对比Swift端的Delegate实现,检查Protocol的方法签名、参数类型是否完全一致。
内容的提问来源于stack exchange,提问作者Mohamed Mabrouki
相关产品推荐
相关产品推荐

