Skip to content

Commit 23d9f49

Browse files
authored
chore: updated CXProvider init and config flow (#2326)
### 💡 Overview Avoided CXProvider redundant recreation. Updated CXProvider configuration setup. 🎫 Ticket: https://linear.app/stream/issue/RN-414/cxprovider-instantiation-and-configuration-updates <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Summary by CodeRabbit * **Bug Fixes** * Improved call setup reliability by consistently applying the latest call configuration before creating and starting calls. * Fixed settings handling with a safer in-memory cache to improve reliability across app sessions. * Reduced issues from concurrent settings access to help prevent inconsistent behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 95bcc2a commit 23d9f49

2 files changed

Lines changed: 30 additions & 32 deletions

File tree

packages/react-native-callingx/ios/CallingxImpl.swift

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ import stream_react_native_webrtc
108108
if CallingxImpl.sharedProvider == nil {
109109
CallingxImpl.sharedProvider = CXProvider(configuration: Settings.getProviderConfiguration())
110110
}
111+
112+
callKeepCallController = CXCallController()
111113

112114
callKeepProvider = CallingxImpl.sharedProvider
113115
callKeepProvider?.setDelegate(nil, queue: nil)
@@ -128,7 +130,8 @@ import stream_react_native_webrtc
128130

129131
// MARK: - Class Methods
130132
@objc public static func initializeIfNeeded() {
131-
_ = getSharedInstance() // ensures the shared instance is created and CXProvider delegate is set
133+
_ = getSharedInstance() // ensures the shared instance is created and CXProvider delegate is set
134+
CallingxImpl.sharedProvider?.configuration = Settings.getProviderConfiguration()
132135
}
133136

134137
@objc public static func reportNewIncomingCall(
@@ -379,29 +382,8 @@ import stream_react_native_webrtc
379382

380383
// MARK: - Setup Methods
381384
@objc public func setup(options: [String: Any]) {
382-
callKeepCallController = CXCallController()
383-
384385
Settings.setSettings(options)
385-
386-
// This is mostly needed for very first setup, as we need to override the default
387-
// provider configuration which is set in the constructor.
388-
// IMPORTANT: We override the CXProvider instance only when there are no calls in
389-
// flight, otherwise we'd destroy CallKit state/events for a live call. We check our
390-
// own storage rather than CXCallObserver here: the observer trails registration and
391-
// can briefly report empty (e.g. a VoIP-push call reported just before setup runs),
392-
// which would wrongly tear down the provider mid-call.
393-
if (CallingxImpl.uuidStorage?.count() ?? 0) == 0 {
394-
let oldProvider = CallingxImpl.sharedProvider
395-
let newProvider = CXProvider(configuration: Settings.getProviderConfiguration())
396-
newProvider.setDelegate(self, queue: nil)
397-
398-
CallingxImpl.sharedProvider = newProvider
399-
callKeepProvider = newProvider
400-
401-
oldProvider?.setDelegate(nil, queue: nil)
402-
oldProvider?.invalidate()
403-
}
404-
386+
CallingxImpl.sharedProvider?.configuration = Settings.getProviderConfiguration()
405387
isSetup = true
406388
}
407389

@@ -615,10 +597,13 @@ import stream_react_native_webrtc
615597
return
616598
}
617599

600+
CallingxImpl.sharedProvider?.configuration = Settings.getProviderConfiguration()
601+
618602
let call = storage.getOrCreateCall(forCid: callId, isOutgoing: true)
619603
call.markStartedConnecting() // outgoing: will be reported via reportOutgoingCall(startedConnectingAt:)
620604

621-
let handleType = Settings.getHandleType("generic")
605+
let handleTypeString = Settings.getSettings()["handleType"] as? String
606+
let handleType = Settings.getHandleType(handleTypeString ?? "generic")
622607
let callHandle = CXHandle(type: handleType, value: phoneNumber)
623608
let startCallAction = CXStartCallAction(call: call.uuid, handle: callHandle)
624609
startCallAction.isVideo = hasVideo

packages/react-native-callingx/ios/Settings.swift

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,36 @@ import UIKit
55
@objcMembers public class Settings: NSObject {
66
private static let settingsKey = "CallingxSettings"
77

8+
// In-memory cache of the settings dictionary
9+
private static var cachedSettings: [String: Any]?
10+
private static let cacheQueue = DispatchQueue(label: "io.getstream.callingx.settings")
11+
812
public static func getSettings() -> [String: Any] {
9-
return UserDefaults.standard.dictionary(forKey: settingsKey) ?? [:]
13+
return cacheQueue.sync {
14+
if let cached = cachedSettings {
15+
return cached
16+
}
17+
cachedSettings = UserDefaults.standard.dictionary(forKey: settingsKey) ?? [:]
18+
return cachedSettings!
19+
}
1020
}
1121

1222
public static func setSettings(_ options: [String: Any]?) {
1323
CallingxLog.settings.debugPublic("[setSettings] options = \(String(describing: options))")
1424

15-
var settings: [String: Any] = getSettings()
25+
cacheQueue.sync {
26+
// Load lazily here rather than via getSettings() to avoid re-entrant sync on cacheQueue.
27+
var settings = cachedSettings ?? UserDefaults.standard.dictionary(forKey: settingsKey) ?? [:]
1628

17-
if let options = options {
18-
for (key, value) in options {
19-
settings[key] = value
29+
if let options = options {
30+
for (key, value) in options {
31+
settings[key] = value
32+
}
2033
}
21-
}
2234

23-
UserDefaults.standard.set(settings, forKey: settingsKey)
24-
UserDefaults.standard.synchronize()
35+
cachedSettings = settings
36+
UserDefaults.standard.set(settings, forKey: settingsKey)
37+
}
2538
}
2639

2740
public static func getShouldRejectCallWhenBusy() -> Bool {

0 commit comments

Comments
 (0)