Skip to content

Commit e826c9d

Browse files
committed
fix Sessions build
1 parent 9b46b05 commit e826c9d

File tree

9 files changed

+58
-32
lines changed

9 files changed

+58
-32
lines changed

FirebaseCore/Extension/FIRLibrary.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ NS_SWIFT_NAME(Library)
3333

3434
/// Returns one or more Components that will be registered in
3535
/// FirebaseApp and participate in dependency resolution and injection.
36-
+ (NSArray<FIRComponent *> *)componentsToRegister;
36+
+ (NSArray<FIRComponent *> *NS_SWIFT_SENDING)componentsToRegister NS_SWIFT_UI_ACTOR;
3737

3838
@end
3939

FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ typedef void (^FIRInstallationsTokenHandler)(
5757
* as the ability to delete it. A Firebase Installation is unique by `FirebaseApp.name` and
5858
* `FirebaseApp.options.googleAppID` .
5959
*/
60-
NS_SWIFT_NAME(Installations) NS_SWIFT_SENDABLE
61-
@interface FIRInstallations : NSObject
60+
NS_SWIFT_NAME(Installations) NS_SWIFT_SENDABLE @interface FIRInstallations : NSObject
6261

6362
- (instancetype)init NS_UNAVAILABLE;
6463

FirebaseSessions/Sources/ApplicationInfo.swift

+4-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,10 @@ final class ApplicationInfo: ApplicationInfoProtocol {
6767

6868
private let networkInformation: NetworkInfoProtocol
6969
private let envParams: [String: String]
70-
nonisolated(unsafe) private let infoDict: [String: Any]?
70+
71+
// Used to hold bundle info, so the `Any` params should also
72+
// be Sendable.
73+
private nonisolated(unsafe) let infoDict: [String: Any]?
7174

7275
init(appID: String, networkInfo: NetworkInfoProtocol = NetworkInfo(),
7376
envParams: [String: String] = ProcessInfo.processInfo.environment,

FirebaseSessions/Sources/FirebaseSessions.swift

+23-3
Original file line numberDiff line numberDiff line change
@@ -247,18 +247,39 @@ private enum GoogleDataTransportConfig {
247247
return SessionDetails(sessionId: sessionGenerator.currentSession?.sessionId)
248248
}
249249

250+
// This type is not actually sendable, but works around an issue below.
251+
// It's safe only if executed on the main actor.
252+
private struct MainActorNotificationCallback: @unchecked Sendable {
253+
private let callback: (Notification) -> Void
254+
255+
init(_ callback: @escaping (Notification) -> Void) {
256+
self.callback = callback
257+
}
258+
259+
func invoke(notification: Notification) {
260+
dispatchPrecondition(condition: .onQueue(.main))
261+
callback(notification)
262+
}
263+
}
264+
250265
func register(subscriber: SessionsSubscriber) {
251266
Logger
252267
.logDebug(
253268
"Registering Sessions SDK subscriber with name: \(subscriber.sessionsSubscriberName), data collection enabled: \(subscriber.isDataCollectionEnabled)"
254269
)
255270

271+
// After bumping to iOS 13, this hack should be replaced with `Task { @MainActor in }`
272+
let callback = MainActorNotificationCallback { notification in
273+
subscriber.onSessionChanged(self.currentSessionDetails)
274+
}
275+
276+
// Guaranteed to execute its callback on the main queue because of the queue parameter.
256277
notificationCenter.addObserver(
257278
forName: Sessions.SessionIDChangedNotificationName,
258279
object: nil,
259-
queue: nil
280+
queue: OperationQueue.main
260281
) { notification in
261-
subscriber.onSessionChanged(self.currentSessionDetails)
282+
callback.invoke(notification: notification)
262283
}
263284
// Immediately call the callback because the Sessions SDK starts
264285
// before subscribers, so subscribers will miss the first Notification
@@ -270,7 +291,6 @@ private enum GoogleDataTransportConfig {
270291
}
271292

272293
// MARK: - Library conformance
273-
274294
static func componentsToRegister() -> [Component] {
275295
return [Component(SessionsProvider.self,
276296
instantiationTiming: .alwaysEager) { container, isCacheable in

FirebaseSessions/Sources/Public/SessionsProvider.swift

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import Foundation
1717

1818
// Sessions Provider is the Session SDK's internal
1919
// interface for other 1P SDKs to talk to.
20+
@MainActor
2021
@objc(FIRSessionsProvider)
2122
public protocol SessionsProvider {
2223
@objc func register(subscriber: SessionsSubscriber)

FirebaseSessions/Sources/SessionCoordinator.swift

+5-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import Foundation
1616

17-
protocol SessionCoordinatorProtocol {
17+
protocol SessionCoordinatorProtocol: Sendable {
1818
func attemptLoggingSessionStart(event: SessionStartEvent,
1919
callback: @escaping (Result<Void, FirebaseSessionsError>) -> Void)
2020
}
@@ -23,9 +23,11 @@ protocol SessionCoordinatorProtocol {
2323
/// SessionCoordinator is responsible for coordinating the systems in this SDK
2424
/// involved with sending a Session Start event.
2525
///
26-
class SessionCoordinator: SessionCoordinatorProtocol {
26+
final class SessionCoordinator: SessionCoordinatorProtocol {
2727
let installations: InstallationsProtocol
28-
let fireLogger: EventGDTLoggerProtocol
28+
29+
// TODO: Make this type sendable
30+
nonisolated(unsafe) let fireLogger: EventGDTLoggerProtocol
2931

3032
init(installations: InstallationsProtocol,
3133
fireLogger: EventGDTLoggerProtocol) {

FirebaseSessions/Sources/SessionInitiator.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ import Foundation
4141
///
4242
class SessionInitiator {
4343
let currentTime: () -> Date
44-
var settings: SettingsProtocol
45-
var backgroundTime = Date.distantFuture
46-
var initiateSessionStart: () -> Void = {}
44+
let settings: SettingsProtocol
45+
private var backgroundTime = Date.distantFuture
46+
private var initiateSessionStart: () -> Void = {}
4747

4848
init(settings: SettingsProtocol, currentTimeProvider: @escaping () -> Date = Date.init) {
4949
currentTime = currentTimeProvider

FirebaseSessions/Sources/Settings/RemoteSettings.swift

+16-17
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ final class RemoteSettings: SettingsProvider, Sendable {
4444

4545
private var sessionsCache: [String: Any] {
4646
cache.withLock { cache in
47-
return cache.cacheContent[RemoteSettings.flagSessionsCache] as? [String: Any] ?? [:]
47+
cache.cacheContent[RemoteSettings.flagSessionsCache] as? [String: Any] ?? [:]
4848
}
4949
}
5050

@@ -65,23 +65,22 @@ final class RemoteSettings: SettingsProvider, Sendable {
6565
}
6666
}
6767

68-
downloader.fetch { result in
69-
70-
switch result {
71-
case let .success(dictionary):
72-
self.cache.withLock { cache in
73-
// Saves all newly fetched Settings to cache
74-
cache.cacheContent = dictionary
75-
// Saves a "cache-key" which carries TTL metadata about current cache
76-
cache.cacheKey = CacheKey(
77-
createdAt: currentTime,
78-
googleAppID: self.appInfo.appID,
79-
appVersion: self.appInfo.synthesizedVersion
80-
)
81-
}
68+
downloader.fetch { result in
69+
70+
switch result {
71+
case let .success(dictionary):
72+
self.cache.withLock { cache in
73+
// Saves all newly fetched Settings to cache
74+
cache.cacheContent = dictionary
75+
// Saves a "cache-key" which carries TTL metadata about current cache
76+
cache.cacheKey = CacheKey(
77+
createdAt: currentTime,
78+
googleAppID: self.appInfo.appID,
79+
appVersion: self.appInfo.synthesizedVersion
80+
)
81+
}
8282
case let .failure(error):
8383
Logger.logError("[Settings] Fetching newest settings failed with error: \(error)")
84-
8584
}
8685
}
8786
}
@@ -114,7 +113,7 @@ extension RemoteSettingsConfigurations {
114113

115114
func isSettingsStale() -> Bool {
116115
cache.withLock { cache in
117-
return isCacheExpired(cache, time: Date())
116+
isCacheExpired(cache, time: Date())
118117
}
119118
}
120119

FirebaseSessions/Sources/Settings/SettingsDownloadClient.swift

+4-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import Foundation
2222
#endif // SWIFT_PACKAGE
2323

2424
protocol SettingsDownloadClient: Sendable {
25-
func fetch(completion: @Sendable @escaping (Result<[String: Any], SettingsDownloaderError>) -> Void)
25+
func fetch(completion: @Sendable @escaping (Result<[String: Any], SettingsDownloaderError>)
26+
-> Void)
2627
}
2728

2829
enum SettingsDownloaderError: Error {
@@ -45,7 +46,8 @@ final class SettingsDownloader: SettingsDownloadClient {
4546
self.installations = installations
4647
}
4748

48-
func fetch(completion: @Sendable @escaping (Result<[String: Any], SettingsDownloaderError>) -> Void) {
49+
func fetch(completion: @Sendable @escaping (Result<[String: Any], SettingsDownloaderError>)
50+
-> Void) {
4951
guard let validURL = url else {
5052
completion(.failure(.URLError("Invalid URL")))
5153
return

0 commit comments

Comments
 (0)