diff --git a/Firebase.podspec b/Firebase.podspec index 1f11d9f682f..33068324e86 100644 --- a/Firebase.podspec +++ b/Firebase.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Firebase' - s.version = '11.4.1' + s.version = '11.4.2' s.summary = 'Firebase' s.description = <<-DESC @@ -43,7 +43,7 @@ Simplify your app development, grow your user base, and monetize more effectivel end s.subspec 'CoreOnly' do |ss| - ss.dependency 'FirebaseCore', '11.4.1' + ss.dependency 'FirebaseCore', '11.4.2' ss.source_files = 'CoreOnly/Sources/Firebase.h' ss.preserve_paths = 'CoreOnly/Sources/module.modulemap' if ENV['FIREBASE_POD_REPO_FOR_DEV_POD'] then diff --git a/FirebaseAuth/Tests/Unit/AuthBackendRPCImplementationTests.swift b/FirebaseAuth/Tests/Unit/AuthBackendRPCImplementationTests.swift index 754fa761a54..7180313df34 100644 --- a/FirebaseAuth/Tests/Unit/AuthBackendRPCImplementationTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthBackendRPCImplementationTests.swift @@ -534,6 +534,11 @@ class AuthBackendRPCImplementationTests: RPCBaseTests { #if COCOAPODS || SWIFT_PACKAGE private class FakeHeartbeatLogger: NSObject, FIRHeartbeatLoggerProtocol { + func headerValue() -> String? { + // `asyncHeaderValue` should be used instead. + fatalError("FakeHeartbeatLogger headerValue should not be used in tests.") + } + func asyncHeaderValue() async -> String? { let payload = flushHeartbeatsIntoPayload() guard !payload.isEmpty else { diff --git a/FirebaseCore.podspec b/FirebaseCore.podspec index 45697bdff72..70c7cd728ad 100644 --- a/FirebaseCore.podspec +++ b/FirebaseCore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCore' - s.version = '11.4.1' + s.version = '11.4.2' s.summary = 'Firebase Core' s.description = <<-DESC @@ -53,7 +53,7 @@ Firebase Core includes FIRApp and FIROptions which provide central configuration # Remember to also update version in `cmake/external/GoogleUtilities.cmake` s.dependency 'GoogleUtilities/Environment', '~> 8.0' s.dependency 'GoogleUtilities/Logger', '~> 8.0' - s.dependency 'FirebaseCoreInternal', '~> 11.4' + s.dependency 'FirebaseCoreInternal', '>= 11.4.2', '< 12.0' s.pod_target_xcconfig = { 'GCC_C_LANGUAGE_STANDARD' => 'c99', diff --git a/FirebaseCore/CHANGELOG.md b/FirebaseCore/CHANGELOG.md index efaf85d2fa4..89ed80fcf55 100644 --- a/FirebaseCore/CHANGELOG.md +++ b/FirebaseCore/CHANGELOG.md @@ -1,3 +1,7 @@ +# Firebase 11.4.2 +- [fixed] CocoaPods only release to fix iOS 12 build failure resulting from + incomplete implementation in the FirebaseCoreInternal CocoaPod. + # Firebase 11.4.1 - [fixed] CocoaPods only release to revert breaking change in `FirebaseCoreExtension` SDK. (#13942) diff --git a/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift b/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift index e4a2cc4c335..e7f4ece2781 100644 --- a/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift +++ b/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift @@ -126,34 +126,30 @@ public final class HeartbeatController { } } - @available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *) - public func flushAsync() async -> HeartbeatsPayload { - return await withCheckedContinuation { continuation in - let resetTransform = { (heartbeatsBundle: HeartbeatsBundle?) -> HeartbeatsBundle? in - guard let oldHeartbeatsBundle = heartbeatsBundle else { - return nil // Storage was empty. - } - // The new value that's stored will use the old's cache to prevent the - // logging of duplicates after flushing. - return HeartbeatsBundle( - capacity: self.heartbeatsStorageCapacity, - cache: oldHeartbeatsBundle.lastAddedHeartbeatDates - ) + public func flushAsync(completionHandler: @escaping (HeartbeatsPayload) -> Void) { + let resetTransform = { (heartbeatsBundle: HeartbeatsBundle?) -> HeartbeatsBundle? in + guard let oldHeartbeatsBundle = heartbeatsBundle else { + return nil // Storage was empty. } + // The new value that's stored will use the old's cache to prevent the + // logging of duplicates after flushing. + return HeartbeatsBundle( + capacity: self.heartbeatsStorageCapacity, + cache: oldHeartbeatsBundle.lastAddedHeartbeatDates + ) + } - // Asynchronously gets and returns the stored heartbeats, resetting storage - // using the given transform. - storage.getAndSetAsync(using: resetTransform) { result in - switch result { - case let .success(heartbeatsBundle): - // If no heartbeats bundle was stored, return an empty payload. - continuation - .resume(returning: heartbeatsBundle?.makeHeartbeatsPayload() ?? HeartbeatsPayload - .emptyPayload) - case .failure: - // If the operation throws, assume no heartbeat(s) were retrieved or set. - continuation.resume(returning: HeartbeatsPayload.emptyPayload) - } + // Asynchronously gets and returns the stored heartbeats, resetting storage + // using the given transform. + storage.getAndSetAsync(using: resetTransform) { result in + switch result { + case let .success(heartbeatsBundle): + // If no heartbeats bundle was stored, return an empty payload. + completionHandler(heartbeatsBundle?.makeHeartbeatsPayload() ?? HeartbeatsPayload + .emptyPayload) + case .failure: + // If the operation throws, assume no heartbeat(s) were retrieved or set. + completionHandler(HeartbeatsPayload.emptyPayload) } } } diff --git a/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift b/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift index fdd13af13be..c60a1e11cc5 100644 --- a/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift +++ b/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift @@ -49,10 +49,12 @@ public class _ObjC_HeartbeatController: NSObject { /// /// - Note: This API is thread-safe. /// - Returns: A heartbeats payload for the flushed heartbeat(s). - @available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *) - public func flushAsync() async -> _ObjC_HeartbeatsPayload { - let heartbeatsPayload = await heartbeatController.flushAsync() - return _ObjC_HeartbeatsPayload(heartbeatsPayload) + public func flushAsync(completionHandler: @escaping (_ObjC_HeartbeatsPayload) -> Void) { + // TODO: When minimum version moves to iOS 13.0, restore the async version + // removed in #13952. + heartbeatController.flushAsync { heartbeatsPayload in + completionHandler(_ObjC_HeartbeatsPayload(heartbeatsPayload)) + } } /// Synchronously flushes the heartbeat for today. diff --git a/FirebaseCore/Internal/Tests/Integration/HeartbeatLoggingIntegrationTests.swift b/FirebaseCore/Internal/Tests/Integration/HeartbeatLoggingIntegrationTests.swift index b306405f4bd..3a9823aa94a 100644 --- a/FirebaseCore/Internal/Tests/Integration/HeartbeatLoggingIntegrationTests.swift +++ b/FirebaseCore/Internal/Tests/Integration/HeartbeatLoggingIntegrationTests.swift @@ -52,29 +52,36 @@ class HeartbeatLoggingIntegrationTests: XCTestCase { ) } - @available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *) - func testLogAndFlushAsync() async throws { + func testLogAndFlushAsync() throws { // Given let heartbeatController = HeartbeatController(id: #function) let expectedDate = HeartbeatsPayload.dateFormatter.string(from: Date()) + let expectation = self.expectation(description: #function) // When heartbeatController.log("dummy_agent") - let payload = await heartbeatController.flushAsync() - // Then - try HeartbeatLoggingTestUtils.assertEqualPayloadStrings( - payload.headerValue(), - """ - { - "version": 2, - "heartbeats": [ + heartbeatController.flushAsync { payload in + // Then + do { + try HeartbeatLoggingTestUtils.assertEqualPayloadStrings( + payload.headerValue(), + """ { - "agent": "dummy_agent", - "dates": ["\(expectedDate)"] + "version": 2, + "heartbeats": [ + { + "agent": "dummy_agent", + "dates": ["\(expectedDate)"] + } + ] } - ] + """ + ) + expectation.fulfill() + } catch { + XCTFail("Unexpected error: \(error)") } - """ - ) + } + waitForExpectations(timeout: 1.0) } /// This test may flake if it is executed during the transition from one day to the next. diff --git a/FirebaseCore/Internal/Tests/Unit/HeartbeatControllerTests.swift b/FirebaseCore/Internal/Tests/Unit/HeartbeatControllerTests.swift index ddf3d1c5d9d..82691ed3f24 100644 --- a/FirebaseCore/Internal/Tests/Unit/HeartbeatControllerTests.swift +++ b/FirebaseCore/Internal/Tests/Unit/HeartbeatControllerTests.swift @@ -58,35 +58,41 @@ class HeartbeatControllerTests: XCTestCase { assertHeartbeatControllerFlushesEmptyPayload(controller) } - @available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *) - func testLogAndFlushAsync() async throws { + func testLogAndFlushAsync() throws { // Given let controller = HeartbeatController( storage: HeartbeatStorageFake(), dateProvider: { self.date } ) + let expectation = expectation(description: #function) assertHeartbeatControllerFlushesEmptyPayload(controller) // When controller.log("dummy_agent") - let heartbeatPayload = await controller.flushAsync() - - // Then - try HeartbeatLoggingTestUtils.assertEqualPayloadStrings( - heartbeatPayload.headerValue(), - """ - { - "version": 2, - "heartbeats": [ + controller.flushAsync { heartbeatPayload in + // Then + do { + try HeartbeatLoggingTestUtils.assertEqualPayloadStrings( + heartbeatPayload.headerValue(), + """ { - "agent": "dummy_agent", - "dates": ["2021-11-01"] + "version": 2, + "heartbeats": [ + { + "agent": "dummy_agent", + "dates": ["2021-11-01"] + } + ] } - ] + """ + ) + expectation.fulfill() + } catch { + XCTFail("Unexpected error: \(error)") } - """ - ) + } + waitForExpectations(timeout: 1.0) assertHeartbeatControllerFlushesEmptyPayload(controller) } diff --git a/FirebaseCore/Sources/FIRHeartbeatLogger.m b/FirebaseCore/Sources/FIRHeartbeatLogger.m index d1c77ee4f2f..4becd085c22 100644 --- a/FirebaseCore/Sources/FIRHeartbeatLogger.m +++ b/FirebaseCore/Sources/FIRHeartbeatLogger.m @@ -87,7 +87,8 @@ - (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload { } - (void)flushHeartbeatsIntoPayloadWithCompletionHandler: - (void (^)(FIRHeartbeatsPayload *))completionHandler { + (void (^)(FIRHeartbeatsPayload *))completionHandler + API_AVAILABLE(ios(13.0), macosx(10.15), macCatalyst(13.0), tvos(13.0), watchos(6.0)) { [_heartbeatController flushAsyncWithCompletionHandler:^(FIRHeartbeatsPayload *payload) { completionHandler(payload); }]; diff --git a/FirebaseCoreInternal.podspec b/FirebaseCoreInternal.podspec index df449a9b8c6..38cd7901466 100644 --- a/FirebaseCoreInternal.podspec +++ b/FirebaseCoreInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCoreInternal' - s.version = '11.4.0' + s.version = '11.4.2' s.summary = 'APIs for internal FirebaseCore usage.' s.description = <<-DESC