livekit/client-sdk-swift

GitHub: livekit/client-sdk-swift

LiveKit 官方 Swift 客户端 SDK,用于在 Apple 平台上构建实时音视频和数据通信应用。

Stars: 417 | Forks: 182

The LiveKit icon, the name of the repository and some sample code in the background. # 适用于 iOS/macOS 的 LiveKit Swift SDK 使用此 SDK 为你的 Swift 应用添加实时视频、音频和数据功能。通过连接到 LiveKit Cloud 或自建服务器,只需几行代码即可快速构建多模态 AI、直播或视频通话等应用。 [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Flivekit%2Fclient-sdk-swift%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/livekit/client-sdk-swift) [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Flivekit%2Fclient-sdk-swift%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/livekit/client-sdk-swift) ## 文档与示例应用 文档和指南请访问 [https://docs.livekit.io](https://docs.livekit.io)。 这里提供了 [iOS/macOS Swift UI 示例应用](https://github.com/livekit/client-example-swift)的完整源代码。 如需查看最小化示例,请查看此仓库 👉 [Swift SDK 示例](https://github.com/livekit/client-example-collection-swift) ## 安装说明 LiveKit for Swift 以 Swift 包的形式提供。 ### Package.swift 添加依赖项并将其添加到你的 target ``` let package = Package( ... dependencies: [ .package(name: "LiveKit", url: "https://github.com/livekit/client-sdk-swift.git", .upToNextMajor("2.14.1")), ], targets: [ .target( name: "MyApp", dependencies: ["LiveKit"] ) ] } ``` ### Xcode 前往项目设置 -> Swift 软件包。 添加新包并输入:`https://github.com/livekit/client-sdk-swift` ### 预编译的 XCFramework 提供预编译的二进制分发版本,以加快集成和 CI 构建速度。请添加 XCFramework 包: `https://github.com/livekit/client-sdk-swift-xcframework` 此包包含 `LiveKit.xcframework`(动态框架)及其依赖项(`LiveKitWebRTC`、`RustLiveKitUniFFI`)。它包含与上述源代码包相同的代码,只是已预编译。 ### CocoaPods 有关使用 CocoaPods 的安装说明,请参阅此[指南](./Docs/cocoapods.md)。 ## iOS 用法 LiveKit 提供了基于 UIKit 的 `VideoView` 类,用于渲染视频轨道。订阅的音频轨道会自动播放。 ``` import LiveKit import UIKit class RoomViewController: UIViewController { lazy var room = Room(delegate: self) lazy var remoteVideoView: VideoView = { let videoView = VideoView() view.addSubview(videoView) // Additional initialization ... return videoView }() lazy var localVideoView: VideoView = { let videoView = VideoView() view.addSubview(videoView) // Additional initialization ... return videoView }() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white let url = "ws://your_host" let token = "your_jwt_token" Task { do { try await room.connect(url: url, token: token) // Connection successful... // Publishing camera & mic... try await room.localParticipant.setCamera(enabled: true) try await room.localParticipant.setMicrophone(enabled: true) } catch { // Failed to connect } } } } extension RoomViewController: RoomDelegate { func room(_: Room, participant _: LocalParticipant, didPublishTrack publication: LocalTrackPublication) { guard let track = publication.track as? VideoTrack else { return } DispatchQueue.main.async { self.localVideoView.track = track } } func room(_: Room, participant _: RemoteParticipant, didSubscribeTrack publication: RemoteTrackPublication) { guard let track = publication.track as? VideoTrack else { return } DispatchQueue.main.async { self.remoteVideoView.track = track } } } ``` ### 屏幕共享 请参阅 [iOS 屏幕共享说明](Docs/ios-screen-sharing.md)。 ## 集成注意事项 ### 提交到 App Store、DSYMs `LiveKitWebRTC.xcframework` 二进制框架是 SDK 的主要依赖项,不包含 DSYMs。将应用提交到 App Store 时会出现以下警告: ``` The archive did not include a dSYM for the LiveKitWebRTC.framework with the UUIDs [...]. Ensure that the archive's dSYM folder includes a DWARF file for LiveKitWebRTC.framework with the expected UUIDs. ``` 这**不会阻止**应用提交到 App Store 或通过审核流程。 如果你正在构建自定义版本的 [LiveKitWebRTC](https://github.com/webrtc-sdk/webrtc),可以使用 `DEBUG` 模式下的[构建脚本](https://github.com/webrtc-sdk/webrtc-build/blob/main/build/apple/xcframework.sh)在本地生成它们。 ### 线程安全 由于 `VideoView` 是 UI 组件,所有操作(读写属性等)必须从 `main` 线程执行。 其他核心类可以从任何线程访问。 委托将在 SDK 的内部线程上调用。 确保对应用 UI 元素的任何访问都来自主线程,例如使用 `@MainActor` 或 `DispatchQueue.main.async`。 ### Swift 6 LiveKit 目前使用 Swift 6.0 编译,完全支持严格并发。以 Swift 6 语言模式编译的应用不需要使用 `@preconcurrency` 或 `@unchecked Sendable` 来访问 LiveKit 类。 ### 内存管理 建议使用 **weak var** 来存储对 SDK 创建和管理的对象(如 `Participant`、`TrackPublication` 等)的引用。当 `Room` 断开连接时,这些对象将失效,并由 SDK 释放。持有这些对象的强引用将阻止释放 `Room` 和其他内部对象。 `VideoView.track` 属性不持有强引用,因此无需将其设置为 `nil`。 ### AudioSession 管理 LiveKit 在连接时会自动管理底层 `AVAudioSession`。默认情况下,会话设置为 `.playback` 类别。当发布本地轨道时,它会切换到 `.playAndRecord`。一般来说,它会选择合理的默认值并做出正确的处理。 如果你想自行配置 `AVAudioSession`,请禁用 SDK 的自动音频会话处理: ``` AudioManager.shared.audioSession.isAutomaticConfigurationEnabled = false ``` - 在启用/发布麦克风之前,必须配置并激活 `AVAudioSession`,类别为 `.playAndRecord`,模式为 `.voiceChat` 或 `.videoChat`(以便音频引擎可以启动)。 要获取音频引擎生命周期的具体时机,可以通过 `AudioManager.shared.set(engineObservers:)` 提供你自己的 `AudioEngineObserver` 链。在应用启动早期配置一次,并避免在引擎使用时更改它。 有关 `AudioEngineObserver` 如何配置音频会话的示例,请参阅默认的 `AudioSessionEngineObserver`。 - 如果你想减少麦克风发布的延迟,可以通过 `try await AudioManager.shared.setRecordingAlwaysPreparedMode(true)` 预热音频引擎。 - 有关更多与音频相关的信息,请参阅[音频指南](./Docs/audio.md)。 ### 与 CallKit 集成 与 CallKit 集成时,`AVAudioSession` 与 SDK 音频引擎之间的正确时机和协调至关重要。 1. 禁用 SDK 的自动 `AVAudioSession` 配置,并防止音频引擎在 CallKit 的 `provider(_:didActivate:)` 和 `provider(_:didDeactivate:)` 窗口之外启动。 ``` // As early as possible, before connecting to a Room. AudioManager.shared.audioSession.isAutomaticConfigurationEnabled = false try AudioManager.shared.setEngineAvailability(.none) ``` 2. 在你的 `CXProviderDelegate` 实现中协调音频引擎的可用性: ``` func provider(_: CXProvider, didActivate session: AVAudioSession) { do { try session.setCategory(.playAndRecord, mode: .voiceChat, options: [.mixWithOthers]) try AudioManager.shared.setEngineAvailability(.default) } catch { // Error } } func provider(_: CXProvider, didDeactivate _: AVAudioSession) { do { try AudioManager.shared.setEngineAvailability(.none) } catch { // Error } } ``` * 请参阅我们的 [CallKit 示例](https://github.com/livekit-examples/swift-example-collection/tree/main/callkit)了解完整详情。 * 有关更多与音频相关的信息,请参阅[音频指南](./Docs/audio.md)。 ### iOS 模拟器限制 - iOS 模拟器不支持发布摄像头轨道。 ### ScrollView 性能 建议通过将 `isEnabled` 属性设置为 `false` 来关闭滚出屏幕且不可见的 `VideoView` 的渲染,并在其重新出现时设置为 `true`,以节省 CPU 资源。 据报道,`UICollectionViewDelegate` 的 `willDisplay` / `didEndDisplaying` 用于此目的时并不可靠。具体来说,在某些 iOS 版本中,即使单元格可见,也可能会调用 `didEndDisplaying`。 以下是使用 `willDisplay` / `didEndDisplaying` 的替代方法: ``` // 1. define a weak-reference set for all cells private var allCells = NSHashTable.weakObjects() ``` ``` // in UICollectionViewDataSource... public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ParticipantCell.reuseIdentifier, for: indexPath) if let cell = cell as? ParticipantCell { // 2. keep weak reference to the cell allCells.add(cell) // configure cell etc... } return cell } ``` ``` // 3. define a func to re-compute and update isEnabled property for cells that visibility changed func reComputeVideoViewEnabled() { let visibleCells = collectionView.visibleCells.compactMap { $0 as? ParticipantCell } let offScreenCells = allCells.allObjects.filter { !visibleCells.contains($0) } for cell in visibleCells.filter({ !$0.videoView.isEnabled }) { print("enabling cell#\(cell.hashValue)") cell.videoView.isEnabled = true } for cell in offScreenCells.filter({ $0.videoView.isEnabled }) { print("disabling cell#\(cell.hashValue)") cell.videoView.isEnabled = false } } ``` ``` // 4. set a timer to invoke the func self.timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { [weak self] _ in self?.reComputeVideoViewEnabled() }) // alternatively, you can call `reComputeVideoViewEnabled` whenever cell visibility changes (such as scrollViewDidScroll(_:)), // but this will be harder to track all cases such as cell reload etc. ``` 完整示例请参见 👉 [UIKit 最小化示例](https://github.com/livekit/client-example-collection-swift/tree/main/uikit-minimal) # 常见问题 ### 如何调整日志级别? SDK 默认会写入 `OSLog`(`io.livekit.*`),最低日志级别为 `info`。可以使用 Xcode 控制台按级别、类别等过滤日志。 - 要调整日志级别,请调用 `LiveKitSDK.setLogLevel(_:)` - 要设置自定义日志记录器(例如传递给自定义日志系统),请调用 `LiveKitSDK.setLogger(_:)` - 要完全禁用日志记录,请调用 `LiveKitSDK.disableLogging()` 所有方法必须在任何其他日志记录之前调用,例如在 `App.init()` 或 `AppDelegate/SceneDelegate` 中。 或者,你可以子类化 `OSLogger` 并重写 `log(...)` 方法以捕获例如警告和错误日志。 ### 如何以 60 FPS 发布摄像头? - 通过调用 `LocalVideoTrack.createCameraTrack(options: CameraCaptureOptions(fps: 60))` 创建 `LocalVideoTrack`。 - 使用 `LocalParticipant.publish(videoTrack: track, publishOptions: VideoPublishOptions(encoding: VideoEncoding(maxFps: 60)))` 发布。 # 已知问题 ### 避免在 macOS Catalina 上崩溃 如果你的应用以 macOS Catalina 为目标,请确保执行以下操作以避免崩溃(未找到 ReplayKit): 1. 在 Build Phases > Link Binary with Libraries 部分显式添加 "ReplayKit.framework" 2. 将其设置为 Optional replykit - 我目前不确定为什么 ReplayKit 需要这样做。 - 如果你的目标是 macOS 11.0+,则不需要这样做。 # 获取帮助 / 贡献 请加入我们的 [Slack](https://livekit.io/join-slack),从我们的开发者/社区成员那里获取帮助。我们欢迎你的贡献(PR),详情可在那里讨论。
LiveKit 生态系统
Agents SDKPython · Node.js
LiveKit SDKBrowser · Swift · Android · Flutter · React Native · Rust · Node.js · Python · Unity · Unity (WebGL) · ESP32 · C++
入门应用Python Agent · TypeScript Agent · React App · SwiftUI App · Android App · Flutter App · React Native App · Web Embed
UI 组件React · Android Compose · SwiftUI · Flutter
服务端 APINode.js · Golang · Ruby · Java/Kotlin · Python · Rust · PHP (社区) · .NET (社区)
资源文档 · 文档 MCP Server · CLI · LiveKit Cloud
LiveKit 服务端 OSSLiveKit server · Egress · Ingress · SIP
社区开发者社区 · Slack · X · YouTube
标签:CocoaPods/SPM, H.264, iOS开发, LiveKit, macOS开发, Objective-C桥接, Opus, Swift Package, Swift SDK, SwiftUI示例, TURN/STUN, tvOS, visionOS, VP8, WebRTC, Xcode集成, 低延迟传输, 信令服务器, 元数据发布, 分布式信令, 参与者权限, 后台模式, 回声消除, 多模态AI, 媒体处理, 实时互动, 实时数据通道, 实时通信, 实时音视频, 客户端SDK, 屏幕共享, 房间管理, 推送通知, 直播, 端到端加密, 网络传输, 自托管服务器, 自适应码率, 视频会议, 视频编解码, 跨平台框架, 边缘计算, 音视频流, 音频处理, 音频降噪