From ef1b4eba7ff9a8e7818547bd503fbb9680ec6329 Mon Sep 17 00:00:00 2001 From: Nikita Vasilev Date: Sat, 5 Apr 2025 20:01:52 +0400 Subject: [PATCH 1/2] Implement `AsyncStream` to listen for remote config updates --- .../Swift/RemoteConfig+AsyncStream.swift | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 FirebaseRemoteConfig/Swift/RemoteConfig+AsyncStream.swift diff --git a/FirebaseRemoteConfig/Swift/RemoteConfig+AsyncStream.swift b/FirebaseRemoteConfig/Swift/RemoteConfig+AsyncStream.swift new file mode 100644 index 00000000000..817f28b2b2b --- /dev/null +++ b/FirebaseRemoteConfig/Swift/RemoteConfig+AsyncStream.swift @@ -0,0 +1,32 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +public extension RemoteConfig { + /// Asynchronous stream of configuration updates. + @available(iOS 13.0, macOS 10.15, macCatalyst 13.0, watchOS 7.0, tvOS 13.0, *) + var updateStream: AsyncStream> { + AsyncStream { continuation in + let registration = self.addOnConfigUpdateListener { update, error in + if let error = error { + continuation.yield(.failure(error)) + } else if let update { + continuation.yield(.success(update)) + } + } + continuation.onTermination = { _ in + registration.remove() + } + } + } +} From 75787315bb458f873838115ec4a3e6b3282b3848 Mon Sep 17 00:00:00 2001 From: Nikita Vasilev Date: Sat, 5 Apr 2025 20:03:42 +0400 Subject: [PATCH 2/2] Implement a unit test for updating the remote configuration --- .../Tests/Swift/SwiftAPI/APITests.swift | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/FirebaseRemoteConfig/Tests/Swift/SwiftAPI/APITests.swift b/FirebaseRemoteConfig/Tests/Swift/SwiftAPI/APITests.swift index 6665dd91258..9ba76758a7c 100644 --- a/FirebaseRemoteConfig/Tests/Swift/SwiftAPI/APITests.swift +++ b/FirebaseRemoteConfig/Tests/Swift/SwiftAPI/APITests.swift @@ -179,6 +179,31 @@ class APITests: APITestBase { registration.remove() } + func testRealtimeRemoteConfigRealConsoleAsync() async { + guard APITests.useFakeConfig == false else { return } + + let expectation = expectation(description: #function) + + let task = Task { + for await updateResult in config.updateStream { + switch updateResult { + case let .success(update): + XCTAssertNotNil(update) + XCTAssertNotNil(update.updatedKeys.contains(Constants.jedi)) + case let .failure(error): + XCTFail("Expected a successful update result, but received an error: \(error)") + } + + expectation.fulfill() + } + } + + console.updateRemoteConfigValue(Constants.yoda, forKey: Constants.jedi) + + await fulfillment(of: [expectation], timeout: 5.0) + task.cancel() + } + // MARK: - RemoteConfigConsole Tests func testFetchConfigThenUpdateConsoleThenFetchAgain() {