-
Notifications
You must be signed in to change notification settings - Fork 35
Implemented LiveCommunicationKit as an alternative to CallKit #1200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -17,36 +17,36 @@ open class CallKitAdapter { | |||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| /// The icon data used as the template for CallKit. | ||||||||||||||||||||||||||||||||||||||||||
| open var iconTemplateImageData: Data? { | ||||||||||||||||||||||||||||||||||||||||||
| get { callKitService.iconTemplateImageData } | ||||||||||||||||||||||||||||||||||||||||||
| set { callKitService.iconTemplateImageData = newValue } | ||||||||||||||||||||||||||||||||||||||||||
| get { activeSystemCallingService.iconTemplateImageData } | ||||||||||||||||||||||||||||||||||||||||||
| set { updateSystemCallingServices { $0.iconTemplateImageData = newValue } } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| /// The ringtone sound to use for CallKit ringing calls. | ||||||||||||||||||||||||||||||||||||||||||
| open var ringtoneSound: String? { | ||||||||||||||||||||||||||||||||||||||||||
| get { callKitService.ringtoneSound } | ||||||||||||||||||||||||||||||||||||||||||
| set { callKitService.ringtoneSound = newValue } | ||||||||||||||||||||||||||||||||||||||||||
| get { activeSystemCallingService.ringtoneSound } | ||||||||||||||||||||||||||||||||||||||||||
| set { updateSystemCallingServices { $0.ringtoneSound = newValue } } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| /// Configure whether calls should appear in the Recents app. | ||||||||||||||||||||||||||||||||||||||||||
| open var includesCallsInRecents: Bool { | ||||||||||||||||||||||||||||||||||||||||||
| get { callKitService.includesCallsInRecents } | ||||||||||||||||||||||||||||||||||||||||||
| set { callKitService.includesCallsInRecents = newValue } | ||||||||||||||||||||||||||||||||||||||||||
| get { activeSystemCallingService.includesCallsInRecents } | ||||||||||||||||||||||||||||||||||||||||||
| set { updateSystemCallingServices { $0.includesCallsInRecents = newValue } } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| /// The callSettings to use when joining a call (after accepting it on CallKit) | ||||||||||||||||||||||||||||||||||||||||||
| /// default: nil | ||||||||||||||||||||||||||||||||||||||||||
| /// The callSettings to use when joining a call after accepting it on the | ||||||||||||||||||||||||||||||||||||||||||
| /// system calling UI. Default: `nil`. | ||||||||||||||||||||||||||||||||||||||||||
| open var callSettings: CallSettings? { | ||||||||||||||||||||||||||||||||||||||||||
| didSet { callKitService.callSettings = callSettings } | ||||||||||||||||||||||||||||||||||||||||||
| didSet { updateSystemCallingServices { $0.callSettings = callSettings } } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| /// The policy that decides if a CallKit-managed call should leave | ||||||||||||||||||||||||||||||||||||||||||
| /// The policy that decides if a system-managed call should leave | ||||||||||||||||||||||||||||||||||||||||||
| /// automatically when participant state changes. | ||||||||||||||||||||||||||||||||||||||||||
| open var participantAutoLeavePolicy: ParticipantAutoLeavePolicy { | ||||||||||||||||||||||||||||||||||||||||||
| get { callKitService.participantAutoLeavePolicy } | ||||||||||||||||||||||||||||||||||||||||||
| set { callKitService.participantAutoLeavePolicy = newValue } | ||||||||||||||||||||||||||||||||||||||||||
| get { activeSystemCallingService.participantAutoLeavePolicy } | ||||||||||||||||||||||||||||||||||||||||||
| set { updateSystemCallingServices { $0.participantAutoLeavePolicy = newValue } } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| /// The policy defining the availability of CallKit services. | ||||||||||||||||||||||||||||||||||||||||||
| /// The policy defining the availability of system calling services. | ||||||||||||||||||||||||||||||||||||||||||
| /// | ||||||||||||||||||||||||||||||||||||||||||
| /// - Default: `.regionBased` | ||||||||||||||||||||||||||||||||||||||||||
| public var availabilityPolicy: CallKitAvailabilityPolicy = .regionBased | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -64,8 +64,8 @@ open class CallKitAdapter { | |||||||||||||||||||||||||||||||||||||||||
| /// join flow, such as waiting for another participant or validating an | ||||||||||||||||||||||||||||||||||||||||||
| /// external precondition. Throw from the interceptor to fail the join. | ||||||||||||||||||||||||||||||||||||||||||
| public var callJoinInterceptor: CallJoinIntercepting? { | ||||||||||||||||||||||||||||||||||||||||||
| get { callKitService.callJoinInterceptor } | ||||||||||||||||||||||||||||||||||||||||||
| set { callKitService.callJoinInterceptor = newValue } | ||||||||||||||||||||||||||||||||||||||||||
| get { activeSystemCallingService.callJoinInterceptor } | ||||||||||||||||||||||||||||||||||||||||||
| set { updateSystemCallingServices { $0.callJoinInterceptor = newValue } } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| /// Initializes the `CallKitAdapter`. | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -87,6 +87,47 @@ open class CallKitAdapter { | |||||||||||||||||||||||||||||||||||||||||
| callKitPushNotificationAdapter.unregister() | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| private var activeSystemCallingService: SystemCallingService { | ||||||||||||||||||||||||||||||||||||||||||
| #if canImport(LiveCommunicationKit) | ||||||||||||||||||||||||||||||||||||||||||
| if #available(iOS 27.0, *), shouldUseLiveCommunicationKit { | ||||||||||||||||||||||||||||||||||||||||||
| return InjectedValues[\.liveCommunicationKitService] | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||||||||||||||
| return callKitService | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| private var shouldUseLiveCommunicationKit: Bool { | ||||||||||||||||||||||||||||||||||||||||||
| streamVideo?.videoConfig.useLiveCommunicationKit ?? true | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| private func updateSystemCallingServices( | ||||||||||||||||||||||||||||||||||||||||||
| _ update: (SystemCallingService) -> Void | ||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||
| update(callKitService) | ||||||||||||||||||||||||||||||||||||||||||
| #if canImport(LiveCommunicationKit) | ||||||||||||||||||||||||||||||||||||||||||
| if #available(iOS 27.0, *) { | ||||||||||||||||||||||||||||||||||||||||||
| update(InjectedValues[\.liveCommunicationKitService]) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| private func updateSystemCallingServices(with streamVideo: StreamVideo?) { | ||||||||||||||||||||||||||||||||||||||||||
| guard let streamVideo else { | ||||||||||||||||||||||||||||||||||||||||||
| updateSystemCallingServices { $0.streamVideo = nil } | ||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| let useLiveCommunicationKit = streamVideo.videoConfig.useLiveCommunicationKit | ||||||||||||||||||||||||||||||||||||||||||
| callKitService.streamVideo = useLiveCommunicationKit ? nil : streamVideo | ||||||||||||||||||||||||||||||||||||||||||
| #if canImport(LiveCommunicationKit) | ||||||||||||||||||||||||||||||||||||||||||
| if #available(iOS 27.0, *) { | ||||||||||||||||||||||||||||||||||||||||||
| InjectedValues[\.liveCommunicationKitService].streamVideo = useLiveCommunicationKit | ||||||||||||||||||||||||||||||||||||||||||
| ? streamVideo | ||||||||||||||||||||||||||||||||||||||||||
| : nil | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+120
to
+128
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win Keep CallKit configured on systems without LiveCommunicationKit. On iOS versions below 27, the default Proposed fix- let useLiveCommunicationKit = streamVideo.videoConfig.useLiveCommunicationKit
- callKitService.streamVideo = useLiveCommunicationKit ? nil : streamVideo
+ var useLiveCommunicationKit = false
`#if` canImport(LiveCommunicationKit)
if `#available`(iOS 27.0, *) {
+ useLiveCommunicationKit =
+ streamVideo.videoConfig.useLiveCommunicationKit
InjectedValues[\.liveCommunicationKitService].streamVideo = useLiveCommunicationKit
? streamVideo
: nil
}
`#endif`
+ callKitService.streamVideo = useLiveCommunicationKit ? nil : streamVideo📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| private func didUpdate(_ streamVideo: StreamVideo?) { | ||||||||||||||||||||||||||||||||||||||||||
| guard availabilityPolicy.policy.isAvailable else { | ||||||||||||||||||||||||||||||||||||||||||
| log | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -96,7 +137,7 @@ open class CallKitAdapter { | |||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| callKitService.streamVideo = streamVideo | ||||||||||||||||||||||||||||||||||||||||||
| updateSystemCallingServices(with: streamVideo) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| guard streamVideo != nil else { | ||||||||||||||||||||||||||||||||||||||||||
| unregisterForIncomingCalls() | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
Repository: GetStream/stream-video-swift
Length of output: 13929
🏁 Script executed:
Repository: GetStream/stream-video-swift
Length of output: 15778
🏁 Script executed:
Repository: GetStream/stream-video-swift
Length of output: 35716
Do not share one
ParticipantAutoLeavePolicyinstance across both servicesSources/StreamVideo/CallKit/CallKitAdapter.swift:44-46forwards the same policy toCallKitServiceandLiveCommunicationKitService, but each service rewritesonPolicyTriggeredindidSet. The last assignment wins, so the other service loses its callback. Keep separate policy ownership or rebind the callback when switching backends.🤖 Prompt for AI Agents