From b33b85ef104ab20e6b45c5ae66c5eef23bdc4eb6 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 15 Jul 2025 14:49:49 -0400 Subject: [PATCH 01/76] [Infra] Carthage artifacts for 12.0.0 (#15118) --- ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAIBinary.json | 3 ++- ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json | 1 + .../CarthageJSON/FirebaseMLModelDownloaderBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json | 1 + 17 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json index a2a0118d1fb..cf57a499bd7 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json @@ -44,6 +44,7 @@ "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebaseABTesting-76f42e76c5778188.zip", "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseABTesting-14bbd5283f79341d.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseABTesting-5436773ba2b9326e.zip", + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseABTesting-bd721c84362383a6.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/ABTesting-d0fdf10c43e985b1.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/ABTesting-d0fdf10c43e985b1.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/ABTesting-a71d17cadc209af9.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json index 4e7b9056455..f7024c4b7bd 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json @@ -1,5 +1,6 @@ { "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAI-b1e75ff6284775b1.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseAI-0991ef5c3a83833a.zip", - "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseAI-ba1237ee5b7a5baa.zip" + "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseAI-ba1237ee5b7a5baa.zip", + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseAI-05a4568076093001.zip" } diff --git a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json index f7ff0a95f02..57b27800483 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json @@ -44,6 +44,7 @@ "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebaseAnalytics-74a530056782a0ed.zip", "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseAnalytics-0929c5c36f6a3dd2.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseAnalytics-fe649e5740ef72e9.zip", + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseAnalytics-70ead21957efa870.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Analytics-2468c231ebeb7922.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Analytics-bc8101d420b896c5.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Analytics-d2b6a6b0242db786.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json index 2344d3aed80..65a947bb3a0 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json @@ -44,6 +44,7 @@ "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebaseAppCheck-31041ca049010d8b.zip", "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseAppCheck-68439fef0d9ee01c.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseAppCheck-366c926c105319b0.zip", + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseAppCheck-b9f47f169bb6249c.zip", "8.0.0": "https://dl.google.com/dl/firebase/ios/carthage/8.0.0/FirebaseAppCheck-9ef1d217cf057203.zip", "8.1.0": "https://dl.google.com/dl/firebase/ios/carthage/8.1.0/FirebaseAppCheck-fc03215d9fe45d3a.zip", "8.10.0": "https://dl.google.com/dl/firebase/ios/carthage/8.10.0/FirebaseAppCheck-6ebe9e9539f06003.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json index b86174efba7..a0ad51cc2fd 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json @@ -44,6 +44,7 @@ "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebaseAppDistribution-908bdcdc87eee86b.zip", "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseAppDistribution-e558ade73b5891d6.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseAppDistribution-32e12df219d91736.zip", + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseAppDistribution-076c2c6efb7eb8dc.zip", "6.31.0": "https://dl.google.com/dl/firebase/ios/carthage/6.31.0/FirebaseAppDistribution-07f6a2cf7f576a8a.zip", "6.32.0": "https://dl.google.com/dl/firebase/ios/carthage/6.32.0/FirebaseAppDistribution-a9c4f5db794508ca.zip", "6.33.0": "https://dl.google.com/dl/firebase/ios/carthage/6.33.0/FirebaseAppDistribution-448a96d2ade54581.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json index 596d5a8116a..7c63aa2557c 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json @@ -44,6 +44,7 @@ "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebaseAuth-24605cbb83eadb6e.zip", "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseAuth-f41dc3e6a1a923d7.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseAuth-ab131b2e07abc902.zip", + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseAuth-e58b2b5f430bfbfe.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Auth-0fa76ba0f7956220.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Auth-5ddd2b4351012c7a.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Auth-5e248984d78d7284.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json index e86ca152e55..1ff9582109d 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json @@ -44,6 +44,7 @@ "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebaseCrashlytics-066561f91425ee41.zip", "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseCrashlytics-36f932dcd3db6874.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseCrashlytics-81aa29d9a106acb0.zip", + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseCrashlytics-d9a9be2a4e220017.zip", "6.15.0": "https://dl.google.com/dl/firebase/ios/carthage/6.15.0/FirebaseCrashlytics-1c6d22d5b73c84fd.zip", "6.16.0": "https://dl.google.com/dl/firebase/ios/carthage/6.16.0/FirebaseCrashlytics-938e5fd0e2eab3b3.zip", "6.17.0": "https://dl.google.com/dl/firebase/ios/carthage/6.17.0/FirebaseCrashlytics-fa09f0c8f31ed5d9.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json b/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json index 71718147ec6..fc72965de98 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json @@ -44,6 +44,7 @@ "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebaseDatabase-665f1d12ee1c5583.zip", "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseDatabase-8e544ced90fb6eb2.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseDatabase-8b970d6e0f67a415.zip", + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseDatabase-18b95ef28b89f3db.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Database-1f7a820452722c7d.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Database-1f7a820452722c7d.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Database-59a12d87456b3e1c.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json b/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json index d482b503303..66d2d9882c0 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json @@ -44,6 +44,7 @@ "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebaseFirestore-b234cb861ecaaabe.zip", "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseFirestore-792558f0eddb9934.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseFirestore-30a2451150d46015.zip", + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseFirestore-635c7c2864cdd1a9.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Firestore-68fc02c229d0cc69.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Firestore-87a804ab561d91db.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Firestore-ecb3eea7bde7e8e8.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json index ba156e8b3c3..87255957bf9 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json @@ -44,6 +44,7 @@ "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebaseFunctions-1b9c374ba8165fcb.zip", "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseFunctions-e85bcbe133482bbc.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseFunctions-1681244d37d89040.zip", + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseFunctions-2ac7bbbaf94c52e1.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Functions-f4c426016dd41e38.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Functions-c6c44427c3034736.zip", "5.0.0": "https://dl.google.com/dl/firebase/ios/carthage/5.0.0/Functions-146f34c401bd459b.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json b/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json index 945e0372292..42ea689c712 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json @@ -44,6 +44,7 @@ "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/GoogleSignIn-e745ddfd77045287.zip", "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/GoogleSignIn-45d907510d5c840b.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/GoogleSignIn-d4359fb699843869.zip", + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/GoogleSignIn-b924d38d37bc920a.zip", "6.0.0": "https://dl.google.com/dl/firebase/ios/carthage/6.0.0/GoogleSignIn-de9c5d5e8eb6d6ea.zip", "6.1.0": "https://dl.google.com/dl/firebase/ios/carthage/6.1.0/GoogleSignIn-8c82f2870573a793.zip", "6.10.0": "https://dl.google.com/dl/firebase/ios/carthage/6.10.0/GoogleSignIn-ff3aef61c4a55b05.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json index f7d04b01c31..53f4da612a0 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json @@ -44,6 +44,7 @@ "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebaseInAppMessaging-ee6bedaea672150b.zip", "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseInAppMessaging-af2b93ac9f853087.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseInAppMessaging-67bccdf31b1dc458.zip", + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseInAppMessaging-59f9fc54fc4eecb5.zip", "5.10.0": "https://dl.google.com/dl/firebase/ios/carthage/5.10.0/InAppMessaging-a7a3f933362f6e95.zip", "5.11.0": "https://dl.google.com/dl/firebase/ios/carthage/5.11.0/InAppMessaging-fa28ce1b88fbca93.zip", "5.12.0": "https://dl.google.com/dl/firebase/ios/carthage/5.12.0/InAppMessaging-fa28ce1b88fbca93.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json b/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json index 193446fc061..646fbacad35 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json @@ -44,6 +44,7 @@ "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebaseMLModelDownloader-6c596e97794f0430.zip", "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseMLModelDownloader-373db3aced970d88.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseMLModelDownloader-2d08410294abf160.zip", + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseMLModelDownloader-1f183c6e3be7cab3.zip", "8.0.0": "https://dl.google.com/dl/firebase/ios/carthage/8.0.0/FirebaseMLModelDownloader-8f972757fb181320.zip", "8.1.0": "https://dl.google.com/dl/firebase/ios/carthage/8.1.0/FirebaseMLModelDownloader-058ad59fa6dc0111.zip", "8.10.0": "https://dl.google.com/dl/firebase/ios/carthage/8.10.0/FirebaseMLModelDownloader-286479a966d2fb37.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json index b48d93e0ea1..c33b12a6473 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json @@ -44,6 +44,7 @@ "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebaseMessaging-9d0027ada8995751.zip", "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseMessaging-ffd97136b9f3cde5.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseMessaging-379bf3738f94ef44.zip", + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseMessaging-0f018ab3d7701839.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Messaging-a22ef2b5f2f30f82.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Messaging-94fa4e090c7e9185.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Messaging-2a00a1c64a19d176.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json b/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json index 1c75aa6bebf..939a7832128 100644 --- a/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json @@ -44,6 +44,7 @@ "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebasePerformance-3b0d7bf17d771ece.zip", "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebasePerformance-e7063e87d9b3d1b7.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebasePerformance-9a2f8d3983650cea.zip", + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebasePerformance-0df8c67ab3cb665c.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Performance-d8693eb892bfa05b.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Performance-0a400f9460f7a71d.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Performance-f5b4002ab96523e4.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json b/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json index 0d5ccc12c74..fb0b84442a7 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json @@ -44,6 +44,7 @@ "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebaseRemoteConfig-68b7ad270036fef7.zip", "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseRemoteConfig-6e66634da4590f07.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseRemoteConfig-7455afe6f2231467.zip", + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseRemoteConfig-5894aa4820a265ae.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/RemoteConfig-7e9635365ccd4a17.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/RemoteConfig-e7928fcb6311c439.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/RemoteConfig-9ab1ca5f360a1780.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json b/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json index 8868dc94ecc..69838986e91 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json @@ -44,6 +44,7 @@ "11.7.0": "https://dl.google.com/dl/firebase/ios/carthage/11.7.0/FirebaseStorage-1fb496e024a9eb57.zip", "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseStorage-f55cadd62f44b14f.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseStorage-5a28ee1b2244be55.zip", + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseStorage-21ed034a4fa51f2a.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Storage-6b3e77e1a7fdbc61.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Storage-4721c35d2b90a569.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Storage-821299369b9d0fb2.zip", From 6f1258305523dfdd40d01c0f200152732d127fe5 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Tue, 15 Jul 2025 17:53:23 -0400 Subject: [PATCH 02/76] [Firebase AI] Fix `Chat` history append locking (#15115) Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- FirebaseAI/Sources/Chat.swift | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/FirebaseAI/Sources/Chat.swift b/FirebaseAI/Sources/Chat.swift index 1aa2c3490c7..42da2ef4a6d 100644 --- a/FirebaseAI/Sources/Chat.swift +++ b/FirebaseAI/Sources/Chat.swift @@ -45,6 +45,12 @@ public final class Chat: Sendable { } } + private func appendHistory(_ newElement: ModelContent) { + historyLock.withLock { + _history.append(newElement) + } + } + /// Sends a message using the existing history of this chat as context. If successful, the message /// and response will be added to the history. If unsuccessful, history will remain unchanged. /// - Parameter parts: The new content to send as a single chat message. @@ -82,7 +88,7 @@ public final class Chat: Sendable { // Append the request and successful result to history, then return the value. appendHistory(contentsOf: newContent) - history.append(toAdd) + appendHistory(toAdd) return result } @@ -134,7 +140,7 @@ public final class Chat: Sendable { // Aggregate the content to add it to the history before we finish. let aggregated = self.aggregatedChunks(aggregatedContent) - self.history.append(aggregated) + self.appendHistory(aggregated) continuation.finish() } } From 59c760160457a8fba27fa2f65f42c40c01470056 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 16 Jul 2025 10:21:30 -0400 Subject: [PATCH 03/76] [Infra] Update versions for Release 12.1.0 (#15120) --- Firebase.podspec | 44 +++++++++---------- FirebaseABTesting.podspec | 4 +- FirebaseAI.podspec | 10 ++--- FirebaseAnalytics.podspec | 12 ++--- FirebaseAppCheck.podspec | 6 +-- FirebaseAppCheckInterop.podspec | 2 +- FirebaseAppDistribution.podspec | 6 +-- FirebaseAuth.podspec | 10 ++--- FirebaseAuthInterop.podspec | 2 +- FirebaseCombineSwift.podspec | 14 +++--- FirebaseCore.podspec | 4 +- FirebaseCoreExtension.podspec | 4 +- FirebaseCoreInternal.podspec | 2 +- FirebaseCrashlytics.podspec | 10 ++--- FirebaseDatabase.podspec | 10 ++--- FirebaseFirestore.podspec | 10 ++--- FirebaseFirestoreInternal.podspec | 6 +-- FirebaseFunctions.podspec | 14 +++--- FirebaseInAppMessaging.podspec | 8 ++-- FirebaseInstallations.podspec | 4 +- FirebaseMLModelDownloader.podspec | 8 ++-- FirebaseMessaging.podspec | 6 +-- FirebaseMessagingInterop.podspec | 2 +- FirebasePerformance.podspec | 10 ++--- FirebaseRemoteConfig.podspec | 12 ++--- FirebaseRemoteConfigInterop.podspec | 2 +- FirebaseSessions.podspec | 8 ++-- FirebaseSharedSwift.podspec | 2 +- FirebaseStorage.podspec | 14 +++--- GoogleAppMeasurement.podspec | 8 ++-- Package.swift | 2 +- .../FirebaseManifest/FirebaseManifest.swift | 2 +- .../FirebaseReleaser/InitializeRelease.swift | 29 +++--------- 33 files changed, 135 insertions(+), 152 deletions(-) diff --git a/Firebase.podspec b/Firebase.podspec index 197ce7ab758..cada41f66c4 100644 --- a/Firebase.podspec +++ b/Firebase.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Firebase' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Firebase' s.description = <<-DESC @@ -36,14 +36,14 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '15.0' - ss.ios.dependency 'FirebaseAnalytics', '~> 12.0.0' - ss.osx.dependency 'FirebaseAnalytics', '~> 12.0.0' - ss.tvos.dependency 'FirebaseAnalytics', '~> 12.0.0' + ss.ios.dependency 'FirebaseAnalytics', '~> 12.1.0' + ss.osx.dependency 'FirebaseAnalytics', '~> 12.1.0' + ss.tvos.dependency 'FirebaseAnalytics', '~> 12.1.0' ss.dependency 'Firebase/CoreOnly' end s.subspec 'CoreOnly' do |ss| - ss.dependency 'FirebaseCore', '~> 12.0.0' + ss.dependency 'FirebaseCore', '~> 12.1.0' ss.source_files = 'CoreOnly/Sources/Firebase.h' ss.preserve_paths = 'CoreOnly/Sources/module.modulemap' if ENV['FIREBASE_POD_REPO_FOR_DEV_POD'] then @@ -70,7 +70,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'ABTesting' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseABTesting', '~> 12.0.0' + ss.dependency 'FirebaseABTesting', '~> 12.1.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -80,13 +80,13 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'AppDistribution' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseAppDistribution', '~> 12.0.0-beta' + ss.ios.dependency 'FirebaseAppDistribution', '~> 12.1.0-beta' ss.ios.deployment_target = '15.0' end s.subspec 'AppCheck' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseAppCheck', '~> 12.0.0' + ss.dependency 'FirebaseAppCheck', '~> 12.1.0' ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '15.0' @@ -95,7 +95,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Auth' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseAuth', '~> 12.0.0' + ss.dependency 'FirebaseAuth', '~> 12.1.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -105,7 +105,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Crashlytics' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseCrashlytics', '~> 12.0.0' + ss.dependency 'FirebaseCrashlytics', '~> 12.1.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -115,7 +115,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Database' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseDatabase', '~> 12.0.0' + ss.dependency 'FirebaseDatabase', '~> 12.1.0' # Standard platforms PLUS watchOS 7. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -125,7 +125,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Firestore' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseFirestore', '~> 12.0.0' + ss.dependency 'FirebaseFirestore', '~> 12.1.0' ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' ss.ios.deployment_target = '15.0' @@ -133,7 +133,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Functions' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseFunctions', '~> 12.0.0' + ss.dependency 'FirebaseFunctions', '~> 12.1.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -143,20 +143,20 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'InAppMessaging' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseInAppMessaging', '~> 12.0.0-beta' - ss.tvos.dependency 'FirebaseInAppMessaging', '~> 12.0.0-beta' + ss.ios.dependency 'FirebaseInAppMessaging', '~> 12.1.0-beta' + ss.tvos.dependency 'FirebaseInAppMessaging', '~> 12.1.0-beta' ss.ios.deployment_target = '15.0' ss.tvos.deployment_target = '15.0' end s.subspec 'Installations' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseInstallations', '~> 12.0.0' + ss.dependency 'FirebaseInstallations', '~> 12.1.0' end s.subspec 'Messaging' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseMessaging', '~> 12.0.0' + ss.dependency 'FirebaseMessaging', '~> 12.1.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -166,7 +166,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'MLModelDownloader' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseMLModelDownloader', '~> 12.0.0-beta' + ss.dependency 'FirebaseMLModelDownloader', '~> 12.1.0-beta' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -176,15 +176,15 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Performance' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebasePerformance', '~> 12.0.0' - ss.tvos.dependency 'FirebasePerformance', '~> 12.0.0' + ss.ios.dependency 'FirebasePerformance', '~> 12.1.0' + ss.tvos.dependency 'FirebasePerformance', '~> 12.1.0' ss.ios.deployment_target = '15.0' ss.tvos.deployment_target = '15.0' end s.subspec 'RemoteConfig' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseRemoteConfig', '~> 12.0.0' + ss.dependency 'FirebaseRemoteConfig', '~> 12.1.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -194,7 +194,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Storage' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseStorage', '~> 12.0.0' + ss.dependency 'FirebaseStorage', '~> 12.1.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' diff --git a/FirebaseABTesting.podspec b/FirebaseABTesting.podspec index d1ce2aaa4b9..ea2ec8c25a2 100644 --- a/FirebaseABTesting.podspec +++ b/FirebaseABTesting.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseABTesting' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Firebase ABTesting' s.description = <<-DESC @@ -51,7 +51,7 @@ Firebase Cloud Messaging and Firebase Remote Config in your app. s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } - s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseCore', '~> 12.1.0' s.test_spec 'unit' do |unit_tests| unit_tests.scheme = { :code_coverage => true } diff --git a/FirebaseAI.podspec b/FirebaseAI.podspec index a8ffa35789d..24c91ff90ac 100644 --- a/FirebaseAI.podspec +++ b/FirebaseAI.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAI' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Firebase AI SDK' s.description = <<-DESC @@ -43,10 +43,10 @@ Build AI-powered apps and features with the Gemini API using the Firebase AI SDK s.tvos.framework = 'UIKit' s.watchos.framework = 'WatchKit' - s.dependency 'FirebaseAppCheckInterop', '~> 12.0.0' - s.dependency 'FirebaseAuthInterop', '~> 12.0.0' - s.dependency 'FirebaseCore', '~> 12.0.0' - s.dependency 'FirebaseCoreExtension', '~> 12.0.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.1.0' + s.dependency 'FirebaseAuthInterop', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseCoreExtension', '~> 12.1.0' s.test_spec 'unit' do |unit_tests| unit_tests_dir = 'FirebaseAI/Tests/Unit/' diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index d748235aea5..b8e7190bde5 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAnalytics' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Firebase Analytics for iOS' s.description = <<-DESC @@ -26,8 +26,8 @@ Pod::Spec.new do |s| s.libraries = 'c++', 'sqlite3', 'z' s.frameworks = 'StoreKit' - s.dependency 'FirebaseCore', '~> 12.0.0' - s.dependency 'FirebaseInstallations', '~> 12.0.0' + s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseInstallations', '~> 12.1.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/MethodSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/NSData+zlib', '~> 8.1' @@ -37,17 +37,17 @@ Pod::Spec.new do |s| s.default_subspecs = 'Default' s.subspec 'Default' do |ss| - ss.dependency 'GoogleAppMeasurement/Default', '12.0.0' + ss.dependency 'GoogleAppMeasurement/Default', '12.1.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end s.subspec 'Core' do |ss| - ss.dependency 'GoogleAppMeasurement/Core', '12.0.0' + ss.dependency 'GoogleAppMeasurement/Core', '12.1.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end s.subspec 'IdentitySupport' do |ss| - ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.0.0' + ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.1.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end diff --git a/FirebaseAppCheck.podspec b/FirebaseAppCheck.podspec index 51b36c2bedd..1aad2a45a7d 100644 --- a/FirebaseAppCheck.podspec +++ b/FirebaseAppCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppCheck' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Firebase App Check SDK.' s.description = <<-DESC @@ -45,8 +45,8 @@ Pod::Spec.new do |s| s.tvos.weak_framework = 'DeviceCheck' s.dependency 'AppCheckCore', '~> 11.0' - s.dependency 'FirebaseAppCheckInterop', '~> 12.0.0' - s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.1.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseAppCheckInterop.podspec b/FirebaseAppCheckInterop.podspec index 427530ab4fc..0f53cfb45f9 100644 --- a/FirebaseAppCheckInterop.podspec +++ b/FirebaseAppCheckInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppCheckInterop' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Interfaces that allow other Firebase SDKs to use AppCheck functionality.' s.description = <<-DESC diff --git a/FirebaseAppDistribution.podspec b/FirebaseAppDistribution.podspec index 13abf86d57d..f438f03a7e9 100644 --- a/FirebaseAppDistribution.podspec +++ b/FirebaseAppDistribution.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppDistribution' - s.version = '12.0.0-beta' + s.version = '12.1.0-beta' s.summary = 'App Distribution for Firebase iOS SDK.' s.description = <<-DESC @@ -30,10 +30,10 @@ iOS SDK for App Distribution for Firebase. ] s.public_header_files = base_dir + 'Public/FirebaseAppDistribution/*.h' - s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseCore', '~> 12.1.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' - s.dependency 'FirebaseInstallations', '~> 12.0.0' + s.dependency 'FirebaseInstallations', '~> 12.1.0' s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' diff --git a/FirebaseAuth.podspec b/FirebaseAuth.podspec index 1f16ebcad86..d89d0e222fb 100644 --- a/FirebaseAuth.podspec +++ b/FirebaseAuth.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAuth' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Apple platform client for Firebase Authentication' s.description = <<-DESC @@ -55,10 +55,10 @@ supports email and password accounts, as well as several 3rd party authenticatio } s.framework = 'Security' s.ios.framework = 'SafariServices' - s.dependency 'FirebaseAuthInterop', '~> 12.0.0' - s.dependency 'FirebaseAppCheckInterop', '~> 12.0.0' - s.dependency 'FirebaseCore', '~> 12.0.0' - s.dependency 'FirebaseCoreExtension', '~> 12.0.0' + s.dependency 'FirebaseAuthInterop', '~> 12.1.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseCoreExtension', '~> 12.1.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 6.0' diff --git a/FirebaseAuthInterop.podspec b/FirebaseAuthInterop.podspec index c1f9df6ed18..e20e453e484 100644 --- a/FirebaseAuthInterop.podspec +++ b/FirebaseAuthInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAuthInterop' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Auth functionality.' s.description = <<-DESC diff --git a/FirebaseCombineSwift.podspec b/FirebaseCombineSwift.podspec index ff78436f4d0..22fda02d2fe 100644 --- a/FirebaseCombineSwift.podspec +++ b/FirebaseCombineSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCombineSwift' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Swift extensions with Combine support for Firebase' s.description = <<-DESC @@ -51,11 +51,11 @@ for internal testing only. It should not be published. s.osx.framework = 'AppKit' s.tvos.framework = 'UIKit' - s.dependency 'FirebaseCore', '~> 12.0.0' - s.dependency 'FirebaseAuth', '~> 12.0.0' - s.dependency 'FirebaseFunctions', '~> 12.0.0' - s.dependency 'FirebaseFirestore', '~> 12.0.0' - s.dependency 'FirebaseStorage', '~> 12.0.0' + s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseAuth', '~> 12.1.0' + s.dependency 'FirebaseFunctions', '~> 12.1.0' + s.dependency 'FirebaseFirestore', '~> 12.1.0' + s.dependency 'FirebaseStorage', '~> 12.1.0' s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"', @@ -104,6 +104,6 @@ for internal testing only. It should not be published. int_tests.resources = 'FirebaseStorage/Tests/Integration/Resources/1mb.dat', 'FirebaseStorage/Tests/Integration/Resources/GoogleService-Info.plist', 'FirebaseStorage/Tests/Integration/Resources/HomeImprovement.numbers' - int_tests.dependency 'FirebaseAuth', '~> 12.0.0' + int_tests.dependency 'FirebaseAuth', '~> 12.1.0' end end diff --git a/FirebaseCore.podspec b/FirebaseCore.podspec index 7ad1c4509cf..9767f1c893e 100644 --- a/FirebaseCore.podspec +++ b/FirebaseCore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCore' - s.version = '12.0.0' + s.version = '12.1.0' 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.1' s.dependency 'GoogleUtilities/Logger', '~> 8.1' - s.dependency 'FirebaseCoreInternal', '~> 12.0.0' + s.dependency 'FirebaseCoreInternal', '~> 12.1.0' s.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'Firebase_VERSION=' + s.version.to_s, diff --git a/FirebaseCoreExtension.podspec b/FirebaseCoreExtension.podspec index 8171d0c5e31..4458e7e9cd3 100644 --- a/FirebaseCoreExtension.podspec +++ b/FirebaseCoreExtension.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCoreExtension' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Extended FirebaseCore APIs for Firebase product SDKs' s.description = <<-DESC @@ -34,5 +34,5 @@ Pod::Spec.new do |s| "#{s.module_name}_Privacy" => 'FirebaseCore/Extension/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseCore', '~> 12.1.0' end diff --git a/FirebaseCoreInternal.podspec b/FirebaseCoreInternal.podspec index 8def2d194ed..e75d03cb018 100644 --- a/FirebaseCoreInternal.podspec +++ b/FirebaseCoreInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCoreInternal' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'APIs for internal FirebaseCore usage.' s.description = <<-DESC diff --git a/FirebaseCrashlytics.podspec b/FirebaseCrashlytics.podspec index 41679ea1fb0..22b9cc1e163 100644 --- a/FirebaseCrashlytics.podspec +++ b/FirebaseCrashlytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCrashlytics' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Best and lightest-weight crash reporting for mobile, desktop and tvOS.' s.description = 'Firebase Crashlytics helps you track, prioritize, and fix stability issues that erode app quality.' s.homepage = 'https://firebase.google.com/' @@ -59,10 +59,10 @@ Pod::Spec.new do |s| cp -f ./Crashlytics/CrashlyticsInputFiles.xcfilelist ./CrashlyticsInputFiles.xcfilelist PREPARE_COMMAND_END - s.dependency 'FirebaseCore', '~> 12.0.0' - s.dependency 'FirebaseInstallations', '~> 12.0.0' - s.dependency 'FirebaseSessions', '~> 12.0.0' - s.dependency 'FirebaseRemoteConfigInterop', '~> 12.0.0' + s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseInstallations', '~> 12.1.0' + s.dependency 'FirebaseSessions', '~> 12.1.0' + s.dependency 'FirebaseRemoteConfigInterop', '~> 12.1.0' s.dependency 'PromisesObjC', '~> 2.4' s.dependency 'GoogleDataTransport', '~> 10.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' diff --git a/FirebaseDatabase.podspec b/FirebaseDatabase.podspec index faa2503c774..4ab36e76ed3 100644 --- a/FirebaseDatabase.podspec +++ b/FirebaseDatabase.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseDatabase' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Firebase Realtime Database' s.description = <<-DESC @@ -48,9 +48,9 @@ Simplify your iOS development, grow your user base, and monetize more effectivel s.macos.frameworks = 'CFNetwork', 'Security', 'SystemConfiguration' s.watchos.frameworks = 'CFNetwork', 'Security', 'WatchKit' s.dependency 'leveldb-library', '~> 1.22' - s.dependency 'FirebaseCore', '~> 12.0.0' - s.dependency 'FirebaseAppCheckInterop', '~> 12.0.0' - s.dependency 'FirebaseSharedSwift', '~> 12.0.0' + s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.1.0' + s.dependency 'FirebaseSharedSwift', '~> 12.1.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' @@ -72,7 +72,7 @@ Simplify your iOS development, grow your user base, and monetize more effectivel 'SharedTestUtilities/FIRComponentTestUtilities.[mh]', 'SharedTestUtilities/FIROptionsMock.[mh]', ] - unit_tests.dependency 'FirebaseAppCheckInterop', '~> 12.0.0' + unit_tests.dependency 'FirebaseAppCheckInterop', '~> 12.1.0' unit_tests.dependency 'OCMock' unit_tests.resources = 'FirebaseDatabase/Tests/Resources/syncPointSpec.json', 'FirebaseDatabase/Tests/Resources/GoogleService-Info.plist' diff --git a/FirebaseFirestore.podspec b/FirebaseFirestore.podspec index 72c0d6754e5..42a937b7681 100644 --- a/FirebaseFirestore.podspec +++ b/FirebaseFirestore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFirestore' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Google Cloud Firestore' s.description = <<-DESC Google Cloud Firestore is a NoSQL document database built for automatic scaling, high performance, and ease of application development. @@ -35,9 +35,9 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, "#{s.module_name}_Privacy" => 'Firestore/Swift/Source/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '~> 12.0.0' - s.dependency 'FirebaseCoreExtension', '~> 12.0.0' - s.dependency 'FirebaseFirestoreInternal', '~> 12.0.0' - s.dependency 'FirebaseSharedSwift', '~> 12.0.0' + s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseCoreExtension', '~> 12.1.0' + s.dependency 'FirebaseFirestoreInternal', '~> 12.1.0' + s.dependency 'FirebaseSharedSwift', '~> 12.1.0' end diff --git a/FirebaseFirestoreInternal.podspec b/FirebaseFirestoreInternal.podspec index 05c72462cd0..57e9ce8bfd1 100644 --- a/FirebaseFirestoreInternal.podspec +++ b/FirebaseFirestoreInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFirestoreInternal' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Google Cloud Firestore' s.description = <<-DESC @@ -91,8 +91,8 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, "#{s.module_name}_Privacy" => 'Firestore/Source/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseAppCheckInterop', '~> 12.0.0' - s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.1.0' abseil_version = '~> 1.20240722.0' s.dependency 'abseil/algorithm', abseil_version diff --git a/FirebaseFunctions.podspec b/FirebaseFunctions.podspec index f75ae1f809d..b26ef279af2 100644 --- a/FirebaseFunctions.podspec +++ b/FirebaseFunctions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFunctions' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Cloud Functions for Firebase' s.description = <<-DESC @@ -35,12 +35,12 @@ Cloud Functions for Firebase. 'FirebaseFunctions/Sources/**/*.swift', ] - s.dependency 'FirebaseCore', '~> 12.0.0' - s.dependency 'FirebaseCoreExtension', '~> 12.0.0' - s.dependency 'FirebaseAppCheckInterop', '~> 12.0.0' - s.dependency 'FirebaseAuthInterop', '~> 12.0.0' - s.dependency 'FirebaseMessagingInterop', '~> 12.0.0' - s.dependency 'FirebaseSharedSwift', '~> 12.0.0' + s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseCoreExtension', '~> 12.1.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.1.0' + s.dependency 'FirebaseAuthInterop', '~> 12.1.0' + s.dependency 'FirebaseMessagingInterop', '~> 12.1.0' + s.dependency 'FirebaseSharedSwift', '~> 12.1.0' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 6.0' s.test_spec 'objc' do |objc_tests| diff --git a/FirebaseInAppMessaging.podspec b/FirebaseInAppMessaging.podspec index 27e3f275853..ef773f8c441 100644 --- a/FirebaseInAppMessaging.podspec +++ b/FirebaseInAppMessaging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseInAppMessaging' - s.version = '12.0.0-beta' + s.version = '12.1.0-beta' s.summary = 'Firebase In-App Messaging for iOS' s.description = <<-DESC @@ -80,9 +80,9 @@ See more product details at https://firebase.google.com/products/in-app-messagin s.framework = 'UIKit' - s.dependency 'FirebaseCore', '~> 12.0.0' - s.dependency 'FirebaseInstallations', '~> 12.0.0' - s.dependency 'FirebaseABTesting', '~> 12.0.0' + s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseInstallations', '~> 12.1.0' + s.dependency 'FirebaseABTesting', '~> 12.1.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' s.dependency 'nanopb', '~> 3.30910.0' diff --git a/FirebaseInstallations.podspec b/FirebaseInstallations.podspec index 6973f91be45..87b49973f1d 100644 --- a/FirebaseInstallations.podspec +++ b/FirebaseInstallations.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseInstallations' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Firebase Installations' s.description = <<-DESC @@ -45,7 +45,7 @@ Pod::Spec.new do |s| } s.framework = 'Security' - s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseCore', '~> 12.1.0' s.dependency 'PromisesObjC', '~> 2.4' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseMLModelDownloader.podspec b/FirebaseMLModelDownloader.podspec index a21110e4a04..7fa88c88c95 100644 --- a/FirebaseMLModelDownloader.podspec +++ b/FirebaseMLModelDownloader.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMLModelDownloader' - s.version = '12.0.0-beta' + s.version = '12.1.0-beta' s.summary = 'Firebase ML Model Downloader' s.description = <<-DESC @@ -36,9 +36,9 @@ Pod::Spec.new do |s| ] s.framework = 'Foundation' - s.dependency 'FirebaseCore', '~> 12.0.0' - s.dependency 'FirebaseCoreExtension', '~> 12.0.0' - s.dependency 'FirebaseInstallations', '~> 12.0.0' + s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseCoreExtension', '~> 12.1.0' + s.dependency 'FirebaseInstallations', '~> 12.1.0' s.dependency 'GoogleDataTransport', '~> 10.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' s.dependency 'SwiftProtobuf', '~> 1.19' diff --git a/FirebaseMessaging.podspec b/FirebaseMessaging.podspec index 627268c0891..96b25677379 100644 --- a/FirebaseMessaging.podspec +++ b/FirebaseMessaging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMessaging' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Firebase Messaging' s.description = <<-DESC @@ -60,8 +60,8 @@ device, and it is completely free. s.tvos.framework = 'SystemConfiguration' s.osx.framework = 'SystemConfiguration' s.weak_framework = 'UserNotifications' - s.dependency 'FirebaseInstallations', '~> 12.0.0' - s.dependency 'FirebaseCore', '~> 12.0.0' + s.dependency 'FirebaseInstallations', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.1.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/Reachability', '~> 8.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' diff --git a/FirebaseMessagingInterop.podspec b/FirebaseMessagingInterop.podspec index 495cc9207b1..80409d6bf2d 100644 --- a/FirebaseMessagingInterop.podspec +++ b/FirebaseMessagingInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMessagingInterop' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Messaging functionality.' s.description = <<-DESC diff --git a/FirebasePerformance.podspec b/FirebasePerformance.podspec index 50b110b2a37..0fb8108870d 100644 --- a/FirebasePerformance.podspec +++ b/FirebasePerformance.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebasePerformance' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Firebase Performance' s.description = <<-DESC @@ -58,10 +58,10 @@ Firebase Performance library to measure performance of Mobile and Web Apps. s.ios.framework = 'CoreTelephony' s.framework = 'QuartzCore' s.framework = 'SystemConfiguration' - s.dependency 'FirebaseCore', '~> 12.0.0' - s.dependency 'FirebaseInstallations', '~> 12.0.0' - s.dependency 'FirebaseRemoteConfig', '~> 12.0.0' - s.dependency 'FirebaseSessions', '~> 12.0.0' + s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseInstallations', '~> 12.1.0' + s.dependency 'FirebaseRemoteConfig', '~> 12.1.0' + s.dependency 'FirebaseSessions', '~> 12.1.0' s.dependency 'GoogleDataTransport', '~> 10.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/MethodSwizzler', '~> 8.1' diff --git a/FirebaseRemoteConfig.podspec b/FirebaseRemoteConfig.podspec index 413a164fa1a..f384ed8f29a 100644 --- a/FirebaseRemoteConfig.podspec +++ b/FirebaseRemoteConfig.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseRemoteConfig' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Firebase Remote Config' s.description = <<-DESC @@ -49,13 +49,13 @@ app update. s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } - s.dependency 'FirebaseABTesting', '~> 12.0.0' - s.dependency 'FirebaseSharedSwift', '~> 12.0.0' - s.dependency 'FirebaseCore', '~> 12.0.0' - s.dependency 'FirebaseInstallations', '~> 12.0.0' + s.dependency 'FirebaseABTesting', '~> 12.1.0' + s.dependency 'FirebaseSharedSwift', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseInstallations', '~> 12.1.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/NSData+zlib', '~> 8.1' - s.dependency 'FirebaseRemoteConfigInterop', '~> 12.0.0' + s.dependency 'FirebaseRemoteConfigInterop', '~> 12.1.0' s.test_spec 'unit' do |unit_tests| unit_tests.scheme = { :code_coverage => true } diff --git a/FirebaseRemoteConfigInterop.podspec b/FirebaseRemoteConfigInterop.podspec index ffa06365043..ddb7c209c3f 100644 --- a/FirebaseRemoteConfigInterop.podspec +++ b/FirebaseRemoteConfigInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseRemoteConfigInterop' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Remote Config functionality.' s.description = <<-DESC diff --git a/FirebaseSessions.podspec b/FirebaseSessions.podspec index 56fb429ab3f..88b2b827e16 100644 --- a/FirebaseSessions.podspec +++ b/FirebaseSessions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseSessions' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Firebase Sessions' s.description = <<-DESC @@ -39,9 +39,9 @@ Pod::Spec.new do |s| base_dir + 'SourcesObjC/**/*.{c,h,m,mm}', ] - s.dependency 'FirebaseCore', '~> 12.0.0' - s.dependency 'FirebaseCoreExtension', '~> 12.0.0' - s.dependency 'FirebaseInstallations', '~> 12.0.0' + s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseCoreExtension', '~> 12.1.0' + s.dependency 'FirebaseInstallations', '~> 12.1.0' s.dependency 'GoogleDataTransport', '~> 10.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseSharedSwift.podspec b/FirebaseSharedSwift.podspec index d91433da223..d14ad49b44d 100644 --- a/FirebaseSharedSwift.podspec +++ b/FirebaseSharedSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseSharedSwift' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Shared Swift Extensions for Firebase' s.description = <<-DESC diff --git a/FirebaseStorage.podspec b/FirebaseStorage.podspec index 9c9561b7335..d1dc7201bbc 100644 --- a/FirebaseStorage.podspec +++ b/FirebaseStorage.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseStorage' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Firebase Storage' s.description = <<-DESC @@ -37,10 +37,10 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas 'FirebaseStorage/Typedefs/*.h', ] - s.dependency 'FirebaseAppCheckInterop', '~> 12.0.0' - s.dependency 'FirebaseAuthInterop', '~> 12.0.0' - s.dependency 'FirebaseCore', '~> 12.0.0' - s.dependency 'FirebaseCoreExtension', '~> 12.0.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.1.0' + s.dependency 'FirebaseAuthInterop', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseCoreExtension', '~> 12.1.0' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 6.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' @@ -57,7 +57,7 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas objc_tests.requires_app_host = true objc_tests.resources = 'FirebaseStorage/Tests/Integration/Resources/1mb.dat', 'FirebaseStorage/Tests/Integration/Resources/GoogleService-Info.plist' - objc_tests.dependency 'FirebaseAuth', '~> 12.0.0' + objc_tests.dependency 'FirebaseAuth', '~> 12.1.0' objc_tests.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } @@ -86,6 +86,6 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas int_tests.resources = 'FirebaseStorage/Tests/Integration/Resources/1mb.dat', 'FirebaseStorage/Tests/Integration/Resources/GoogleService-Info.plist', 'FirebaseStorage/Tests/Integration/Resources/HomeImprovement.numbers' - int_tests.dependency 'FirebaseAuth', '~> 12.0.0' + int_tests.dependency 'FirebaseAuth', '~> 12.1.0' end end diff --git a/GoogleAppMeasurement.podspec b/GoogleAppMeasurement.podspec index 4d26b5e6cfb..38c1de633e1 100644 --- a/GoogleAppMeasurement.podspec +++ b/GoogleAppMeasurement.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'GoogleAppMeasurement' - s.version = '12.0.0' + s.version = '12.1.0' s.summary = 'Shared measurement methods for Google libraries. Not intended for direct use.' s.description = <<-DESC @@ -37,8 +37,8 @@ Pod::Spec.new do |s| s.default_subspecs = 'Default' s.subspec 'Default' do |ss| - ss.dependency 'GoogleAppMeasurement/Core', '12.0.0' - ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.0.0' + ss.dependency 'GoogleAppMeasurement/Core', '12.1.0' + ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.1.0' ss.ios.dependency 'GoogleAdsOnDeviceConversion', '2.1.0' end @@ -47,7 +47,7 @@ Pod::Spec.new do |s| end s.subspec 'IdentitySupport' do |ss| - ss.dependency 'GoogleAppMeasurement/Core', '12.0.0' + ss.dependency 'GoogleAppMeasurement/Core', '12.1.0' ss.vendored_frameworks = 'Frameworks/GoogleAppMeasurementIdentitySupport.xcframework' end end diff --git a/Package.swift b/Package.swift index 034bfc6d90a..1ef46aa47ef 100644 --- a/Package.swift +++ b/Package.swift @@ -18,7 +18,7 @@ import PackageDescription -let firebaseVersion = "12.0.0" +let firebaseVersion = "12.1.0" let package = Package( name: "Firebase", diff --git a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift index 4e63c277a8f..27faaa0b188 100755 --- a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift +++ b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift @@ -21,7 +21,7 @@ import Foundation /// The version and releasing fields of the non-Firebase pods should be reviewed every release. /// The array should be ordered so that any pod's dependencies precede it in the list. public let shared = Manifest( - version: "12.0.0", + version: "12.1.0", pods: [ Pod("FirebaseSharedSwift"), Pod("FirebaseCoreInternal"), diff --git a/ReleaseTooling/Sources/FirebaseReleaser/InitializeRelease.swift b/ReleaseTooling/Sources/FirebaseReleaser/InitializeRelease.swift index 3e5c5190212..4674a765e55 100644 --- a/ReleaseTooling/Sources/FirebaseReleaser/InitializeRelease.swift +++ b/ReleaseTooling/Sources/FirebaseReleaser/InitializeRelease.swift @@ -50,29 +50,12 @@ enum InitializeRelease { updateFirebasePodspec(path: path, manifest: manifest) } else { updatePodspecVersion(pod: pod, version: version, path: path) - - // Pods dependencies to update to latest. - if pod.name.hasPrefix("GoogleAppMeasurement") || - pod.name == "FirebaseCore" || - pod.name == "FirebaseCoreExtension" || - pod.name == "FirebaseCoreInternal" || - pod.name == "FirebaseFirestoreInternal" || - pod.name == "FirebaseAI" { - updateDependenciesToLatest( - dependency: pod.name, - pods: manifest.pods, - version: version, - path: path - ) - } else if version.hasSuffix(".0.0") { - let patchlessVersion = String(version[.. Date: Wed, 16 Jul 2025 12:36:35 -0400 Subject: [PATCH 04/76] [NFC] Remove comment from RCNRemoteConfigTest.m (#15122) --- FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfigTest.m | 1 - 1 file changed, 1 deletion(-) diff --git a/FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfigTest.m b/FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfigTest.m index 9d4781930f1..a58bb92a76d 100644 --- a/FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfigTest.m +++ b/FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfigTest.m @@ -311,7 +311,6 @@ - (void)tearDown { _userDefaultsMock = nil; for (int i = 0; i < RCNTestRCNumTotalInstances; i++) { [(id)_configInstances[i] stopMocking]; - // [(id)_configFetch[i] stopMocking]; } [_configInstances removeAllObjects]; [_configFetch removeAllObjects]; From 37b1ad64dfb00bdc7dac7790005edadcbc303c05 Mon Sep 17 00:00:00 2001 From: Yakov Manshin Date: Wed, 16 Jul 2025 23:03:13 +0200 Subject: [PATCH 05/76] Functions Cleanup (#15119) --- .../Sources/Callable+Codable.swift | 4 +- FirebaseFunctions/Sources/Functions.swift | 46 +------------------ FirebaseFunctions/Sources/HTTPSCallable.swift | 1 - .../Sources/Internal/FunctionsContext.swift | 3 -- .../CombineUnit/HTTPSCallableTests.swift | 1 - .../Tests/Integration/IntegrationTests.swift | 15 ------ .../Tests/Unit/FunctionsAPITests.swift | 32 ++++++------- 7 files changed, 15 insertions(+), 87 deletions(-) diff --git a/FirebaseFunctions/Sources/Callable+Codable.swift b/FirebaseFunctions/Sources/Callable+Codable.swift index bcf5ce91a31..ca4790b3052 100644 --- a/FirebaseFunctions/Sources/Callable+Codable.swift +++ b/FirebaseFunctions/Sources/Callable+Codable.swift @@ -133,7 +133,6 @@ public struct Callable: Sendable { /// - Throws: An error if the callable fails to complete /// /// - Returns: The decoded `Response` value - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) public func call(_ data: Request) async throws -> Response { let encoded = try encoder.encode(data) let result = try await callable.call(encoded) @@ -160,7 +159,6 @@ public struct Callable: Sendable { /// - Parameters: /// - data: Parameters to pass to the trigger. /// - Returns: The decoded `Response` value - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) public func callAsFunction(_ data: Request) async throws -> Response { return try await call(data) } @@ -174,7 +172,7 @@ private protocol StreamResponseProtocol {} /// /// This can be used as the generic `Response` parameter to ``Callable`` to receive both the /// yielded messages and final return value of the streaming callable function. -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +@available(macOS 12.0, watchOS 8.0, *) public enum StreamResponse: Decodable, Sendable, StreamResponseProtocol { diff --git a/FirebaseFunctions/Sources/Functions.swift b/FirebaseFunctions/Sources/Functions.swift index 42a59a3e106..1662059662e 100644 --- a/FirebaseFunctions/Sources/Functions.swift +++ b/FirebaseFunctions/Sources/Functions.swift @@ -386,7 +386,6 @@ enum FunctionsConstants { return URL(string: "https://\(region)-\(projectID).cloudfunctions.net/\(name)") } - @available(iOS 13, macCatalyst 13, macOS 10.15, tvOS 13, watchOS 7, *) func callFunction(at url: URL, withObject data: Any?, options: HTTPSCallableOptions?, @@ -408,49 +407,6 @@ enum FunctionsConstants { } } - private func callFunction(url: URL, - withObject data: Any?, - options: HTTPSCallableOptions?, - timeout: TimeInterval, - context: FunctionsContext, - completion: @escaping @MainActor (Result) - -> Void) { - let fetcher: GTMSessionFetcher - do { - fetcher = try makeFetcher( - url: url, - data: data, - options: options, - timeout: timeout, - context: context - ) - } catch { - DispatchQueue.main.async { - completion(.failure(error)) - } - return - } - - fetcher.beginFetch { [self] data, error in - let result: Result - if let error { - result = .failure(processedError(fromResponseError: error, endpointURL: url)) - } else if let data { - do { - result = try .success(callableResult(fromResponseData: data, endpointURL: url)) - } catch { - result = .failure(error) - } - } else { - result = .failure(FunctionsError(.internal)) - } - - DispatchQueue.main.async { - completion(result) - } - } - } - @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) func stream(at url: URL, data: SendableWrapper?, @@ -556,7 +512,7 @@ enum FunctionsConstants { } } - @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) + @available(macOS 12.0, watchOS 8.0, *) private func callableStreamResult(fromResponseData data: Data, endpointURL url: URL) throws -> sending JSONStreamResponse { let data = try processedData(fromResponseData: data, endpointURL: url) diff --git a/FirebaseFunctions/Sources/HTTPSCallable.swift b/FirebaseFunctions/Sources/HTTPSCallable.swift index b74e5b93c4b..6286a169ef6 100644 --- a/FirebaseFunctions/Sources/HTTPSCallable.swift +++ b/FirebaseFunctions/Sources/HTTPSCallable.swift @@ -160,7 +160,6 @@ public final class HTTPSCallable: NSObject, Sendable { /// - Parameter data: Parameters to pass to the trigger. /// - Throws: An error if the Cloud Functions invocation failed. /// - Returns: The result of the call. - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) public func call(_ data: Any? = nil) async throws -> sending HTTPSCallableResult { try await functions .callFunction(at: url, withObject: data, options: options, timeout: timeoutInterval) diff --git a/FirebaseFunctions/Sources/Internal/FunctionsContext.swift b/FirebaseFunctions/Sources/Internal/FunctionsContext.swift index bacf989ed37..9a941b5f8e6 100644 --- a/FirebaseFunctions/Sources/Internal/FunctionsContext.swift +++ b/FirebaseFunctions/Sources/Internal/FunctionsContext.swift @@ -36,7 +36,6 @@ struct FunctionsContextProvider: Sendable { self.appCheck = appCheck } - @available(iOS 13, macCatalyst 13, macOS 10.15, tvOS 13, watchOS 7, *) func context(options: HTTPSCallableOptions?) async throws -> FunctionsContext { async let authToken = auth?.getToken(forcingRefresh: false) async let appCheckToken = getAppCheckToken(options: options) @@ -52,7 +51,6 @@ struct FunctionsContextProvider: Sendable { ) } - @available(iOS 13, macCatalyst 13, macOS 10.15, tvOS 13, watchOS 7, *) private func getAppCheckToken(options: HTTPSCallableOptions?) async -> String? { guard options?.requireLimitedUseAppCheckTokens != true, @@ -62,7 +60,6 @@ struct FunctionsContextProvider: Sendable { return tokenResult.token } - @available(iOS 13, macCatalyst 13, macOS 10.15, tvOS 13, watchOS 7, *) private func getLimitedUseAppCheckToken(options: HTTPSCallableOptions?) async -> String? { // At the moment, `await` doesn’t get along with Objective-C’s optional protocol methods. await withCheckedContinuation { (continuation: CheckedContinuation) in diff --git a/FirebaseFunctions/Tests/CombineUnit/HTTPSCallableTests.swift b/FirebaseFunctions/Tests/CombineUnit/HTTPSCallableTests.swift index 8b342f11785..556ab119037 100644 --- a/FirebaseFunctions/Tests/CombineUnit/HTTPSCallableTests.swift +++ b/FirebaseFunctions/Tests/CombineUnit/HTTPSCallableTests.swift @@ -54,7 +54,6 @@ class MockFunctions: Functions, @unchecked Sendable { } } -@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *) class HTTPSCallableTests: XCTestCase { func testCallWithoutParametersSuccess() { // given diff --git a/FirebaseFunctions/Tests/Integration/IntegrationTests.swift b/FirebaseFunctions/Tests/Integration/IntegrationTests.swift index 3032c700bc1..50b48f8c5f0 100644 --- a/FirebaseFunctions/Tests/Integration/IntegrationTests.swift +++ b/FirebaseFunctions/Tests/Integration/IntegrationTests.swift @@ -119,7 +119,6 @@ class IntegrationTests: XCTestCase { } } - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) func testDataAsync() async throws { let data = DataTestRequest( bool: true, @@ -174,7 +173,6 @@ class IntegrationTests: XCTestCase { } } - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) func testScalarAsync() async throws { let byName = functions.httpsCallable( "scalarTest", @@ -193,7 +191,6 @@ class IntegrationTests: XCTestCase { } } - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) func testScalarAsyncAlternateSignature() async throws { let byName: Callable = functions.httpsCallable("scalarTest") let byURL: Callable = functions.httpsCallable(emulatorURL("scalarTest")) @@ -241,7 +238,6 @@ class IntegrationTests: XCTestCase { } } - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) func testTokenAsync() async throws { // Recreate functions with a token. let functions = Functions( @@ -297,7 +293,6 @@ class IntegrationTests: XCTestCase { } } - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) func testFCMTokenAsync() async throws { let byName = functions.httpsCallable( "FCMTokenTest", @@ -342,7 +337,6 @@ class IntegrationTests: XCTestCase { } } - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) func testNullAsync() async throws { let byName = functions.httpsCallable( "nullTest", @@ -391,7 +385,6 @@ class IntegrationTests: XCTestCase { } } - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) func testMissingResultAsync() async { let byName = functions.httpsCallable( "missingResultTest", @@ -445,7 +438,6 @@ class IntegrationTests: XCTestCase { } } - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) func testUnhandledErrorAsync() async { let byName = functions.httpsCallable( "unhandledErrorTest", @@ -498,7 +490,6 @@ class IntegrationTests: XCTestCase { waitForExpectations(timeout: 5) } - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) func testUnknownErrorAsync() async { let byName = functions.httpsCallable( "unknownErrorTest", @@ -553,7 +544,6 @@ class IntegrationTests: XCTestCase { } } - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) func testExplicitErrorAsync() async { let byName = functions.httpsCallable( "explicitErrorTest", @@ -608,7 +598,6 @@ class IntegrationTests: XCTestCase { } } - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) func testHttpErrorAsync() async { let byName = functions.httpsCallable( "httpErrorTest", @@ -661,7 +650,6 @@ class IntegrationTests: XCTestCase { } } - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) func testThrowErrorAsync() async { let byName = functions.httpsCallable( "throwTest", @@ -716,7 +704,6 @@ class IntegrationTests: XCTestCase { } } - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) func testTimeoutAsync() async { var byName = functions.httpsCallable( "timeoutTest", @@ -778,7 +765,6 @@ class IntegrationTests: XCTestCase { } } - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) func testCallAsFunctionAsync() async throws { let data = DataTestRequest( bool: true, @@ -841,7 +827,6 @@ class IntegrationTests: XCTestCase { } } - @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) func testInferredTyesAsync() async throws { let data = DataTestRequest( bool: true, diff --git a/FirebaseFunctions/Tests/Unit/FunctionsAPITests.swift b/FirebaseFunctions/Tests/Unit/FunctionsAPITests.swift index 6ab0fb11a81..9d8d013e04f 100644 --- a/FirebaseFunctions/Tests/Unit/FunctionsAPITests.swift +++ b/FirebaseFunctions/Tests/Unit/FunctionsAPITests.swift @@ -85,16 +85,13 @@ final class FunctionsAPITests: XCTestCase { } } - if #available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 7.0, *) { - // async/await is a Swift Concurrency feature available on iOS 13+ and macOS 10.15+ - Task { - do { - let data: Any? = nil - let result = try await callableRef.call(data) - _ = result.data - } catch { - // ... - } + Task { + do { + let data: Any? = nil + let result = try await callableRef.call(data) + _ = result.data + } catch { + // ... } } @@ -106,15 +103,12 @@ final class FunctionsAPITests: XCTestCase { } } - if #available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 7.0, *) { - // async/await is a Swift Concurrency feature available on iOS 13+ and macOS 10.15+ - Task { - do { - let result = try await callableRef.call() - _ = result.data - } catch { - // ... - } + Task { + do { + let result = try await callableRef.call() + _ = result.data + } catch { + // ... } } From de80eaf2a909744b377c171472ee8174b73d8deb Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Thu, 17 Jul 2025 10:45:19 -0400 Subject: [PATCH 06/76] [Infra] Suppress designated initializer warning in `FIRQueryFake` (#15123) Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- FirebaseTestingSupport/Firestore/Sources/FIRQueryFake.mm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/FirebaseTestingSupport/Firestore/Sources/FIRQueryFake.mm b/FirebaseTestingSupport/Firestore/Sources/FIRQueryFake.mm index 8d8c181ca0d..002fbf67e8d 100644 --- a/FirebaseTestingSupport/Firestore/Sources/FIRQueryFake.mm +++ b/FirebaseTestingSupport/Firestore/Sources/FIRQueryFake.mm @@ -16,10 +16,13 @@ @implementation FIRQueryFake +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wobjc-designated-initializers" - (instancetype)init { // The object is partially initialized. Make sure the methods used during testing are overridden. return self; } +#pragma clang diagnostic pop - (void)getDocumentsWithCompletion:(FIRQuerySnapshotBlock)completion { if (self.getDocumentsHandler) { From 907df98c6107ea884045b9f6c7ce2d316837b177 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Thu, 17 Jul 2025 10:45:44 -0400 Subject: [PATCH 07/76] [Infra] Add `@unchecked` Sendable to `MockQuery` (#15124) Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- .../Tests/Unit/Firestore/GetDocumentsTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseCombineSwift/Tests/Unit/Firestore/GetDocumentsTests.swift b/FirebaseCombineSwift/Tests/Unit/Firestore/GetDocumentsTests.swift index 0b1c539f5cb..a0eb8ea0a7b 100644 --- a/FirebaseCombineSwift/Tests/Unit/Firestore/GetDocumentsTests.swift +++ b/FirebaseCombineSwift/Tests/Unit/Firestore/GetDocumentsTests.swift @@ -20,7 +20,7 @@ import XCTest class GetDocumentsTests: XCTestCase { let expectationTimeout: TimeInterval = 2 - class MockQuery: QueryFake { + class MockQuery: QueryFake, @unchecked Sendable { var mockGetDocuments: () throws -> QuerySnapshot = { fatalError("You need to implement \(#function) in your mock.") } From 95570e5e143e79d939b4f5f89a93ee7587c96ad6 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Fri, 18 Jul 2025 06:58:48 -0700 Subject: [PATCH 08/76] Restore pod Firebase/Firestore for tvOS (#15127) --- Firebase.podspec | 2 +- Firestore/CHANGELOG.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Firebase.podspec b/Firebase.podspec index cada41f66c4..6374a742fa2 100644 --- a/Firebase.podspec +++ b/Firebase.podspec @@ -128,7 +128,7 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.dependency 'FirebaseFirestore', '~> 12.1.0' ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' - ss.ios.deployment_target = '15.0' + ss.tvos.deployment_target = '15.0' end s.subspec 'Functions' do |ss| diff --git a/Firestore/CHANGELOG.md b/Firestore/CHANGELOG.md index bcb63c64c11..5c21cd4c423 100644 --- a/Firestore/CHANGELOG.md +++ b/Firestore/CHANGELOG.md @@ -1,3 +1,6 @@ +# Unreleased +- [fixed] Fixed accidental removal of `pod "Firebase/Firestore"` for tvOS in 12.0.0. + # 11.12.0 - [fixed] Fixed the `null` value handling in `isNotEqualTo` and `notIn` filters. From 12582dd0fc259fa283025ffcb7896d557215a77a Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Mon, 21 Jul 2025 22:45:00 -0400 Subject: [PATCH 09/76] [Firebase AI] Conform `GroundingMetdata` to `Equatable` (#15137) Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- FirebaseAI/Sources/GenerateContentResponse.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/FirebaseAI/Sources/GenerateContentResponse.swift b/FirebaseAI/Sources/GenerateContentResponse.swift index b0e348d2192..1cc9874e795 100644 --- a/FirebaseAI/Sources/GenerateContentResponse.swift +++ b/FirebaseAI/Sources/GenerateContentResponse.swift @@ -310,7 +310,7 @@ public struct PromptFeedback: Sendable { /// or Vertex AI Gemini API (see [Service Terms](https://cloud.google.com/terms/service-terms) /// section within the Service Specific Terms). @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) -public struct GroundingMetadata: Sendable { +public struct GroundingMetadata: Sendable, Equatable, Hashable { /// A list of web search queries that the model performed to gather the grounding information. /// These can be used to allow users to explore the search results themselves. public let webSearchQueries: [String] @@ -327,7 +327,7 @@ public struct GroundingMetadata: Sendable { /// A struct representing the Google Search entry point. @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) - public struct SearchEntryPoint: Sendable { + public struct SearchEntryPoint: Sendable, Equatable, Hashable { /// An HTML/CSS snippet that can be embedded in your app. /// /// To ensure proper rendering, it's recommended to display this content within a `WKWebView`. @@ -337,14 +337,14 @@ public struct GroundingMetadata: Sendable { /// Represents a chunk of retrieved data that supports a claim in the model's response. This is /// part of the grounding information provided when grounding is enabled. @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) - public struct GroundingChunk: Sendable { + public struct GroundingChunk: Sendable, Equatable, Hashable { /// Contains details if the grounding chunk is from a web source. public let web: WebGroundingChunk? } /// A grounding chunk sourced from the web. @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) - public struct WebGroundingChunk: Sendable { + public struct WebGroundingChunk: Sendable, Equatable, Hashable { /// The URI of the retrieved web page. public let uri: String? /// The title of the retrieved web page. @@ -358,7 +358,7 @@ public struct GroundingMetadata: Sendable { /// Provides information about how a specific segment of the model's response is supported by the /// retrieved grounding chunks. @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) - public struct GroundingSupport: Sendable { + public struct GroundingSupport: Sendable, Equatable, Hashable { /// Specifies the segment of the model's response content that this grounding support pertains /// to. public let segment: Segment @@ -391,7 +391,7 @@ public struct GroundingMetadata: Sendable { /// Represents a specific segment within a ``ModelContent`` struct, often used to pinpoint the /// exact location of text or data that grounding information refers to. @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) -public struct Segment: Sendable { +public struct Segment: Sendable, Equatable, Hashable { /// The zero-based index of the ``Part`` object within the `parts` array of its parent /// ``ModelContent`` object. This identifies which part of the content the segment belongs to. public let partIndex: Int From e0c6d91ce18117a69550b21adee4b520f6e0884a Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Mon, 21 Jul 2025 20:44:11 -0700 Subject: [PATCH 10/76] Increase Firebase AI Logic unit test coverage (#15126) Co-authored-by: Andrew Heard --- FirebaseAI/Tests/Unit/ChatTests.swift | 100 ++++++++++++++ FirebaseAI/Tests/Unit/JSONValueTests.swift | 68 ++++++++++ .../Tests/Unit/PartsRepresentableTests.swift | 51 ++++++++ FirebaseAI/Tests/Unit/SafetyTests.swift | 123 ++++++++++++++++++ 4 files changed, 342 insertions(+) create mode 100644 FirebaseAI/Tests/Unit/SafetyTests.swift diff --git a/FirebaseAI/Tests/Unit/ChatTests.swift b/FirebaseAI/Tests/Unit/ChatTests.swift index 40373a47494..4bf89f8cb51 100644 --- a/FirebaseAI/Tests/Unit/ChatTests.swift +++ b/FirebaseAI/Tests/Unit/ChatTests.swift @@ -94,4 +94,104 @@ final class ChatTests: XCTestCase { XCTAssertEqual(chat.history[1], assembledExpectation) #endif // os(watchOS) } + + func testSendMessage_unary_appendsHistory() async throws { + let expectedInput = "Test input" + MockURLProtocol.requestHandler = try GenerativeModelTestUtil.httpRequestHandler( + forResource: "unary-success-basic-reply-short", + withExtension: "json", + subdirectory: "mock-responses/googleai" + ) + let model = GenerativeModel( + modelName: modelName, + modelResourceName: modelResourceName, + firebaseInfo: GenerativeModelTestUtil.testFirebaseInfo(), + apiConfig: FirebaseAI.defaultVertexAIAPIConfig, + tools: nil, + requestOptions: RequestOptions(), + urlSession: urlSession + ) + let chat = model.startChat() + + // Pre-condition: History should be empty. + XCTAssertTrue(chat.history.isEmpty) + + let response = try await chat.sendMessage(expectedInput) + + XCTAssertNotNil(response.text) + let text = try XCTUnwrap(response.text) + XCTAssertFalse(text.isEmpty) + + // Post-condition: History should have the user's message and the model's response. + XCTAssertEqual(chat.history.count, 2) + let userInput = try XCTUnwrap(chat.history.first) + XCTAssertEqual(userInput.role, "user") + XCTAssertEqual(userInput.parts.count, 1) + let userInputText = try XCTUnwrap(userInput.parts.first as? TextPart) + XCTAssertEqual(userInputText.text, expectedInput) + + let modelResponse = try XCTUnwrap(chat.history.last) + XCTAssertEqual(modelResponse.role, "model") + XCTAssertEqual(modelResponse.parts.count, 1) + let modelResponseText = try XCTUnwrap(modelResponse.parts.first as? TextPart) + XCTAssertFalse(modelResponseText.text.isEmpty) + } + + func testSendMessageStream_error_doesNotAppendHistory() async throws { + MockURLProtocol.requestHandler = try GenerativeModelTestUtil.httpRequestHandler( + forResource: "streaming-failure-finish-reason-safety", + withExtension: "txt", + subdirectory: "mock-responses/vertexai" + ) + let model = GenerativeModel( + modelName: modelName, + modelResourceName: modelResourceName, + firebaseInfo: GenerativeModelTestUtil.testFirebaseInfo(), + apiConfig: FirebaseAI.defaultVertexAIAPIConfig, + tools: nil, + requestOptions: RequestOptions(), + urlSession: urlSession + ) + let chat = model.startChat() + let input = "Test input" + + // Pre-condition: History should be empty. + XCTAssertTrue(chat.history.isEmpty) + + do { + let stream = try chat.sendMessageStream(input) + for try await _ in stream { + // Consume the stream. + } + XCTFail("Should have thrown a responseStoppedEarly error.") + } catch let GenerateContentError.responseStoppedEarly(reason, _) { + XCTAssertEqual(reason, .safety) + } catch { + XCTFail("Unexpected error thrown: \(error)") + } + + // Post-condition: History should still be empty. + XCTAssertEqual(chat.history.count, 0) + } + + func testStartChat_withHistory_initializesCorrectly() async throws { + let history = [ + ModelContent(role: "user", parts: "Question 1"), + ModelContent(role: "model", parts: "Answer 1"), + ] + let model = GenerativeModel( + modelName: modelName, + modelResourceName: modelResourceName, + firebaseInfo: GenerativeModelTestUtil.testFirebaseInfo(), + apiConfig: FirebaseAI.defaultVertexAIAPIConfig, + tools: nil, + requestOptions: RequestOptions(), + urlSession: urlSession + ) + + let chat = model.startChat(history: history) + + XCTAssertEqual(chat.history.count, 2) + XCTAssertEqual(chat.history, history) + } } diff --git a/FirebaseAI/Tests/Unit/JSONValueTests.swift b/FirebaseAI/Tests/Unit/JSONValueTests.swift index 1ffe88eaf55..54ac3520e77 100644 --- a/FirebaseAI/Tests/Unit/JSONValueTests.swift +++ b/FirebaseAI/Tests/Unit/JSONValueTests.swift @@ -97,6 +97,48 @@ final class JSONValueTests: XCTestCase { XCTAssertEqual(json, "null") } + func testDecodeNestedObject() throws { + let nestedObject: JSONObject = [ + "nestedKey": .string("nestedValue"), + ] + let expectedObject: JSONObject = [ + "numberKey": .number(numberValue), + "objectKey": .object(nestedObject), + ] + let json = """ + { + "numberKey": \(numberValue), + "objectKey": { + "nestedKey": "nestedValue" + } + } + """ + let jsonData = try XCTUnwrap(json.data(using: .utf8)) + + let jsonObject = try XCTUnwrap(decoder.decode(JSONValue.self, from: jsonData)) + + XCTAssertEqual(jsonObject, .object(expectedObject)) + } + + func testDecodeNestedArray() throws { + let nestedArray: [JSONValue] = [.string("a"), .string("b")] + let expectedObject: JSONObject = [ + "numberKey": .number(numberValue), + "arrayKey": .array(nestedArray), + ] + let json = """ + { + "numberKey": \(numberValue), + "arrayKey": ["a", "b"] + } + """ + let jsonData = try XCTUnwrap(json.data(using: .utf8)) + + let jsonObject = try XCTUnwrap(decoder.decode(JSONValue.self, from: jsonData)) + + XCTAssertEqual(jsonObject, .object(expectedObject)) + } + func testEncodeNumber() throws { let jsonData = try encoder.encode(JSONValue.number(numberValue)) @@ -143,4 +185,30 @@ final class JSONValueTests: XCTestCase { let json = try XCTUnwrap(String(data: jsonData, encoding: .utf8)) XCTAssertEqual(json, "[null,\(numberValueEncoded)]") } + + func testEncodeNestedObject() throws { + let nestedObject: JSONObject = [ + "nestedKey": .string("nestedValue"), + ] + let objectValue: JSONObject = [ + "numberKey": .number(numberValue), + "objectKey": .object(nestedObject), + ] + + let jsonData = try encoder.encode(JSONValue.object(objectValue)) + let jsonObject = try XCTUnwrap(decoder.decode(JSONValue.self, from: jsonData)) + XCTAssertEqual(jsonObject, .object(objectValue)) + } + + func testEncodeNestedArray() throws { + let nestedArray: [JSONValue] = [.string("a"), .string("b")] + let objectValue: JSONObject = [ + "numberKey": .number(numberValue), + "arrayKey": .array(nestedArray), + ] + + let jsonData = try encoder.encode(JSONValue.object(objectValue)) + let jsonObject = try XCTUnwrap(decoder.decode(JSONValue.self, from: jsonData)) + XCTAssertEqual(jsonObject, .object(objectValue)) + } } diff --git a/FirebaseAI/Tests/Unit/PartsRepresentableTests.swift b/FirebaseAI/Tests/Unit/PartsRepresentableTests.swift index e7531d1da9e..658db79a50e 100644 --- a/FirebaseAI/Tests/Unit/PartsRepresentableTests.swift +++ b/FirebaseAI/Tests/Unit/PartsRepresentableTests.swift @@ -121,4 +121,55 @@ final class PartsRepresentableTests: XCTestCase { } } #endif + + func testMixedParts() throws { + let text = "This is a test" + let data = try XCTUnwrap("This is some data".data(using: .utf8)) + let inlineData = InlineDataPart(data: data, mimeType: "text/plain") + + let parts: [any PartsRepresentable] = [text, inlineData] + let modelContent = ModelContent(parts: parts) + + XCTAssertEqual(modelContent.parts.count, 2) + let textPart = try XCTUnwrap(modelContent.parts[0] as? TextPart) + XCTAssertEqual(textPart.text, text) + let dataPart = try XCTUnwrap(modelContent.parts[1] as? InlineDataPart) + XCTAssertEqual(dataPart, inlineData) + } + + #if canImport(UIKit) + func testMixedParts_withImage() throws { + let text = "This is a test" + let image = try XCTUnwrap(UIImage(systemName: "star")) + let parts: [any PartsRepresentable] = [text, image] + let modelContent = ModelContent(parts: parts) + + XCTAssertEqual(modelContent.parts.count, 2) + let textPart = try XCTUnwrap(modelContent.parts[0] as? TextPart) + XCTAssertEqual(textPart.text, text) + let imagePart = try XCTUnwrap(modelContent.parts[1] as? InlineDataPart) + XCTAssertEqual(imagePart.mimeType, "image/jpeg") + XCTAssertFalse(imagePart.data.isEmpty) + } + + #elseif canImport(AppKit) + func testMixedParts_withImage() throws { + let text = "This is a test" + let coreImage = CIImage(color: CIColor.blue) + .cropped(to: CGRect(origin: CGPoint.zero, size: CGSize(width: 16, height: 16))) + let rep = NSCIImageRep(ciImage: coreImage) + let image = NSImage(size: rep.size) + image.addRepresentation(rep) + + let parts: [any PartsRepresentable] = [text, image] + let modelContent = ModelContent(parts: parts) + + XCTAssertEqual(modelContent.parts.count, 2) + let textPart = try XCTUnwrap(modelContent.parts[0] as? TextPart) + XCTAssertEqual(textPart.text, text) + let imagePart = try XCTUnwrap(modelContent.parts[1] as? InlineDataPart) + XCTAssertEqual(imagePart.mimeType, "image/jpeg") + XCTAssertFalse(imagePart.data.isEmpty) + } + #endif } diff --git a/FirebaseAI/Tests/Unit/SafetyTests.swift b/FirebaseAI/Tests/Unit/SafetyTests.swift new file mode 100644 index 00000000000..4a1e07e04e3 --- /dev/null +++ b/FirebaseAI/Tests/Unit/SafetyTests.swift @@ -0,0 +1,123 @@ +// 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. + +import XCTest + +@testable import FirebaseAI + +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +final class SafetyTests: XCTestCase { + let decoder = JSONDecoder() + let encoder = JSONEncoder() + + override func setUp() { + encoder.outputFormatting = .init( + arrayLiteral: .prettyPrinted, .sortedKeys, .withoutEscapingSlashes + ) + } + + // MARK: - SafetyRating Decoding + + func testDecodeSafetyRating_allFieldsPresent() throws { + let json = """ + { + "category": "HARM_CATEGORY_DANGEROUS_CONTENT", + "probability": "NEGLIGIBLE", + "probabilityScore": 0.1, + "severity": "HARM_SEVERITY_LOW", + "severityScore": 0.2, + "blocked": true + } + """ + let jsonData = try XCTUnwrap(json.data(using: .utf8)) + let rating = try decoder.decode(SafetyRating.self, from: jsonData) + + XCTAssertEqual(rating.category, .dangerousContent) + XCTAssertEqual(rating.probability, .negligible) + XCTAssertEqual(rating.probabilityScore, 0.1) + XCTAssertEqual(rating.severity, .low) + XCTAssertEqual(rating.severityScore, 0.2) + XCTAssertTrue(rating.blocked) + } + + func testDecodeSafetyRating_missingOptionalFields() throws { + let json = """ + { + "category": "HARM_CATEGORY_HARASSMENT", + "probability": "LOW" + } + """ + let jsonData = try XCTUnwrap(json.data(using: .utf8)) + let rating = try decoder.decode(SafetyRating.self, from: jsonData) + + XCTAssertEqual(rating.category, .harassment) + XCTAssertEqual(rating.probability, .low) + XCTAssertEqual(rating.probabilityScore, 0.0) + XCTAssertEqual(rating.severity, .unspecified) + XCTAssertEqual(rating.severityScore, 0.0) + XCTAssertFalse(rating.blocked) + } + + func testDecodeSafetyRating_unknownEnums() throws { + let json = """ + { + "category": "HARM_CATEGORY_UNKNOWN", + "probability": "UNKNOWN_PROBABILITY", + "severity": "UNKNOWN_SEVERITY" + } + """ + let jsonData = try XCTUnwrap(json.data(using: .utf8)) + let rating = try decoder.decode(SafetyRating.self, from: jsonData) + + XCTAssertEqual(rating.category.rawValue, "HARM_CATEGORY_UNKNOWN") + XCTAssertEqual(rating.probability.rawValue, "UNKNOWN_PROBABILITY") + XCTAssertEqual(rating.severity.rawValue, "UNKNOWN_SEVERITY") + } + + // MARK: - SafetySetting Encoding + + func testEncodeSafetySetting_allFields() throws { + let setting = SafetySetting( + harmCategory: .hateSpeech, + threshold: .blockMediumAndAbove, + method: .severity + ) + let jsonData = try encoder.encode(setting) + let jsonString = try XCTUnwrap(String(data: jsonData, encoding: .utf8)) + + XCTAssertEqual(jsonString, """ + { + "category" : "HARM_CATEGORY_HATE_SPEECH", + "method" : "SEVERITY", + "threshold" : "BLOCK_MEDIUM_AND_ABOVE" + } + """) + } + + func testEncodeSafetySetting_nilMethod() throws { + let setting = SafetySetting( + harmCategory: .sexuallyExplicit, + threshold: .blockOnlyHigh + ) + let jsonData = try encoder.encode(setting) + let jsonString = try XCTUnwrap(String(data: jsonData, encoding: .utf8)) + + XCTAssertEqual(jsonString, """ + { + "category" : "HARM_CATEGORY_SEXUALLY_EXPLICIT", + "threshold" : "BLOCK_ONLY_HIGH" + } + """) + } +} From 3bbfbcc3418544b413afdb4bd5afa3f954050b3f Mon Sep 17 00:00:00 2001 From: Andrii Zinoviev Date: Wed, 23 Jul 2025 00:02:50 +0200 Subject: [PATCH 11/76] Do not log using raw print in SettingsCacheClient (#15132) --- FirebaseSessions/Sources/Settings/SettingsCacheClient.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseSessions/Sources/Settings/SettingsCacheClient.swift b/FirebaseSessions/Sources/Settings/SettingsCacheClient.swift index 18f9bcefbff..79a2e1ffa20 100644 --- a/FirebaseSessions/Sources/Settings/SettingsCacheClient.swift +++ b/FirebaseSessions/Sources/Settings/SettingsCacheClient.swift @@ -129,7 +129,7 @@ final class SettingsCache: SettingsCacheClient { guard let duration = cacheContent[Self.flagCacheDuration] as? Double else { return Self.cacheDurationSecondsDefault } - print("Duration: \(duration)") + Logger.logDebug("[Settings] Cache duration: \(duration)") return duration } } From ea0e252e24d819818ae09060207bea74df90c4b6 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 22 Jul 2025 21:56:30 -0400 Subject: [PATCH 12/76] [Infra] Add changelog for #15139 (#15141) Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- Crashlytics/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Crashlytics/CHANGELOG.md b/Crashlytics/CHANGELOG.md index fa67c39d6a7..a603c89d07d 100644 --- a/Crashlytics/CHANGELOG.md +++ b/Crashlytics/CHANGELOG.md @@ -1,3 +1,6 @@ +# Unreleased +- [fixed] Do not log using raw print in an internal class. (#15138) + # 12.0.0 - [fixed] Resolved compiler warnings related to constant definitions. (#15059) From 1166090a7cc9295c2def236d1c6223d1a4c45765 Mon Sep 17 00:00:00 2001 From: Ben Hagen Date: Wed, 23 Jul 2025 21:38:47 +0200 Subject: [PATCH 13/76] [Auth] Fix TOTP URL generation (#15128) --- FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPSecret.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPSecret.swift b/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPSecret.swift index 9791b974e52..b9f1d913920 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPSecret.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPSecret.swift @@ -47,7 +47,7 @@ import Foundation return "" } return "otpauth://totp/\(issuer):\(accountName)?secret=\(secretKey)&issuer=\(issuer)" + - "&algorithm=%\(hashingAlgorithm)&digits=\(codeLength)" + "&algorithm=\(hashingAlgorithm)&digits=\(codeLength)" } /// Opens the specified QR Code URL in a password manager like iCloud Keychain. From 3d467ef97d187f676c6e1a7fa6565d8ddea2db5e Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 23 Jul 2025 15:47:20 -0400 Subject: [PATCH 14/76] [Auth] Add changelog entry for #15128 (#15143) --- FirebaseAuth/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index 143e9dfedc6..b2bce553f71 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,3 +1,7 @@ +# Unreleased +- [fixed] Fix a formatting issue with generated TOTP URLs that prevented them + from working with the Google Authenticator app. (#15128) + # 12.0.0 - [removed] **Breaking Change**: Removed the following Dynamic Links related APIs: From 690d973efb082294039d7d1605577ad132b15f50 Mon Sep 17 00:00:00 2001 From: Daymon <17409137+daymxn@users.noreply.github.com> Date: Tue, 29 Jul 2025 11:16:16 -0500 Subject: [PATCH 15/76] Update changelogs for 12.1.0 (#15156) --- Crashlytics/CHANGELOG.md | 2 +- FirebaseAuth/CHANGELOG.md | 2 +- Firestore/CHANGELOG.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Crashlytics/CHANGELOG.md b/Crashlytics/CHANGELOG.md index a603c89d07d..777e07cd8b1 100644 --- a/Crashlytics/CHANGELOG.md +++ b/Crashlytics/CHANGELOG.md @@ -1,4 +1,4 @@ -# Unreleased +# 12.1.0 - [fixed] Do not log using raw print in an internal class. (#15138) # 12.0.0 diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index b2bce553f71..a0d6d7a2210 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,4 +1,4 @@ -# Unreleased +# 12.1.0 - [fixed] Fix a formatting issue with generated TOTP URLs that prevented them from working with the Google Authenticator app. (#15128) diff --git a/Firestore/CHANGELOG.md b/Firestore/CHANGELOG.md index 5c21cd4c423..628e3afd826 100644 --- a/Firestore/CHANGELOG.md +++ b/Firestore/CHANGELOG.md @@ -1,4 +1,4 @@ -# Unreleased +# 12.1.0 - [fixed] Fixed accidental removal of `pod "Firebase/Firestore"` for tvOS in 12.0.0. # 11.12.0 From feef47a63e1748582d943dac3f0ef7352f2c00b4 Mon Sep 17 00:00:00 2001 From: htcgh Date: Tue, 29 Jul 2025 15:45:15 -0700 Subject: [PATCH 16/76] Analytics 12.1.0 (#15157) --- FirebaseAnalytics.podspec | 2 +- GoogleAppMeasurement.podspec | 4 ++-- Package.swift | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index b8e7190bde5..6beee36dd2c 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.authors = 'Google, Inc.' s.source = { - :http => 'https://dl.google.com/firebase/ios/analytics/c3a136153af090b8/FirebaseAnalytics-12.0.0.tar.gz' + :http => 'https://dl.google.com/firebase/ios/analytics/f8b1e0fb38da4d8c/FirebaseAnalytics-12.1.0.tar.gz' } s.cocoapods_version = '>= 1.12.0' diff --git a/GoogleAppMeasurement.podspec b/GoogleAppMeasurement.podspec index 38c1de633e1..f9fc10c2772 100644 --- a/GoogleAppMeasurement.podspec +++ b/GoogleAppMeasurement.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |s| s.authors = 'Google, Inc.' s.source = { - :http => 'https://dl.google.com/firebase/ios/analytics/dcba2ac84f595e1b/GoogleAppMeasurement-12.0.0.tar.gz' + :http => 'https://dl.google.com/firebase/ios/analytics/40ed69179ccc9278/GoogleAppMeasurement-12.1.0.tar.gz' } s.cocoapods_version = '>= 1.12.0' @@ -39,7 +39,7 @@ Pod::Spec.new do |s| s.subspec 'Default' do |ss| ss.dependency 'GoogleAppMeasurement/Core', '12.1.0' ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.1.0' - ss.ios.dependency 'GoogleAdsOnDeviceConversion', '2.1.0' + ss.ios.dependency 'GoogleAdsOnDeviceConversion', '2.2.0' end s.subspec 'Core' do |ss| diff --git a/Package.swift b/Package.swift index 1ef46aa47ef..2a5240e3bf7 100644 --- a/Package.swift +++ b/Package.swift @@ -329,8 +329,8 @@ let package = Package( ), .binaryTarget( name: "FirebaseAnalytics", - url: "https://dl.google.com/firebase/ios/swiftpm/12.0.0/FirebaseAnalytics.zip", - checksum: "d5db7d1373be7c2595e34e6a50c943ca61ee36b806037da39c7b4d0253ce11db" + url: "https://dl.google.com/firebase/ios/swiftpm/12.1.0/FirebaseAnalytics.zip", + checksum: "57ab43b31bc0b804bb09db48d77d713fa7834085bc5aa7e2cd1b5369e63a697d" ), .testTarget( name: "AnalyticsSwiftUnit", @@ -1384,7 +1384,7 @@ func googleAppMeasurementDependency() -> Package.Dependency { return .package(url: appMeasurementURL, branch: "main") } - return .package(url: appMeasurementURL, exact: "12.0.0") + return .package(url: appMeasurementURL, exact: "12.1.0") } func abseilDependency() -> Package.Dependency { From 73bc2f6992cddc6e8e50adebc1726d0e3cae6f48 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Thu, 31 Jul 2025 16:55:08 -0400 Subject: [PATCH 17/76] [FirebaseMessaging] Fix Xcode 26 symbol crash (#15165) Co-authored-by: subdiox --- .../Sources/Runtime/FIRIAMActionURLFollower.m | 5 +++-- .../Tests/Unit/FIRIAMActionUrlFollowerTests.m | 5 +++-- FirebaseMessaging/CHANGELOG.md | 5 +++++ FirebaseMessaging/Sources/FIRMessaging.m | 5 +++-- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/FirebaseInAppMessaging/Sources/Runtime/FIRIAMActionURLFollower.m b/FirebaseInAppMessaging/Sources/Runtime/FIRIAMActionURLFollower.m index 840937c1be5..e80a4f29f48 100644 --- a/FirebaseInAppMessaging/Sources/Runtime/FIRIAMActionURLFollower.m +++ b/FirebaseInAppMessaging/Sources/Runtime/FIRIAMActionURLFollower.m @@ -175,8 +175,9 @@ - (BOOL)followURLWithContinueUserActivity:(NSURL *)url { FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM240004", @"App delegate responds to application:continueUserActivity:restorationHandler:." "Simulating action url opening from a web browser."); - NSUserActivity *userActivity = - [[NSUserActivity alloc] initWithActivityType:NSUserActivityTypeBrowsingWeb]; + // Use string literal to ensure compatibility with Xcode 26 and iOS 18 + NSString *browsingWebType = @"NSUserActivityTypeBrowsingWeb"; + NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:browsingWebType]; userActivity.webpageURL = url; BOOL handled = [self.appDelegate application:self.mainApplication continueUserActivity:userActivity diff --git a/FirebaseInAppMessaging/Tests/Unit/FIRIAMActionUrlFollowerTests.m b/FirebaseInAppMessaging/Tests/Unit/FIRIAMActionUrlFollowerTests.m index 9a0b56e26e5..6fe8e363402 100644 --- a/FirebaseInAppMessaging/Tests/Unit/FIRIAMActionUrlFollowerTests.m +++ b/FirebaseInAppMessaging/Tests/Unit/FIRIAMActionUrlFollowerTests.m @@ -84,8 +84,9 @@ - (void)testUniversalLinkHandlingReturnYES { continueUserActivity:[OCMArg checkWithBlock:^BOOL(id userActivity) { // verifying the type and url field for the userActivity object NSUserActivity *activity = (NSUserActivity *)userActivity; - return [activity.activityType - isEqualToString:NSUserActivityTypeBrowsingWeb] && + // Use string literal to ensure compatibility with Xcode 26 and iOS 18 + NSString *browsingWebType = @"NSUserActivityTypeBrowsingWeb"; + return [activity.activityType isEqualToString:browsingWebType] && [activity.webpageURL isEqual:url]; }] restorationHandler:[OCMArg any]]) diff --git a/FirebaseMessaging/CHANGELOG.md b/FirebaseMessaging/CHANGELOG.md index 00b746df27a..f2756c5ce0a 100644 --- a/FirebaseMessaging/CHANGELOG.md +++ b/FirebaseMessaging/CHANGELOG.md @@ -1,3 +1,8 @@ +# 12.1.0 +- [fixed] Fix Xcode 26 crash from missing `NSUserActivityTypeBrowsingWeb` + symbol. Note that this fix isn't in the 12.1.0 zip and Carthage + distributions, but will be included from 12.2.0 onwards. (#15159) + # 11.14.0 - [fixed] Fix a potential SQL injection issue. (#14846). diff --git a/FirebaseMessaging/Sources/FIRMessaging.m b/FirebaseMessaging/Sources/FIRMessaging.m index e2bb09b098c..3eb83e94e5f 100644 --- a/FirebaseMessaging/Sources/FIRMessaging.m +++ b/FirebaseMessaging/Sources/FIRMessaging.m @@ -400,8 +400,9 @@ - (void)handleIncomingLinkIfNeededFromMessage:(NSDictionary *)message { // if they haven't implemented it. if ([NSUserActivity class] != nil && [appDelegate respondsToSelector:continueUserActivitySelector]) { - NSUserActivity *userActivity = - [[NSUserActivity alloc] initWithActivityType:NSUserActivityTypeBrowsingWeb]; + // Use string literal to ensure compatibility with Xcode 26 and iOS 18 + NSString *browsingWebType = @"NSUserActivityTypeBrowsingWeb"; + NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:browsingWebType]; userActivity.webpageURL = url; [appDelegate application:application continueUserActivity:userActivity From b030a1333d756a615264f561433c5685322faf3e Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Thu, 31 Jul 2025 18:24:22 -0400 Subject: [PATCH 18/76] [Infra] Add changelog entry for Xcode 26 crash fix (#15166) --- FirebaseInAppMessaging/CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/FirebaseInAppMessaging/CHANGELOG.md b/FirebaseInAppMessaging/CHANGELOG.md index c2213ec15f6..64ca9d6955b 100644 --- a/FirebaseInAppMessaging/CHANGELOG.md +++ b/FirebaseInAppMessaging/CHANGELOG.md @@ -1,3 +1,8 @@ +# 12.1.0 +- [fixed] Fix Xcode 26 crash from missing `NSUserActivityTypeBrowsingWeb` + symbol. Note that this fix isn't in the 12.1.0 zip and Carthage + distributions, but will be included from 12.2.0 onwards. (#15159) + # 11.0.0 - [removed] **Breaking change**: The deprecated `FirebaseInAppMessagingSwift` module has been removed. See From b9bf3adac18e6e3059167194aeb632f15a5ba4b2 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Fri, 1 Aug 2025 15:38:19 -0400 Subject: [PATCH 19/76] [Firebase AI] Remove `.civicIntegrity` from `generateImage` test (#15169) --- .../Tests/Integration/GenerateContentIntegrationTests.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift index da77cea9df7..d83c300623d 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift @@ -209,6 +209,11 @@ struct GenerateContentIntegrationTests { topK: 1, responseModalities: [.text, .image] ) + let safetySettings = safetySettings.filter { + // HARM_CATEGORY_CIVIC_INTEGRITY is deprecated in Vertex AI but only rejected when using the + // 'gemini-2.0-flash-preview-image-generation' model. + $0.harmCategory != .civicIntegrity + } let model = FirebaseAI.componentInstance(config).generativeModel( modelName: ModelNames.gemini2FlashPreviewImageGeneration, generationConfig: generationConfig, From fcc8261365c81ef8121e5282b82dcad8cbd49c99 Mon Sep 17 00:00:00 2001 From: Daymon <17409137+daymxn@users.noreply.github.com> Date: Mon, 4 Aug 2025 15:37:09 -0500 Subject: [PATCH 20/76] Update Carthage json files for 12.1.0 (#15175) --- ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAIBinary.json | 3 ++- ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json | 1 + .../CarthageJSON/FirebaseMLModelDownloaderBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json | 1 + 17 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json index cf57a499bd7..46bcfece798 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json @@ -45,6 +45,7 @@ "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseABTesting-14bbd5283f79341d.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseABTesting-5436773ba2b9326e.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseABTesting-bd721c84362383a6.zip", + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseABTesting-bb0e44f97fd81c31.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/ABTesting-d0fdf10c43e985b1.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/ABTesting-d0fdf10c43e985b1.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/ABTesting-a71d17cadc209af9.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json index f7024c4b7bd..ba7d7cb3685 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json @@ -2,5 +2,6 @@ "11.13.0": "https://dl.google.com/dl/firebase/ios/carthage/11.13.0/FirebaseAI-b1e75ff6284775b1.zip", "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseAI-0991ef5c3a83833a.zip", "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseAI-ba1237ee5b7a5baa.zip", - "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseAI-05a4568076093001.zip" + "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseAI-05a4568076093001.zip", + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseAI-1fa7d016c66b2331.zip" } diff --git a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json index 57b27800483..6628fc3fdda 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json @@ -45,6 +45,7 @@ "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseAnalytics-0929c5c36f6a3dd2.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseAnalytics-fe649e5740ef72e9.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseAnalytics-70ead21957efa870.zip", + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseAnalytics-88dad74aa8ab040a.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Analytics-2468c231ebeb7922.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Analytics-bc8101d420b896c5.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Analytics-d2b6a6b0242db786.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json index 65a947bb3a0..209eee8f4d4 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json @@ -45,6 +45,7 @@ "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseAppCheck-68439fef0d9ee01c.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseAppCheck-366c926c105319b0.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseAppCheck-b9f47f169bb6249c.zip", + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseAppCheck-072a1be1f8eb1177.zip", "8.0.0": "https://dl.google.com/dl/firebase/ios/carthage/8.0.0/FirebaseAppCheck-9ef1d217cf057203.zip", "8.1.0": "https://dl.google.com/dl/firebase/ios/carthage/8.1.0/FirebaseAppCheck-fc03215d9fe45d3a.zip", "8.10.0": "https://dl.google.com/dl/firebase/ios/carthage/8.10.0/FirebaseAppCheck-6ebe9e9539f06003.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json index a0ad51cc2fd..252385766d7 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json @@ -45,6 +45,7 @@ "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseAppDistribution-e558ade73b5891d6.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseAppDistribution-32e12df219d91736.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseAppDistribution-076c2c6efb7eb8dc.zip", + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseAppDistribution-370884f5f825f098.zip", "6.31.0": "https://dl.google.com/dl/firebase/ios/carthage/6.31.0/FirebaseAppDistribution-07f6a2cf7f576a8a.zip", "6.32.0": "https://dl.google.com/dl/firebase/ios/carthage/6.32.0/FirebaseAppDistribution-a9c4f5db794508ca.zip", "6.33.0": "https://dl.google.com/dl/firebase/ios/carthage/6.33.0/FirebaseAppDistribution-448a96d2ade54581.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json index 7c63aa2557c..65ac8b39fec 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json @@ -45,6 +45,7 @@ "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseAuth-f41dc3e6a1a923d7.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseAuth-ab131b2e07abc902.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseAuth-e58b2b5f430bfbfe.zip", + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseAuth-2c17100b302eb080.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Auth-0fa76ba0f7956220.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Auth-5ddd2b4351012c7a.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Auth-5e248984d78d7284.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json index 1ff9582109d..cc05921dcfd 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json @@ -45,6 +45,7 @@ "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseCrashlytics-36f932dcd3db6874.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseCrashlytics-81aa29d9a106acb0.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseCrashlytics-d9a9be2a4e220017.zip", + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseCrashlytics-fbf241b0c59f3821.zip", "6.15.0": "https://dl.google.com/dl/firebase/ios/carthage/6.15.0/FirebaseCrashlytics-1c6d22d5b73c84fd.zip", "6.16.0": "https://dl.google.com/dl/firebase/ios/carthage/6.16.0/FirebaseCrashlytics-938e5fd0e2eab3b3.zip", "6.17.0": "https://dl.google.com/dl/firebase/ios/carthage/6.17.0/FirebaseCrashlytics-fa09f0c8f31ed5d9.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json b/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json index fc72965de98..0959ea0af13 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json @@ -45,6 +45,7 @@ "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseDatabase-8e544ced90fb6eb2.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseDatabase-8b970d6e0f67a415.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseDatabase-18b95ef28b89f3db.zip", + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseDatabase-d6c24e13e4b05437.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Database-1f7a820452722c7d.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Database-1f7a820452722c7d.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Database-59a12d87456b3e1c.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json b/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json index 66d2d9882c0..b724c13a0de 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json @@ -45,6 +45,7 @@ "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseFirestore-792558f0eddb9934.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseFirestore-30a2451150d46015.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseFirestore-635c7c2864cdd1a9.zip", + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseFirestore-6098779ef7b7b151.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Firestore-68fc02c229d0cc69.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Firestore-87a804ab561d91db.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Firestore-ecb3eea7bde7e8e8.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json index 87255957bf9..cce3563815c 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json @@ -45,6 +45,7 @@ "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseFunctions-e85bcbe133482bbc.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseFunctions-1681244d37d89040.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseFunctions-2ac7bbbaf94c52e1.zip", + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseFunctions-f4a1c660d9a2ea75.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Functions-f4c426016dd41e38.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Functions-c6c44427c3034736.zip", "5.0.0": "https://dl.google.com/dl/firebase/ios/carthage/5.0.0/Functions-146f34c401bd459b.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json b/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json index 42ea689c712..87f96dd518f 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json @@ -45,6 +45,7 @@ "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/GoogleSignIn-45d907510d5c840b.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/GoogleSignIn-d4359fb699843869.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/GoogleSignIn-b924d38d37bc920a.zip", + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/GoogleSignIn-01f98c11db934294.zip", "6.0.0": "https://dl.google.com/dl/firebase/ios/carthage/6.0.0/GoogleSignIn-de9c5d5e8eb6d6ea.zip", "6.1.0": "https://dl.google.com/dl/firebase/ios/carthage/6.1.0/GoogleSignIn-8c82f2870573a793.zip", "6.10.0": "https://dl.google.com/dl/firebase/ios/carthage/6.10.0/GoogleSignIn-ff3aef61c4a55b05.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json index 53f4da612a0..d83b9ffff48 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json @@ -45,6 +45,7 @@ "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseInAppMessaging-af2b93ac9f853087.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseInAppMessaging-67bccdf31b1dc458.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseInAppMessaging-59f9fc54fc4eecb5.zip", + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseInAppMessaging-78a0d591fb574512.zip", "5.10.0": "https://dl.google.com/dl/firebase/ios/carthage/5.10.0/InAppMessaging-a7a3f933362f6e95.zip", "5.11.0": "https://dl.google.com/dl/firebase/ios/carthage/5.11.0/InAppMessaging-fa28ce1b88fbca93.zip", "5.12.0": "https://dl.google.com/dl/firebase/ios/carthage/5.12.0/InAppMessaging-fa28ce1b88fbca93.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json b/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json index 646fbacad35..1f8860d484f 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json @@ -45,6 +45,7 @@ "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseMLModelDownloader-373db3aced970d88.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseMLModelDownloader-2d08410294abf160.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseMLModelDownloader-1f183c6e3be7cab3.zip", + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseMLModelDownloader-3864d35f4429bc08.zip", "8.0.0": "https://dl.google.com/dl/firebase/ios/carthage/8.0.0/FirebaseMLModelDownloader-8f972757fb181320.zip", "8.1.0": "https://dl.google.com/dl/firebase/ios/carthage/8.1.0/FirebaseMLModelDownloader-058ad59fa6dc0111.zip", "8.10.0": "https://dl.google.com/dl/firebase/ios/carthage/8.10.0/FirebaseMLModelDownloader-286479a966d2fb37.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json index c33b12a6473..4fc0c68b1ca 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json @@ -45,6 +45,7 @@ "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseMessaging-ffd97136b9f3cde5.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseMessaging-379bf3738f94ef44.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseMessaging-0f018ab3d7701839.zip", + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseMessaging-252cac88c87e9c55.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Messaging-a22ef2b5f2f30f82.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Messaging-94fa4e090c7e9185.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Messaging-2a00a1c64a19d176.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json b/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json index 939a7832128..0237b8ed2c3 100644 --- a/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json @@ -45,6 +45,7 @@ "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebasePerformance-e7063e87d9b3d1b7.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebasePerformance-9a2f8d3983650cea.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebasePerformance-0df8c67ab3cb665c.zip", + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebasePerformance-dec4dc5c3edadd9a.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Performance-d8693eb892bfa05b.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Performance-0a400f9460f7a71d.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Performance-f5b4002ab96523e4.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json b/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json index fb0b84442a7..9027616f5d0 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json @@ -45,6 +45,7 @@ "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseRemoteConfig-6e66634da4590f07.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseRemoteConfig-7455afe6f2231467.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseRemoteConfig-5894aa4820a265ae.zip", + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseRemoteConfig-bb5ba29a5f73cd24.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/RemoteConfig-7e9635365ccd4a17.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/RemoteConfig-e7928fcb6311c439.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/RemoteConfig-9ab1ca5f360a1780.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json b/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json index 69838986e91..b753e8be256 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json @@ -45,6 +45,7 @@ "11.8.0": "https://dl.google.com/dl/firebase/ios/carthage/11.8.0/FirebaseStorage-f55cadd62f44b14f.zip", "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseStorage-5a28ee1b2244be55.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseStorage-21ed034a4fa51f2a.zip", + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseStorage-faeffdccd0d44a7c.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Storage-6b3e77e1a7fdbc61.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Storage-4721c35d2b90a569.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Storage-821299369b9d0fb2.zip", From fb59b2a1f1c117ea549b55376c6f9f0a9757bae5 Mon Sep 17 00:00:00 2001 From: Daymon <17409137+daymxn@users.noreply.github.com> Date: Mon, 4 Aug 2025 19:56:46 -0500 Subject: [PATCH 21/76] Update versions for Release 12.2.0 (#15176) --- Firebase.podspec | 44 +++++++++---------- FirebaseABTesting.podspec | 4 +- FirebaseAI.podspec | 10 ++--- FirebaseAnalytics.podspec | 12 ++--- FirebaseAppCheck.podspec | 6 +-- FirebaseAppCheckInterop.podspec | 2 +- FirebaseAppDistribution.podspec | 6 +-- FirebaseAuth.podspec | 10 ++--- FirebaseAuthInterop.podspec | 2 +- FirebaseCombineSwift.podspec | 14 +++--- FirebaseCore.podspec | 4 +- FirebaseCoreExtension.podspec | 4 +- FirebaseCoreInternal.podspec | 2 +- FirebaseCrashlytics.podspec | 10 ++--- FirebaseDatabase.podspec | 10 ++--- FirebaseFirestore.podspec | 10 ++--- FirebaseFirestoreInternal.podspec | 6 +-- FirebaseFunctions.podspec | 14 +++--- FirebaseInAppMessaging.podspec | 8 ++-- FirebaseInstallations.podspec | 4 +- FirebaseMLModelDownloader.podspec | 8 ++-- FirebaseMessaging.podspec | 6 +-- FirebaseMessagingInterop.podspec | 2 +- FirebasePerformance.podspec | 10 ++--- FirebaseRemoteConfig.podspec | 12 ++--- FirebaseRemoteConfigInterop.podspec | 2 +- FirebaseSessions.podspec | 8 ++-- FirebaseSharedSwift.podspec | 2 +- FirebaseStorage.podspec | 14 +++--- GoogleAppMeasurement.podspec | 8 ++-- Package.swift | 2 +- .../FirebaseManifest/FirebaseManifest.swift | 2 +- 32 files changed, 129 insertions(+), 129 deletions(-) diff --git a/Firebase.podspec b/Firebase.podspec index 6374a742fa2..415d933d8e0 100644 --- a/Firebase.podspec +++ b/Firebase.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Firebase' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Firebase' s.description = <<-DESC @@ -36,14 +36,14 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '15.0' - ss.ios.dependency 'FirebaseAnalytics', '~> 12.1.0' - ss.osx.dependency 'FirebaseAnalytics', '~> 12.1.0' - ss.tvos.dependency 'FirebaseAnalytics', '~> 12.1.0' + ss.ios.dependency 'FirebaseAnalytics', '~> 12.2.0' + ss.osx.dependency 'FirebaseAnalytics', '~> 12.2.0' + ss.tvos.dependency 'FirebaseAnalytics', '~> 12.2.0' ss.dependency 'Firebase/CoreOnly' end s.subspec 'CoreOnly' do |ss| - ss.dependency 'FirebaseCore', '~> 12.1.0' + ss.dependency 'FirebaseCore', '~> 12.2.0' ss.source_files = 'CoreOnly/Sources/Firebase.h' ss.preserve_paths = 'CoreOnly/Sources/module.modulemap' if ENV['FIREBASE_POD_REPO_FOR_DEV_POD'] then @@ -70,7 +70,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'ABTesting' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseABTesting', '~> 12.1.0' + ss.dependency 'FirebaseABTesting', '~> 12.2.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -80,13 +80,13 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'AppDistribution' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseAppDistribution', '~> 12.1.0-beta' + ss.ios.dependency 'FirebaseAppDistribution', '~> 12.2.0-beta' ss.ios.deployment_target = '15.0' end s.subspec 'AppCheck' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseAppCheck', '~> 12.1.0' + ss.dependency 'FirebaseAppCheck', '~> 12.2.0' ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '15.0' @@ -95,7 +95,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Auth' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseAuth', '~> 12.1.0' + ss.dependency 'FirebaseAuth', '~> 12.2.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -105,7 +105,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Crashlytics' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseCrashlytics', '~> 12.1.0' + ss.dependency 'FirebaseCrashlytics', '~> 12.2.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -115,7 +115,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Database' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseDatabase', '~> 12.1.0' + ss.dependency 'FirebaseDatabase', '~> 12.2.0' # Standard platforms PLUS watchOS 7. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -125,7 +125,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Firestore' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseFirestore', '~> 12.1.0' + ss.dependency 'FirebaseFirestore', '~> 12.2.0' ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '15.0' @@ -133,7 +133,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Functions' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseFunctions', '~> 12.1.0' + ss.dependency 'FirebaseFunctions', '~> 12.2.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -143,20 +143,20 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'InAppMessaging' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseInAppMessaging', '~> 12.1.0-beta' - ss.tvos.dependency 'FirebaseInAppMessaging', '~> 12.1.0-beta' + ss.ios.dependency 'FirebaseInAppMessaging', '~> 12.2.0-beta' + ss.tvos.dependency 'FirebaseInAppMessaging', '~> 12.2.0-beta' ss.ios.deployment_target = '15.0' ss.tvos.deployment_target = '15.0' end s.subspec 'Installations' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseInstallations', '~> 12.1.0' + ss.dependency 'FirebaseInstallations', '~> 12.2.0' end s.subspec 'Messaging' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseMessaging', '~> 12.1.0' + ss.dependency 'FirebaseMessaging', '~> 12.2.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -166,7 +166,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'MLModelDownloader' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseMLModelDownloader', '~> 12.1.0-beta' + ss.dependency 'FirebaseMLModelDownloader', '~> 12.2.0-beta' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -176,15 +176,15 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Performance' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebasePerformance', '~> 12.1.0' - ss.tvos.dependency 'FirebasePerformance', '~> 12.1.0' + ss.ios.dependency 'FirebasePerformance', '~> 12.2.0' + ss.tvos.dependency 'FirebasePerformance', '~> 12.2.0' ss.ios.deployment_target = '15.0' ss.tvos.deployment_target = '15.0' end s.subspec 'RemoteConfig' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseRemoteConfig', '~> 12.1.0' + ss.dependency 'FirebaseRemoteConfig', '~> 12.2.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -194,7 +194,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Storage' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseStorage', '~> 12.1.0' + ss.dependency 'FirebaseStorage', '~> 12.2.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' diff --git a/FirebaseABTesting.podspec b/FirebaseABTesting.podspec index ea2ec8c25a2..d6cfb519ae4 100644 --- a/FirebaseABTesting.podspec +++ b/FirebaseABTesting.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseABTesting' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Firebase ABTesting' s.description = <<-DESC @@ -51,7 +51,7 @@ Firebase Cloud Messaging and Firebase Remote Config in your app. s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } - s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.2.0' s.test_spec 'unit' do |unit_tests| unit_tests.scheme = { :code_coverage => true } diff --git a/FirebaseAI.podspec b/FirebaseAI.podspec index 24c91ff90ac..9b5787bf038 100644 --- a/FirebaseAI.podspec +++ b/FirebaseAI.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAI' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Firebase AI SDK' s.description = <<-DESC @@ -43,10 +43,10 @@ Build AI-powered apps and features with the Gemini API using the Firebase AI SDK s.tvos.framework = 'UIKit' s.watchos.framework = 'WatchKit' - s.dependency 'FirebaseAppCheckInterop', '~> 12.1.0' - s.dependency 'FirebaseAuthInterop', '~> 12.1.0' - s.dependency 'FirebaseCore', '~> 12.1.0' - s.dependency 'FirebaseCoreExtension', '~> 12.1.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.2.0' + s.dependency 'FirebaseAuthInterop', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseCoreExtension', '~> 12.2.0' s.test_spec 'unit' do |unit_tests| unit_tests_dir = 'FirebaseAI/Tests/Unit/' diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index 6beee36dd2c..4a6e7393d68 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAnalytics' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Firebase Analytics for iOS' s.description = <<-DESC @@ -26,8 +26,8 @@ Pod::Spec.new do |s| s.libraries = 'c++', 'sqlite3', 'z' s.frameworks = 'StoreKit' - s.dependency 'FirebaseCore', '~> 12.1.0' - s.dependency 'FirebaseInstallations', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseInstallations', '~> 12.2.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/MethodSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/NSData+zlib', '~> 8.1' @@ -37,17 +37,17 @@ Pod::Spec.new do |s| s.default_subspecs = 'Default' s.subspec 'Default' do |ss| - ss.dependency 'GoogleAppMeasurement/Default', '12.1.0' + ss.dependency 'GoogleAppMeasurement/Default', '12.2.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end s.subspec 'Core' do |ss| - ss.dependency 'GoogleAppMeasurement/Core', '12.1.0' + ss.dependency 'GoogleAppMeasurement/Core', '12.2.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end s.subspec 'IdentitySupport' do |ss| - ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.1.0' + ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.2.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end diff --git a/FirebaseAppCheck.podspec b/FirebaseAppCheck.podspec index 1aad2a45a7d..86d023c4c3d 100644 --- a/FirebaseAppCheck.podspec +++ b/FirebaseAppCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppCheck' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Firebase App Check SDK.' s.description = <<-DESC @@ -45,8 +45,8 @@ Pod::Spec.new do |s| s.tvos.weak_framework = 'DeviceCheck' s.dependency 'AppCheckCore', '~> 11.0' - s.dependency 'FirebaseAppCheckInterop', '~> 12.1.0' - s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.2.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseAppCheckInterop.podspec b/FirebaseAppCheckInterop.podspec index 0f53cfb45f9..5b2a61f6134 100644 --- a/FirebaseAppCheckInterop.podspec +++ b/FirebaseAppCheckInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppCheckInterop' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Interfaces that allow other Firebase SDKs to use AppCheck functionality.' s.description = <<-DESC diff --git a/FirebaseAppDistribution.podspec b/FirebaseAppDistribution.podspec index f438f03a7e9..853a66272b6 100644 --- a/FirebaseAppDistribution.podspec +++ b/FirebaseAppDistribution.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppDistribution' - s.version = '12.1.0-beta' + s.version = '12.2.0-beta' s.summary = 'App Distribution for Firebase iOS SDK.' s.description = <<-DESC @@ -30,10 +30,10 @@ iOS SDK for App Distribution for Firebase. ] s.public_header_files = base_dir + 'Public/FirebaseAppDistribution/*.h' - s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.2.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' - s.dependency 'FirebaseInstallations', '~> 12.1.0' + s.dependency 'FirebaseInstallations', '~> 12.2.0' s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' diff --git a/FirebaseAuth.podspec b/FirebaseAuth.podspec index d89d0e222fb..e192db98da9 100644 --- a/FirebaseAuth.podspec +++ b/FirebaseAuth.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAuth' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Apple platform client for Firebase Authentication' s.description = <<-DESC @@ -55,10 +55,10 @@ supports email and password accounts, as well as several 3rd party authenticatio } s.framework = 'Security' s.ios.framework = 'SafariServices' - s.dependency 'FirebaseAuthInterop', '~> 12.1.0' - s.dependency 'FirebaseAppCheckInterop', '~> 12.1.0' - s.dependency 'FirebaseCore', '~> 12.1.0' - s.dependency 'FirebaseCoreExtension', '~> 12.1.0' + s.dependency 'FirebaseAuthInterop', '~> 12.2.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseCoreExtension', '~> 12.2.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 6.0' diff --git a/FirebaseAuthInterop.podspec b/FirebaseAuthInterop.podspec index e20e453e484..c5c5877c8d1 100644 --- a/FirebaseAuthInterop.podspec +++ b/FirebaseAuthInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAuthInterop' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Auth functionality.' s.description = <<-DESC diff --git a/FirebaseCombineSwift.podspec b/FirebaseCombineSwift.podspec index 22fda02d2fe..e25c93a9bdf 100644 --- a/FirebaseCombineSwift.podspec +++ b/FirebaseCombineSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCombineSwift' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Swift extensions with Combine support for Firebase' s.description = <<-DESC @@ -51,11 +51,11 @@ for internal testing only. It should not be published. s.osx.framework = 'AppKit' s.tvos.framework = 'UIKit' - s.dependency 'FirebaseCore', '~> 12.1.0' - s.dependency 'FirebaseAuth', '~> 12.1.0' - s.dependency 'FirebaseFunctions', '~> 12.1.0' - s.dependency 'FirebaseFirestore', '~> 12.1.0' - s.dependency 'FirebaseStorage', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseAuth', '~> 12.2.0' + s.dependency 'FirebaseFunctions', '~> 12.2.0' + s.dependency 'FirebaseFirestore', '~> 12.2.0' + s.dependency 'FirebaseStorage', '~> 12.2.0' s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"', @@ -104,6 +104,6 @@ for internal testing only. It should not be published. int_tests.resources = 'FirebaseStorage/Tests/Integration/Resources/1mb.dat', 'FirebaseStorage/Tests/Integration/Resources/GoogleService-Info.plist', 'FirebaseStorage/Tests/Integration/Resources/HomeImprovement.numbers' - int_tests.dependency 'FirebaseAuth', '~> 12.1.0' + int_tests.dependency 'FirebaseAuth', '~> 12.2.0' end end diff --git a/FirebaseCore.podspec b/FirebaseCore.podspec index 9767f1c893e..77c336ba8c4 100644 --- a/FirebaseCore.podspec +++ b/FirebaseCore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCore' - s.version = '12.1.0' + s.version = '12.2.0' 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.1' s.dependency 'GoogleUtilities/Logger', '~> 8.1' - s.dependency 'FirebaseCoreInternal', '~> 12.1.0' + s.dependency 'FirebaseCoreInternal', '~> 12.2.0' s.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'Firebase_VERSION=' + s.version.to_s, diff --git a/FirebaseCoreExtension.podspec b/FirebaseCoreExtension.podspec index 4458e7e9cd3..b7c893d25c1 100644 --- a/FirebaseCoreExtension.podspec +++ b/FirebaseCoreExtension.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCoreExtension' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Extended FirebaseCore APIs for Firebase product SDKs' s.description = <<-DESC @@ -34,5 +34,5 @@ Pod::Spec.new do |s| "#{s.module_name}_Privacy" => 'FirebaseCore/Extension/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.2.0' end diff --git a/FirebaseCoreInternal.podspec b/FirebaseCoreInternal.podspec index e75d03cb018..a5832bb6e8e 100644 --- a/FirebaseCoreInternal.podspec +++ b/FirebaseCoreInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCoreInternal' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'APIs for internal FirebaseCore usage.' s.description = <<-DESC diff --git a/FirebaseCrashlytics.podspec b/FirebaseCrashlytics.podspec index 22b9cc1e163..8675001983c 100644 --- a/FirebaseCrashlytics.podspec +++ b/FirebaseCrashlytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCrashlytics' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Best and lightest-weight crash reporting for mobile, desktop and tvOS.' s.description = 'Firebase Crashlytics helps you track, prioritize, and fix stability issues that erode app quality.' s.homepage = 'https://firebase.google.com/' @@ -59,10 +59,10 @@ Pod::Spec.new do |s| cp -f ./Crashlytics/CrashlyticsInputFiles.xcfilelist ./CrashlyticsInputFiles.xcfilelist PREPARE_COMMAND_END - s.dependency 'FirebaseCore', '~> 12.1.0' - s.dependency 'FirebaseInstallations', '~> 12.1.0' - s.dependency 'FirebaseSessions', '~> 12.1.0' - s.dependency 'FirebaseRemoteConfigInterop', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseInstallations', '~> 12.2.0' + s.dependency 'FirebaseSessions', '~> 12.2.0' + s.dependency 'FirebaseRemoteConfigInterop', '~> 12.2.0' s.dependency 'PromisesObjC', '~> 2.4' s.dependency 'GoogleDataTransport', '~> 10.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' diff --git a/FirebaseDatabase.podspec b/FirebaseDatabase.podspec index 4ab36e76ed3..86931787c3b 100644 --- a/FirebaseDatabase.podspec +++ b/FirebaseDatabase.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseDatabase' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Firebase Realtime Database' s.description = <<-DESC @@ -48,9 +48,9 @@ Simplify your iOS development, grow your user base, and monetize more effectivel s.macos.frameworks = 'CFNetwork', 'Security', 'SystemConfiguration' s.watchos.frameworks = 'CFNetwork', 'Security', 'WatchKit' s.dependency 'leveldb-library', '~> 1.22' - s.dependency 'FirebaseCore', '~> 12.1.0' - s.dependency 'FirebaseAppCheckInterop', '~> 12.1.0' - s.dependency 'FirebaseSharedSwift', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.2.0' + s.dependency 'FirebaseSharedSwift', '~> 12.2.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' @@ -72,7 +72,7 @@ Simplify your iOS development, grow your user base, and monetize more effectivel 'SharedTestUtilities/FIRComponentTestUtilities.[mh]', 'SharedTestUtilities/FIROptionsMock.[mh]', ] - unit_tests.dependency 'FirebaseAppCheckInterop', '~> 12.1.0' + unit_tests.dependency 'FirebaseAppCheckInterop', '~> 12.2.0' unit_tests.dependency 'OCMock' unit_tests.resources = 'FirebaseDatabase/Tests/Resources/syncPointSpec.json', 'FirebaseDatabase/Tests/Resources/GoogleService-Info.plist' diff --git a/FirebaseFirestore.podspec b/FirebaseFirestore.podspec index 42a937b7681..df500387412 100644 --- a/FirebaseFirestore.podspec +++ b/FirebaseFirestore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFirestore' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Google Cloud Firestore' s.description = <<-DESC Google Cloud Firestore is a NoSQL document database built for automatic scaling, high performance, and ease of application development. @@ -35,9 +35,9 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, "#{s.module_name}_Privacy" => 'Firestore/Swift/Source/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '~> 12.1.0' - s.dependency 'FirebaseCoreExtension', '~> 12.1.0' - s.dependency 'FirebaseFirestoreInternal', '~> 12.1.0' - s.dependency 'FirebaseSharedSwift', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseCoreExtension', '~> 12.2.0' + s.dependency 'FirebaseFirestoreInternal', '~> 12.2.0' + s.dependency 'FirebaseSharedSwift', '~> 12.2.0' end diff --git a/FirebaseFirestoreInternal.podspec b/FirebaseFirestoreInternal.podspec index 57e9ce8bfd1..b2881725ecb 100644 --- a/FirebaseFirestoreInternal.podspec +++ b/FirebaseFirestoreInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFirestoreInternal' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Google Cloud Firestore' s.description = <<-DESC @@ -91,8 +91,8 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, "#{s.module_name}_Privacy" => 'Firestore/Source/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseAppCheckInterop', '~> 12.1.0' - s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.2.0' abseil_version = '~> 1.20240722.0' s.dependency 'abseil/algorithm', abseil_version diff --git a/FirebaseFunctions.podspec b/FirebaseFunctions.podspec index b26ef279af2..52bbf0f26c1 100644 --- a/FirebaseFunctions.podspec +++ b/FirebaseFunctions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFunctions' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Cloud Functions for Firebase' s.description = <<-DESC @@ -35,12 +35,12 @@ Cloud Functions for Firebase. 'FirebaseFunctions/Sources/**/*.swift', ] - s.dependency 'FirebaseCore', '~> 12.1.0' - s.dependency 'FirebaseCoreExtension', '~> 12.1.0' - s.dependency 'FirebaseAppCheckInterop', '~> 12.1.0' - s.dependency 'FirebaseAuthInterop', '~> 12.1.0' - s.dependency 'FirebaseMessagingInterop', '~> 12.1.0' - s.dependency 'FirebaseSharedSwift', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseCoreExtension', '~> 12.2.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.2.0' + s.dependency 'FirebaseAuthInterop', '~> 12.2.0' + s.dependency 'FirebaseMessagingInterop', '~> 12.2.0' + s.dependency 'FirebaseSharedSwift', '~> 12.2.0' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 6.0' s.test_spec 'objc' do |objc_tests| diff --git a/FirebaseInAppMessaging.podspec b/FirebaseInAppMessaging.podspec index ef773f8c441..ed309155b99 100644 --- a/FirebaseInAppMessaging.podspec +++ b/FirebaseInAppMessaging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseInAppMessaging' - s.version = '12.1.0-beta' + s.version = '12.2.0-beta' s.summary = 'Firebase In-App Messaging for iOS' s.description = <<-DESC @@ -80,9 +80,9 @@ See more product details at https://firebase.google.com/products/in-app-messagin s.framework = 'UIKit' - s.dependency 'FirebaseCore', '~> 12.1.0' - s.dependency 'FirebaseInstallations', '~> 12.1.0' - s.dependency 'FirebaseABTesting', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseInstallations', '~> 12.2.0' + s.dependency 'FirebaseABTesting', '~> 12.2.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' s.dependency 'nanopb', '~> 3.30910.0' diff --git a/FirebaseInstallations.podspec b/FirebaseInstallations.podspec index 87b49973f1d..217fe097416 100644 --- a/FirebaseInstallations.podspec +++ b/FirebaseInstallations.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseInstallations' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Firebase Installations' s.description = <<-DESC @@ -45,7 +45,7 @@ Pod::Spec.new do |s| } s.framework = 'Security' - s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.2.0' s.dependency 'PromisesObjC', '~> 2.4' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseMLModelDownloader.podspec b/FirebaseMLModelDownloader.podspec index 7fa88c88c95..1c19d2e8746 100644 --- a/FirebaseMLModelDownloader.podspec +++ b/FirebaseMLModelDownloader.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMLModelDownloader' - s.version = '12.1.0-beta' + s.version = '12.2.0-beta' s.summary = 'Firebase ML Model Downloader' s.description = <<-DESC @@ -36,9 +36,9 @@ Pod::Spec.new do |s| ] s.framework = 'Foundation' - s.dependency 'FirebaseCore', '~> 12.1.0' - s.dependency 'FirebaseCoreExtension', '~> 12.1.0' - s.dependency 'FirebaseInstallations', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseCoreExtension', '~> 12.2.0' + s.dependency 'FirebaseInstallations', '~> 12.2.0' s.dependency 'GoogleDataTransport', '~> 10.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' s.dependency 'SwiftProtobuf', '~> 1.19' diff --git a/FirebaseMessaging.podspec b/FirebaseMessaging.podspec index 96b25677379..06f138db888 100644 --- a/FirebaseMessaging.podspec +++ b/FirebaseMessaging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMessaging' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Firebase Messaging' s.description = <<-DESC @@ -60,8 +60,8 @@ device, and it is completely free. s.tvos.framework = 'SystemConfiguration' s.osx.framework = 'SystemConfiguration' s.weak_framework = 'UserNotifications' - s.dependency 'FirebaseInstallations', '~> 12.1.0' - s.dependency 'FirebaseCore', '~> 12.1.0' + s.dependency 'FirebaseInstallations', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.2.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/Reachability', '~> 8.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' diff --git a/FirebaseMessagingInterop.podspec b/FirebaseMessagingInterop.podspec index 80409d6bf2d..cedd5c82a8b 100644 --- a/FirebaseMessagingInterop.podspec +++ b/FirebaseMessagingInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMessagingInterop' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Messaging functionality.' s.description = <<-DESC diff --git a/FirebasePerformance.podspec b/FirebasePerformance.podspec index 0fb8108870d..78cefbdaede 100644 --- a/FirebasePerformance.podspec +++ b/FirebasePerformance.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebasePerformance' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Firebase Performance' s.description = <<-DESC @@ -58,10 +58,10 @@ Firebase Performance library to measure performance of Mobile and Web Apps. s.ios.framework = 'CoreTelephony' s.framework = 'QuartzCore' s.framework = 'SystemConfiguration' - s.dependency 'FirebaseCore', '~> 12.1.0' - s.dependency 'FirebaseInstallations', '~> 12.1.0' - s.dependency 'FirebaseRemoteConfig', '~> 12.1.0' - s.dependency 'FirebaseSessions', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseInstallations', '~> 12.2.0' + s.dependency 'FirebaseRemoteConfig', '~> 12.2.0' + s.dependency 'FirebaseSessions', '~> 12.2.0' s.dependency 'GoogleDataTransport', '~> 10.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/MethodSwizzler', '~> 8.1' diff --git a/FirebaseRemoteConfig.podspec b/FirebaseRemoteConfig.podspec index f384ed8f29a..06fde8ddcb4 100644 --- a/FirebaseRemoteConfig.podspec +++ b/FirebaseRemoteConfig.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseRemoteConfig' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Firebase Remote Config' s.description = <<-DESC @@ -49,13 +49,13 @@ app update. s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } - s.dependency 'FirebaseABTesting', '~> 12.1.0' - s.dependency 'FirebaseSharedSwift', '~> 12.1.0' - s.dependency 'FirebaseCore', '~> 12.1.0' - s.dependency 'FirebaseInstallations', '~> 12.1.0' + s.dependency 'FirebaseABTesting', '~> 12.2.0' + s.dependency 'FirebaseSharedSwift', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseInstallations', '~> 12.2.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/NSData+zlib', '~> 8.1' - s.dependency 'FirebaseRemoteConfigInterop', '~> 12.1.0' + s.dependency 'FirebaseRemoteConfigInterop', '~> 12.2.0' s.test_spec 'unit' do |unit_tests| unit_tests.scheme = { :code_coverage => true } diff --git a/FirebaseRemoteConfigInterop.podspec b/FirebaseRemoteConfigInterop.podspec index ddb7c209c3f..3266634c9fa 100644 --- a/FirebaseRemoteConfigInterop.podspec +++ b/FirebaseRemoteConfigInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseRemoteConfigInterop' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Remote Config functionality.' s.description = <<-DESC diff --git a/FirebaseSessions.podspec b/FirebaseSessions.podspec index 88b2b827e16..88406da2eb6 100644 --- a/FirebaseSessions.podspec +++ b/FirebaseSessions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseSessions' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Firebase Sessions' s.description = <<-DESC @@ -39,9 +39,9 @@ Pod::Spec.new do |s| base_dir + 'SourcesObjC/**/*.{c,h,m,mm}', ] - s.dependency 'FirebaseCore', '~> 12.1.0' - s.dependency 'FirebaseCoreExtension', '~> 12.1.0' - s.dependency 'FirebaseInstallations', '~> 12.1.0' + s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseCoreExtension', '~> 12.2.0' + s.dependency 'FirebaseInstallations', '~> 12.2.0' s.dependency 'GoogleDataTransport', '~> 10.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseSharedSwift.podspec b/FirebaseSharedSwift.podspec index d14ad49b44d..b52cf86f973 100644 --- a/FirebaseSharedSwift.podspec +++ b/FirebaseSharedSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseSharedSwift' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Shared Swift Extensions for Firebase' s.description = <<-DESC diff --git a/FirebaseStorage.podspec b/FirebaseStorage.podspec index d1dc7201bbc..ac4caed6655 100644 --- a/FirebaseStorage.podspec +++ b/FirebaseStorage.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseStorage' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Firebase Storage' s.description = <<-DESC @@ -37,10 +37,10 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas 'FirebaseStorage/Typedefs/*.h', ] - s.dependency 'FirebaseAppCheckInterop', '~> 12.1.0' - s.dependency 'FirebaseAuthInterop', '~> 12.1.0' - s.dependency 'FirebaseCore', '~> 12.1.0' - s.dependency 'FirebaseCoreExtension', '~> 12.1.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.2.0' + s.dependency 'FirebaseAuthInterop', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseCoreExtension', '~> 12.2.0' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 6.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' @@ -57,7 +57,7 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas objc_tests.requires_app_host = true objc_tests.resources = 'FirebaseStorage/Tests/Integration/Resources/1mb.dat', 'FirebaseStorage/Tests/Integration/Resources/GoogleService-Info.plist' - objc_tests.dependency 'FirebaseAuth', '~> 12.1.0' + objc_tests.dependency 'FirebaseAuth', '~> 12.2.0' objc_tests.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } @@ -86,6 +86,6 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas int_tests.resources = 'FirebaseStorage/Tests/Integration/Resources/1mb.dat', 'FirebaseStorage/Tests/Integration/Resources/GoogleService-Info.plist', 'FirebaseStorage/Tests/Integration/Resources/HomeImprovement.numbers' - int_tests.dependency 'FirebaseAuth', '~> 12.1.0' + int_tests.dependency 'FirebaseAuth', '~> 12.2.0' end end diff --git a/GoogleAppMeasurement.podspec b/GoogleAppMeasurement.podspec index f9fc10c2772..5b649c66cbb 100644 --- a/GoogleAppMeasurement.podspec +++ b/GoogleAppMeasurement.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'GoogleAppMeasurement' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Shared measurement methods for Google libraries. Not intended for direct use.' s.description = <<-DESC @@ -37,8 +37,8 @@ Pod::Spec.new do |s| s.default_subspecs = 'Default' s.subspec 'Default' do |ss| - ss.dependency 'GoogleAppMeasurement/Core', '12.1.0' - ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.1.0' + ss.dependency 'GoogleAppMeasurement/Core', '12.2.0' + ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.2.0' ss.ios.dependency 'GoogleAdsOnDeviceConversion', '2.2.0' end @@ -47,7 +47,7 @@ Pod::Spec.new do |s| end s.subspec 'IdentitySupport' do |ss| - ss.dependency 'GoogleAppMeasurement/Core', '12.1.0' + ss.dependency 'GoogleAppMeasurement/Core', '12.2.0' ss.vendored_frameworks = 'Frameworks/GoogleAppMeasurementIdentitySupport.xcframework' end end diff --git a/Package.swift b/Package.swift index 2a5240e3bf7..1de488a3886 100644 --- a/Package.swift +++ b/Package.swift @@ -18,7 +18,7 @@ import PackageDescription -let firebaseVersion = "12.1.0" +let firebaseVersion = "12.2.0" let package = Package( name: "Firebase", diff --git a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift index 27faaa0b188..9e5a6aebb35 100755 --- a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift +++ b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift @@ -21,7 +21,7 @@ import Foundation /// The version and releasing fields of the non-Firebase pods should be reviewed every release. /// The array should be ordered so that any pod's dependencies precede it in the list. public let shared = Manifest( - version: "12.1.0", + version: "12.2.0", pods: [ Pod("FirebaseSharedSwift"), Pod("FirebaseCoreInternal"), From b550a0669ac15284ec346a6563e565c20a1ed3de Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Wed, 6 Aug 2025 10:21:59 -0400 Subject: [PATCH 22/76] [Firebase AI] Add `retry-tests-on-failure` for integration tests (#15177) --- scripts/build.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/build.sh b/scripts/build.sh index 80cc79f0bb5..30b84004c3b 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -521,6 +521,8 @@ case "$product-$platform-$method" in -scheme "FirebaseAITestApp-SPM" \ "${xcb_flags[@]}" \ -parallel-testing-enabled NO \ + -retry-tests-on-failure \ + -test-iterations 3 \ test ;; From 7f3c935bcf1dd27c5ab06d5ae1257a9d4e28e9bb Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 11 Aug 2025 13:42:59 -0400 Subject: [PATCH 23/76] [Infra] Attempt to reduce Crashlytics testing flake (#15183) --- Crashlytics/UnitTests/Mocks/FIRCLSMockFileManager.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Crashlytics/UnitTests/Mocks/FIRCLSMockFileManager.m b/Crashlytics/UnitTests/Mocks/FIRCLSMockFileManager.m index b89d05bbff8..955e701d065 100644 --- a/Crashlytics/UnitTests/Mocks/FIRCLSMockFileManager.m +++ b/Crashlytics/UnitTests/Mocks/FIRCLSMockFileManager.m @@ -41,7 +41,9 @@ - (BOOL)removeItemAtPath:(NSString *)path { // If we set up the expectation, and we went over the expected count or removes, fulfill the // expectation if (self.removeExpectation && self.removeCount >= self.expectedRemoveCount) { - [self.removeExpectation fulfill]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self.removeExpectation fulfill]; + }); } return YES; From b7db7b4492e33d954f6868c1807aed650f337fff Mon Sep 17 00:00:00 2001 From: Ben Hagen Date: Tue, 12 Aug 2025 17:39:28 +0200 Subject: [PATCH 24/76] [Auth] TOTP support for macOS (#15112) Co-authored-by: Nick Cooke <36927374+ncooke3@users.noreply.github.com> --- FirebaseAuth/CHANGELOG.md | 3 + FirebaseAuth/README.md | 2 +- .../Sources/ObjC/FIRMultiFactorConstants.m | 2 +- .../Public/FirebaseAuth/FIRMultiFactor.h | 15 +++-- .../Sources/Swift/Backend/AuthBackend.swift | 8 +-- .../Swift/MultiFactor/MultiFactor.swift | 4 +- .../MultiFactor/MultiFactorAssertion.swift | 4 +- .../Swift/MultiFactor/MultiFactorInfo.swift | 4 +- .../MultiFactor/MultiFactorResolver.swift | 4 +- .../MultiFactor/MultiFactorSession.swift | 4 +- .../Phone/PhoneMultiFactorAssertion.swift | 4 +- .../Phone/PhoneMultiFactorGenerator.swift | 4 +- .../Phone/PhoneMultiFactorInfo.swift | 4 +- .../TOTP/TOTPMultFactorAssertion.swift | 4 +- .../TOTP/TOTPMultiFactorGenerator.swift | 4 +- .../TOTP/TOTPMultiFactorInfo.swift | 4 +- .../Swift/MultiFactor/TOTP/TOTPSecret.swift | 49 +++++++++++------ FirebaseAuth/Sources/Swift/User/User.swift | 14 ++--- .../Swift/Utilities/AuthErrorUtils.swift | 4 +- FirebaseAuth/Tests/Unit/ObjCAPITests.m | 6 +- FirebaseAuth/Tests/Unit/ObjCGlobalTests.m | 4 +- FirebaseAuth/Tests/Unit/SwiftAPI.swift | 4 +- .../Tests/Unit/SwiftGlobalTests.swift | 5 +- FirebaseAuth/Tests/Unit/UserTests.swift | 55 +++++++++++++------ .../Sources/Auth/MultiFactor+Combine.swift | 7 +-- .../Auth/MultiFactorResolver+Combine.swift | 7 +-- 26 files changed, 135 insertions(+), 94 deletions(-) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index a0d6d7a2210..cd04d3440d7 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,3 +1,6 @@ +# Unreleased +- [added] Added TOTP support for macOS. + # 12.1.0 - [fixed] Fix a formatting issue with generated TOTP URLs that prevented them from working with the Google Authenticator app. (#15128) diff --git a/FirebaseAuth/README.md b/FirebaseAuth/README.md index 1dbb6f9cbc3..b055658e4c9 100644 --- a/FirebaseAuth/README.md +++ b/FirebaseAuth/README.md @@ -1,4 +1,4 @@ -# Firebase Auth for iOS +# Firebase Auth for iOS and macOS Firebase Auth enables apps to easily support multiple authentication options for their end users. diff --git a/FirebaseAuth/Sources/ObjC/FIRMultiFactorConstants.m b/FirebaseAuth/Sources/ObjC/FIRMultiFactorConstants.m index 4862a485884..85648f2fc3b 100644 --- a/FirebaseAuth/Sources/ObjC/FIRMultiFactorConstants.m +++ b/FirebaseAuth/Sources/ObjC/FIRMultiFactorConstants.m @@ -15,7 +15,7 @@ */ #import -#if TARGET_OS_IOS +#if TARGET_OS_IOS || TARGET_OS_OSX #import diff --git a/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h b/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h index aae0db8ab6f..da05c8309ce 100644 --- a/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h +++ b/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h @@ -5,7 +5,7 @@ * 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/LICENSE2.0 + * 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, @@ -22,27 +22,26 @@ NS_ASSUME_NONNULL_BEGIN /** @typedef FIRMultiFactorSessionCallback @brief The callback that triggered when a developer calls `getSessionWithCompletion`. - This type is available on iOS only. + This type is available on iOS and macOS. @param session The multi factor session returned, if any. @param error The error which occurred, if any. */ typedef void (^FIRMultiFactorSessionCallback)(FIRMultiFactorSession *_Nullable session, NSError *_Nullable error) - NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead.") - API_UNAVAILABLE(macos, tvos, watchos); + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead.") API_UNAVAILABLE(tvos, watchos); /** @brief The string identifier for using phone as a second factor. - This constant is available on iOS only. + This constant is available on iOS and macOS. */ extern NSString *const _Nonnull FIRPhoneMultiFactorID NS_SWIFT_NAME(PhoneMultiFactorID) - API_UNAVAILABLE(macos, tvos, watchos); + API_UNAVAILABLE(tvos, watchos); /** @brief The string identifier for using TOTP as a second factor. - This constant is available on iOS only. + This constant is available on iOS and macOS. */ extern NSString *const _Nonnull FIRTOTPMultiFactorID NS_SWIFT_NAME(TOTPMultiFactorID) - API_UNAVAILABLE(macos, tvos, watchos); + API_UNAVAILABLE(tvos, watchos); NS_ASSUME_NONNULL_END diff --git a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift index 7a0c39340ae..55780c1ca89 100644 --- a/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift +++ b/FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift @@ -99,9 +99,7 @@ final class AuthBackend: AuthBackendProtocol { } private static func generateMFAError(response: AuthRPCResponse, auth: Auth) -> Error? { - #if !os(iOS) - return nil - #else + #if os(iOS) || os(macOS) if let mfaResponse = response as? AuthMFAResponse, mfaResponse.idToken == nil, let enrollments = mfaResponse.mfaInfo { @@ -124,7 +122,9 @@ final class AuthBackend: AuthBackendProtocol { } else { return nil } - #endif // !os(iOS) + #else + return nil + #endif // os(iOS) || os(macOS) } // Check whether or not the successful response is actually the special case phone diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift index 17ec6b18731..e227117c981 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactor.swift @@ -14,7 +14,7 @@ import Foundation -#if os(iOS) +#if os(iOS) || os(macOS) @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) extension MultiFactor: NSSecureCoding {} @@ -22,7 +22,7 @@ import Foundation /// The interface defining the multi factor related properties and operations pertaining to a /// user. /// - /// This class is available on iOS only. + /// This class is available on iOS and macOS. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) @objc(FIRMultiFactor) open class MultiFactor: NSObject { @objc open var enrolledFactors: [MultiFactorInfo] diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorAssertion.swift b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorAssertion.swift index ff3edc94dd0..edfad7aaa58 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorAssertion.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorAssertion.swift @@ -14,12 +14,12 @@ import Foundation -#if os(iOS) +#if os(iOS) || os(macOS) /// The base class for asserting ownership of a second factor. This is equivalent to the /// AuthCredential class. /// - /// This class is available on iOS only. + /// This class is available on iOS and macOS. @objc(FIRMultiFactorAssertion) open class MultiFactorAssertion: NSObject { /// The second factor identifier for this opaque object asserting a second factor. @objc open var factorID: String diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorInfo.swift b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorInfo.swift index 839e405fc05..a1b134a7265 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorInfo.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorInfo.swift @@ -16,12 +16,12 @@ import Foundation // TODO(Swift 6 Breaking): Make checked Sendable. -#if os(iOS) +#if os(iOS) || os(macOS) extension MultiFactorInfo: NSSecureCoding {} /// Safe public structure used to represent a second factor entity from a client perspective. /// - /// This class is available on iOS only. + /// This class is available on iOS and macOS. @objc(FIRMultiFactorInfo) open class MultiFactorInfo: NSObject, @unchecked Sendable { /// The multi-factor enrollment ID. @objc(UID) public let uid: String diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorResolver.swift b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorResolver.swift index 223c1f9f5f5..374f86de88c 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorResolver.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorResolver.swift @@ -14,12 +14,12 @@ import Foundation -#if os(iOS) +#if os(iOS) || os(macOS) /// The subclass of base class `MultiFactorAssertion`, used to assert ownership of a phone /// second factor. /// - /// This class is available on iOS only. + /// This class is available on iOS and macOS. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) @objc(FIRMultiFactorResolver) open class MultiFactorResolver: NSObject { diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorSession.swift b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorSession.swift index 33f7ef927ce..d22578a291a 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorSession.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/MultiFactorSession.swift @@ -14,7 +14,7 @@ import Foundation -#if os(iOS) +#if os(iOS) || os(macOS) /// Opaque object that identifies the current session to enroll a second factor or to /// complete sign in when previously enrolled. @@ -23,7 +23,7 @@ import Foundation /// or to complete sign in when previously enrolled. It contains additional context on the /// existing user, notably the confirmation that the user passed the first factor challenge. /// - /// This class is available on iOS only. + /// This class is available on iOS and macOS. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) @objc(FIRMultiFactorSession) open class MultiFactorSession: NSObject { /// The ID token for an enroll flow. This has to be retrieved after recent authentication. diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/Phone/PhoneMultiFactorAssertion.swift b/FirebaseAuth/Sources/Swift/MultiFactor/Phone/PhoneMultiFactorAssertion.swift index 999809e4bd3..941b0c244f4 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/Phone/PhoneMultiFactorAssertion.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/Phone/PhoneMultiFactorAssertion.swift @@ -14,12 +14,12 @@ import Foundation -#if os(iOS) +#if os(iOS) || os(macOS) /// The subclass of base class FIRMultiFactorAssertion, used to assert ownership of a phone /// second factor. /// - /// This class is available on iOS only. + /// This class is available on iOS and macOS. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) @objc(FIRPhoneMultiFactorAssertion) open class PhoneMultiFactorAssertion: MultiFactorAssertion { var authCredential: PhoneAuthCredential? diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/Phone/PhoneMultiFactorGenerator.swift b/FirebaseAuth/Sources/Swift/MultiFactor/Phone/PhoneMultiFactorGenerator.swift index cd213c14196..74c50abfb96 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/Phone/PhoneMultiFactorGenerator.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/Phone/PhoneMultiFactorGenerator.swift @@ -14,14 +14,14 @@ import Foundation -#if os(iOS) +#if os(iOS) || os(macOS) /// The data structure used to help initialize an assertion for a second factor entity to the /// Firebase Auth/CICP server. /// /// Depending on the type of second factor, this will help generate the assertion. /// - /// This class is available on iOS only. + /// This class is available on iOS and macOS. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) @objc(FIRPhoneMultiFactorGenerator) open class PhoneMultiFactorGenerator: NSObject { diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/Phone/PhoneMultiFactorInfo.swift b/FirebaseAuth/Sources/Swift/MultiFactor/Phone/PhoneMultiFactorInfo.swift index b847407c48a..4ec36505dac 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/Phone/PhoneMultiFactorInfo.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/Phone/PhoneMultiFactorInfo.swift @@ -16,13 +16,13 @@ import Foundation // TODO(Swift 6 Breaking): Make checked Sendable. -#if os(iOS) +#if os(iOS) || os(macOS) /// Extends the MultiFactorInfo class for phone number second factors. /// /// The identifier of this second factor is "phone". /// - /// This class is available on iOS only. + /// This class is available on iOS and macOS. @objc(FIRPhoneMultiFactorInfo) open class PhoneMultiFactorInfo: MultiFactorInfo, @unchecked Sendable { /// The string identifier for using phone as a second factor. diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultFactorAssertion.swift b/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultFactorAssertion.swift index b5b1c43f3d6..dd64e4319af 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultFactorAssertion.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultFactorAssertion.swift @@ -14,7 +14,7 @@ import Foundation -#if os(iOS) +#if os(iOS) || os(macOS) enum SecretOrID { case secret(TOTPSecret) @@ -24,7 +24,7 @@ import Foundation /// The subclass of base class MultiFactorAssertion, used to assert ownership of a TOTP /// (Time-based One Time Password) second factor. /// - /// This class is available on iOS only. + /// This class is available on iOS and macOS. @objc(FIRTOTPMultiFactorAssertion) open class TOTPMultiFactorAssertion: MultiFactorAssertion { let oneTimePassword: String let secretOrID: SecretOrID diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultiFactorGenerator.swift b/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultiFactorGenerator.swift index bf3b07634ca..c24dedb3b22 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultiFactorGenerator.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultiFactorGenerator.swift @@ -14,13 +14,13 @@ import Foundation -#if os(iOS) +#if os(iOS) || os(macOS) /// The data structure used to help initialize an assertion for a second factor entity to the /// Firebase Auth/CICP server. Depending on the type of second factor, this will help generate /// the assertion. /// - /// This class is available on iOS only. + /// This class is available on iOS and macOS. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) @objc(FIRTOTPMultiFactorGenerator) open class TOTPMultiFactorGenerator: NSObject { /// Creates a TOTP secret as part of enrolling a TOTP second factor. Used for generating a diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultiFactorInfo.swift b/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultiFactorInfo.swift index dbb2eeb7042..b252f4fd8c6 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultiFactorInfo.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPMultiFactorInfo.swift @@ -17,13 +17,13 @@ import Foundation // TODO(Swift 6 Breaking): Make checked Sendable. Also, does this need // to be public? -#if os(iOS) +#if os(iOS) || os(macOS) /// Extends the MultiFactorInfo class for time based one-time password second factors. /// /// The identifier of this second factor is "totp". /// - /// This class is available on iOS only. + /// This class is available on iOS and macOS. class TOTPMultiFactorInfo: MultiFactorInfo, @unchecked Sendable { /// Initialize the AuthProtoMFAEnrollment instance with proto. /// - Parameter proto: AuthProtoMFAEnrollment proto object. diff --git a/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPSecret.swift b/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPSecret.swift index b9f1d913920..1f4b3f9e125 100644 --- a/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPSecret.swift +++ b/FirebaseAuth/Sources/Swift/MultiFactor/TOTP/TOTPSecret.swift @@ -19,13 +19,17 @@ import Foundation internal import GoogleUtilities_Environment #endif -#if os(iOS) - import UIKit +#if os(iOS) || os(macOS) + #if os(iOS) + import UIKit + #elseif os(macOS) + import AppKit + #endif /// The subclass of base class MultiFactorAssertion, used to assert ownership of a TOTP /// (Time-based One Time Password) second factor. /// - /// This class is available on iOS only. + /// This class is available on iOS and macOS. @objc(FIRTOTPSecret) open class TOTPSecret: NSObject { /// Returns the shared secret key/seed used to generate time-based one-time passwords. @objc open func sharedSecretKey() -> String { @@ -57,24 +61,33 @@ import Foundation @MainActor @objc(openInOTPAppWithQRCodeURL:) open func openInOTPApp(withQRCodeURL qrCodeURL: String) { if GULAppEnvironmentUtil.isAppExtension() { - // iOS App extensions should not call [UIApplication sharedApplication], even if - // UIApplication responds to it. + // App extensions should not call [UIApplication sharedApplication] or [NSWorkspace + // sharedWorkspace], even if they respond to it. return } - // Using reflection here to avoid build errors in extensions. - let sel = NSSelectorFromString("sharedApplication") - guard UIApplication.responds(to: sel), - let rawApplication = UIApplication.perform(sel), - let application = rawApplication.takeUnretainedValue() as? UIApplication else { - return - } - if let url = URL(string: qrCodeURL), application.canOpenURL(url) { - application.open(url, options: [:], completionHandler: nil) - } else { - AuthLog.logError(code: "I-AUT000019", - message: "URL: \(qrCodeURL) cannot be opened") - } + #if os(iOS) + // Using reflection here to avoid build errors in extensions. + let sel = NSSelectorFromString("sharedApplication") + guard UIApplication.responds(to: sel), + let rawApplication = UIApplication.perform(sel), + let application = rawApplication.takeUnretainedValue() as? UIApplication else { + return + } + if let url = URL(string: qrCodeURL), application.canOpenURL(url) { + application.open(url, options: [:], completionHandler: nil) + } else { + AuthLog.logError(code: "I-AUT000019", + message: "URL: \(qrCodeURL) cannot be opened") + } + #elseif os(macOS) + if let url = URL(string: qrCodeURL) { + NSWorkspace.shared.open(url) + } else { + AuthLog.logError(code: "I-AUT000019", + message: "URL: \(qrCodeURL) cannot be opened") + } + #endif } /// Shared secret key/seed used for enrolling in TOTP MFA and generating OTPs. diff --git a/FirebaseAuth/Sources/Swift/User/User.swift b/FirebaseAuth/Sources/Swift/User/User.swift index 4ef324e177c..ea006baa418 100644 --- a/FirebaseAuth/Sources/Swift/User/User.swift +++ b/FirebaseAuth/Sources/Swift/User/User.swift @@ -58,10 +58,10 @@ extension User: NSSecureCoding {} /// The tenant ID of the current user. `nil` if none is available. @objc public private(set) var tenantID: String? - #if os(iOS) + #if os(iOS) || os(macOS) /// Multi factor object associated with the user. /// - /// This property is available on iOS only. + /// This property is available on iOS and macOS. @objc public private(set) var multiFactor: MultiFactor #endif @@ -1066,7 +1066,7 @@ extension User: NSSecureCoding {} isEmailVerified = false metadata = UserMetadata(withCreationDate: nil, lastSignInDate: nil) tenantID = nil - #if os(iOS) + #if os(iOS) || os(macOS) multiFactor = MultiFactor(withMFAEnrollments: []) #endif uid = "" @@ -1297,7 +1297,7 @@ extension User: NSSecureCoding {} } } providerDataRaw = providerData - #if os(iOS) + #if os(iOS) || os(macOS) if let enrollments = user.mfaEnrollments { multiFactor = MultiFactor(withMFAEnrollments: enrollments) } @@ -1718,7 +1718,7 @@ extension User: NSSecureCoding {} coder.encode(auth.requestConfiguration.appID, forKey: kFirebaseAppIDCodingKey) } coder.encode(tokenService, forKey: kTokenServiceCodingKey) - #if os(iOS) + #if os(iOS) || os(macOS) coder.encode(multiFactor, forKey: kMultiFactorCodingKey) #endif } @@ -1747,7 +1747,7 @@ extension User: NSSecureCoding {} as? [String: UserInfoImpl] let metadata = coder.decodeObject(of: UserMetadata.self, forKey: kMetadataCodingKey) let tenantID = coder.decodeObject(of: NSString.self, forKey: kTenantIDCodingKey) as? String - #if os(iOS) + #if os(iOS) || os(macOS) let multiFactor = coder.decodeObject(of: MultiFactor.self, forKey: kMultiFactorCodingKey) #endif self.tokenService = tokenService @@ -1778,7 +1778,7 @@ extension User: NSSecureCoding {} backend = AuthBackend(rpcIssuer: AuthBackendRPCIssuer()) userProfileUpdate = UserProfileUpdate() - #if os(iOS) + #if os(iOS) || os(macOS) self.multiFactor = multiFactor ?? MultiFactor() super.init() multiFactor?.user = self diff --git a/FirebaseAuth/Sources/Swift/Utilities/AuthErrorUtils.swift b/FirebaseAuth/Sources/Swift/Utilities/AuthErrorUtils.swift index 5c78b223ab4..17d76c810a7 100644 --- a/FirebaseAuth/Sources/Swift/Utilities/AuthErrorUtils.swift +++ b/FirebaseAuth/Sources/Swift/Utilities/AuthErrorUtils.swift @@ -568,7 +568,7 @@ class AuthErrorUtils { return error(code: .blockingCloudFunctionError, message: errorMessage) } - #if os(iOS) + #if os(iOS) || os(macOS) static func secondFactorRequiredError(pendingCredential: String?, hints: [MultiFactorInfo], auth: Auth) @@ -581,7 +581,7 @@ class AuthErrorUtils { return error(code: .secondFactorRequired, userInfo: userInfo) } - #endif // os(iOS) + #endif // os(iOS) || os(macOS) static func recaptchaSDKNotLinkedError() -> Error { // TODO(ObjC): point the link to GCIP doc once available. diff --git a/FirebaseAuth/Tests/Unit/ObjCAPITests.m b/FirebaseAuth/Tests/Unit/ObjCAPITests.m index 6784beb8548..d6a528d8930 100644 --- a/FirebaseAuth/Tests/Unit/ObjCAPITests.m +++ b/FirebaseAuth/Tests/Unit/ObjCAPITests.m @@ -372,7 +372,7 @@ - (void)FIRGoogleAuthProvider_h { accessToken:@"token"]; } -#if TARGET_OS_IOS +#if TARGET_OS_IOS || TARGET_OS_OSX - (void)FIRMultiFactor_h:(FIRMultiFactor *)mf mfa:(FIRMultiFactorAssertion *)mfa { [mf getSessionWithCompletion:^(FIRMultiFactorSession *_Nullable credential, NSError *_Nullable error){ @@ -466,7 +466,9 @@ - (void)FIRPhoneAuthProvider_h:(FIRPhoneAuthCredential *)credential { - (void)phoneMultiFactorInfo:(FIRPhoneMultiFactorInfo *)info { __unused NSString *s = [info phoneNumber]; } +#endif +#if TARGET_OS_IOS || TARGET_OS_OSX - (void)FIRTOTPSecret_h:(FIRTOTPSecret *)secret { NSString *s = [secret sharedSecretKey]; s = [secret generateQRCodeURLWithAccountName:@"name" issuer:@"issuer"]; @@ -571,7 +573,7 @@ - (void)userProperties:(FIRUser *)user { b = [user isEmailVerified]; __unused NSArray *> *userInfo = [user providerData]; __unused FIRUserMetadata *meta = [user metadata]; -#if TARGET_OS_IOS +#if TARGET_OS_IOS || TARGET_OS_OSX __unused FIRMultiFactor *mf = [user multiFactor]; #endif NSString *s = [user refreshToken]; diff --git a/FirebaseAuth/Tests/Unit/ObjCGlobalTests.m b/FirebaseAuth/Tests/Unit/ObjCGlobalTests.m index 59fe0718b5e..62ab96666c5 100644 --- a/FirebaseAuth/Tests/Unit/ObjCGlobalTests.m +++ b/FirebaseAuth/Tests/Unit/ObjCGlobalTests.m @@ -41,9 +41,11 @@ - (void)GlobalSymbolBuildTest { s = FIRGoogleAuthSignInMethod; #if TARGET_OS_IOS s = FIRPhoneMultiFactorID; - s = FIRTOTPMultiFactorID; s = FIRPhoneAuthProviderID; s = FIRPhoneAuthSignInMethod; +#endif +#if TARGET_OS_IOS || TARGET_OS_OSX + s = FIRTOTPMultiFactorID; #endif s = FIRTwitterAuthProviderID; s = FIRTwitterAuthSignInMethod; diff --git a/FirebaseAuth/Tests/Unit/SwiftAPI.swift b/FirebaseAuth/Tests/Unit/SwiftAPI.swift index db002ccd599..fc6c2f466da 100644 --- a/FirebaseAuth/Tests/Unit/SwiftAPI.swift +++ b/FirebaseAuth/Tests/Unit/SwiftAPI.swift @@ -548,7 +548,9 @@ class AuthAPI_hOnlyTests: XCTestCase { func phoneMultiFactorInfo(mfi: PhoneMultiFactorInfo) { let _: String = mfi.phoneNumber } + #endif + #if os(iOS) || os(macOS) func FIRTOTPSecret_h(session: MultiFactorSession) async throws { let obj = try await TOTPMultiFactorGenerator.generateSecret(with: session) _ = obj.sharedSecretKey() @@ -638,7 +640,7 @@ class AuthAPI_hOnlyTests: XCTestCase { let _: Bool = user.isEmailVerified let _: [UserInfo] = user.providerData let _: UserMetadata = user.metadata - #if os(iOS) + #if os(iOS) || os(macOS) let _: MultiFactor = user.multiFactor #endif if let _: String = user.refreshToken, diff --git a/FirebaseAuth/Tests/Unit/SwiftGlobalTests.swift b/FirebaseAuth/Tests/Unit/SwiftGlobalTests.swift index f0956d54aa3..8d863cb1a58 100644 --- a/FirebaseAuth/Tests/Unit/SwiftGlobalTests.swift +++ b/FirebaseAuth/Tests/Unit/SwiftGlobalTests.swift @@ -38,9 +38,10 @@ class SwiftGlobalTests: XCTestCase { let _: String = GitHubAuthSignInMethod let _: String = GoogleAuthProviderID let _: String = GoogleAuthSignInMethod - #if os(iOS) - let _: String = PhoneMultiFactorID + #if os(iOS) || os(macOS) let _: String = TOTPMultiFactorID + #endif + #if os(iOS) let _: String = PhoneAuthProviderID let _: String = PhoneAuthSignInMethod #endif diff --git a/FirebaseAuth/Tests/Unit/UserTests.swift b/FirebaseAuth/Tests/Unit/UserTests.swift index c610e04a0bc..24f426d1bd8 100644 --- a/FirebaseAuth/Tests/Unit/UserTests.swift +++ b/FirebaseAuth/Tests/Unit/UserTests.swift @@ -135,6 +135,27 @@ class UserTests: RPCBaseTests { ]) #endif + var mfaInfo: [[AnyHashable: AnyHashable]] = [] + + #if os(iOS) + mfaInfo.append([ + "phoneInfo": kPhoneInfo, + "mfaEnrollmentId": kEnrollmentID, + "displayName": kDisplayName, + "enrolledAt": kEnrolledAt, + ]) + #endif + + #if os(iOS) || os(macOS) + mfaInfo.append([ + // In practice, this will be an empty dictionary. + "totpInfo": [AnyHashable: AnyHashable](), + "mfaEnrollmentId": kEnrollmentID, + "displayName": kDisplayName, + "enrolledAt": kEnrolledAt, + ]) + #endif + rpcIssuer?.fakeGetAccountProviderJSON = [[ kProviderUserInfoKey: providerUserInfos, kLocalIDKey: kLocalID, @@ -146,21 +167,7 @@ class UserTests: RPCBaseTests { "phoneNumber": kPhoneNumber, "createdAt": String(Int(kCreationDateTimeIntervalInSeconds) * 1000), // to nanoseconds "lastLoginAt": String(Int(kLastSignInDateTimeIntervalInSeconds) * 1000), - "mfaInfo": [ - [ - "phoneInfo": kPhoneInfo, - "mfaEnrollmentId": kEnrollmentID, - "displayName": kDisplayName, - "enrolledAt": kEnrolledAt, - ], - [ - // In practice, this will be an empty dictionary. - "totpInfo": [AnyHashable: AnyHashable](), - "mfaEnrollmentId": kEnrollmentID, - "displayName": kDisplayName, - "enrolledAt": kEnrolledAt, - ] as [AnyHashable: AnyHashable], - ], + "mfaInfo": mfaInfo, ]] let expectation = self.expectation(description: #function) @@ -247,9 +254,12 @@ class UserTests: RPCBaseTests { var encodedClasses = [User.self, NSDictionary.self, NSURL.self, SecureTokenService.self, UserInfoImpl.self, NSDate.self, UserMetadata.self, NSString.self, NSArray.self] - #if os(iOS) + #if os(iOS) || os(macOS) encodedClasses.append(MultiFactor.self) - encodedClasses.append(PhoneMultiFactorInfo.self) + encodedClasses.append(TOTPMultiFactorInfo.self) + #if os(iOS) + encodedClasses.append(PhoneMultiFactorInfo.self) + #endif #endif let unarchivedUser = try XCTUnwrap(NSKeyedUnarchiver.unarchivedObject( @@ -370,6 +380,17 @@ class UserTests: RPCBaseTests { XCTAssertEqual("\(date)", kEnrolledAtMatch) } #endif + + #if os(macOS) + // Verify TOTP MultiFactorInfo properties. + let enrolledFactors = try XCTUnwrap(user.multiFactor.enrolledFactors) + XCTAssertEqual(enrolledFactors.count, 1) + XCTAssertEqual(enrolledFactors[0].factorID, PhoneMultiFactorInfo.TOTPMultiFactorID) + XCTAssertEqual(enrolledFactors[0].uid, kEnrollmentID) + XCTAssertEqual(enrolledFactors[0].displayName, self.kDisplayName) + let date = try XCTUnwrap(enrolledFactors[0].enrollmentDate) + XCTAssertEqual("\(date)", kEnrolledAtMatch) + #endif } catch { XCTFail("Caught an error in \(#function): \(error)") } diff --git a/FirebaseCombineSwift/Sources/Auth/MultiFactor+Combine.swift b/FirebaseCombineSwift/Sources/Auth/MultiFactor+Combine.swift index 4fd850da1e6..b7f8a790dff 100644 --- a/FirebaseCombineSwift/Sources/Auth/MultiFactor+Combine.swift +++ b/FirebaseCombineSwift/Sources/Auth/MultiFactor+Combine.swift @@ -12,13 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#if os(iOS) || targetEnvironment(macCatalyst) +#if os(iOS) || targetEnvironment(macCatalyst) || os(macOS) import Combine import FirebaseAuth - @available(iOS 13.0, macCatalyst 13.0, *) - @available(macOS, unavailable) + @available(iOS 13.0, macCatalyst 13.0, macOS 10.15, *) @available(tvOS, unavailable) @available(watchOS, unavailable) public extension MultiFactor { @@ -111,4 +110,4 @@ } } -#endif // os(iOS) || targetEnvironment(macCatalyst) +#endif // os(iOS) || targetEnvironment(macCatalyst) || os(macOS) diff --git a/FirebaseCombineSwift/Sources/Auth/MultiFactorResolver+Combine.swift b/FirebaseCombineSwift/Sources/Auth/MultiFactorResolver+Combine.swift index b2ada743c66..a94e3b7cd82 100644 --- a/FirebaseCombineSwift/Sources/Auth/MultiFactorResolver+Combine.swift +++ b/FirebaseCombineSwift/Sources/Auth/MultiFactorResolver+Combine.swift @@ -12,13 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#if os(iOS) || targetEnvironment(macCatalyst) +#if os(iOS) || targetEnvironment(macCatalyst) || os(macOS) import Combine import FirebaseAuth - @available(iOS 13.0, macCatalyst 13.0, *) - @available(macOS, unavailable) + @available(iOS 13.0, macCatalyst 13.0, macOS 10.15, *) @available(tvOS, unavailable) @available(watchOS, unavailable) public extension MultiFactorResolver { @@ -43,4 +42,4 @@ } } -#endif // os(iOS) || targetEnvironment(macCatalyst) +#endif // os(iOS) || targetEnvironment(macCatalyst) || os(macOS) From 4beb3304e55a9f1f8065e50cacc4056f4b21e4a0 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 12 Aug 2025 16:27:22 -0400 Subject: [PATCH 25/76] [Infra] Update release tooling minimum versions (#15188) --- ReleaseTooling/Sources/ZipBuilder/main.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReleaseTooling/Sources/ZipBuilder/main.swift b/ReleaseTooling/Sources/ZipBuilder/main.swift index 4a56842b425..cc19e3fafe6 100644 --- a/ReleaseTooling/Sources/ZipBuilder/main.swift +++ b/ReleaseTooling/Sources/ZipBuilder/main.swift @@ -100,7 +100,7 @@ struct ZipBuilderTool: ParsableCommand { // MARK: - Platform Arguments /// The minimum iOS Version to build for. - @Option(default: "12.0", help: ArgumentHelp("The minimum supported iOS version.")) + @Option(default: "15.0", help: ArgumentHelp("The minimum supported iOS version.")) var minimumIOSVersion: String /// The minimum macOS Version to build for. @@ -108,7 +108,7 @@ struct ZipBuilderTool: ParsableCommand { var minimumMacOSVersion: String /// The minimum tvOS Version to build for. - @Option(default: "13.0", help: ArgumentHelp("The minimum supported tvOS version.")) + @Option(default: "15.0", help: ArgumentHelp("The minimum supported tvOS version.")) var minimumTVOSVersion: String /// The minimum watchOS Version to build for. From d4d341d6df49747229411af982d2e2439b7c2479 Mon Sep 17 00:00:00 2001 From: pcfba <111909874+pcfba@users.noreply.github.com> Date: Thu, 14 Aug 2025 11:25:05 -0700 Subject: [PATCH 26/76] Add Mac Catalyst disable instructions for GoogleAdsOnDeviceConversion (#15198) --- ReleaseTooling/Template/README.md | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/ReleaseTooling/Template/README.md b/ReleaseTooling/Template/README.md index 2b02fa7177a..2c97c76f470 100644 --- a/ReleaseTooling/Template/README.md +++ b/ReleaseTooling/Template/README.md @@ -67,13 +67,26 @@ To integrate a Firebase SDK with your app: c. Double-click the setting, click the '+' button, and add `-lc++` -10. Drag the `Firebase.h` header in this directory into your project. This will +10. If you're using Firebase Analytics, disable + GoogleAdsOnDeviceConversion.xcframework for Mac Catalyst: + + a. In your project settings, open the **Settings** panel for your target. + + b. Go to the Build Phases tab and find the + **GoogleAdsOnDeviceConversion.xcframework** setting in the **Link Binary + With Libraries** section. + + c. Click on the filter icon button in the + **GoogleAdsOnDeviceConversion.xcframework** row and deselect the Mac Catalyst + checkbox. + +11. Drag the `Firebase.h` header in this directory into your project. This will allow you to `#import "Firebase.h"` and start using any Firebase SDK that you have. -11. Drag `module.modulemap` into your project and update the +12. Drag `module.modulemap` into your project and update the "User Header Search Paths" in your project's Build Settings to include the directory that contains the added module map. -12. If your app does not include any Swift implementation, you may need to add +13. If your app does not include any Swift implementation, you may need to add a dummy Swift file to the app to prevent Swift system library missing symbol linker errors. See https://forums.swift.org/t/using-binary-swift-sdks-from-non-swift-apps/55989. @@ -81,7 +94,7 @@ To integrate a Firebase SDK with your app: > ⚠ If prompted with the option to create a corresponding bridging header > for the new Swift file, select **Don't create**. -13. You're done! Build your target and start using Firebase. +14. You're done! Build your target and start using Firebase. If you want to add another SDK, repeat the steps above with the xcframeworks for the new SDK. You only need to add each framework once, so if you've already From 69ad8a4db3332d8c234c7e77ad354955e32c13d1 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Sun, 17 Aug 2025 21:40:21 -0400 Subject: [PATCH 27/76] [CI] Run all `macos-15` jobs with Xcode 16.4 (#15200) Co-authored-by: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Co-authored-by: Nick Cooke --- .github/workflows/abtesting.yml | 6 ++-- .github/workflows/client_app.yml | 28 ++++++++++----- .github/workflows/common.yml | 6 +--- .github/workflows/common_catalyst.yml | 2 +- .github/workflows/core_extension.yml | 2 +- .github/workflows/core_internal.yml | 2 +- .github/workflows/crashlytics.yml | 6 ++-- .github/workflows/database.yml | 4 +-- .github/workflows/firebase_app_check.yml | 4 +-- .github/workflows/firebasepod.yml | 2 +- .github/workflows/firestore.yml | 5 ++- .github/workflows/inappmessaging.yml | 6 ++-- .github/workflows/installations.yml | 6 ++-- .github/workflows/messaging.yml | 12 +++---- .github/workflows/mlmodeldownloader.yml | 4 +-- .github/workflows/performance.yml | 8 ++--- .github/workflows/prerelease.yml | 2 +- .github/workflows/release.yml | 2 +- .../workflows/sessions-integration-tests.yml | 2 +- .github/workflows/spm.yml | 4 +-- .github/workflows/storage.yml | 4 +-- .github/workflows/zip.yml | 36 ++++++++----------- scripts/build.sh | 21 +++++------ 23 files changed, 87 insertions(+), 87 deletions(-) diff --git a/.github/workflows/abtesting.yml b/.github/workflows/abtesting.yml index a8701041b72..a52070bdf10 100644 --- a/.github/workflows/abtesting.yml +++ b/.github/workflows/abtesting.yml @@ -51,7 +51,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup quickstart env: LEGACY: true @@ -86,7 +86,7 @@ jobs: run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-abtesting.plist.gpg \ quickstart-ios/abtesting/GoogleService-Info.plist "$plist_secret" - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Build swift quickstart env: LEGACY: true @@ -116,7 +116,7 @@ jobs: - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: PodLibLint ABTesting Cron run: | scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb \ diff --git a/.github/workflows/client_app.yml b/.github/workflows/client_app.yml index 150d879edca..8c4f72c4c27 100644 --- a/.github/workflows/client_app.yml +++ b/.github/workflows/client_app.yml @@ -27,12 +27,16 @@ jobs: client-app-spm: if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' strategy: - # TODO: Add Xcode matrix when Xcode 16 is ubiquitous on CI runners. matrix: #TODO(ncooke3): Add multi-platform support: tvOS, macOS, catalyst platform: [iOS] scheme: [ClientApp] os: [macos-14, macos-15] + include: + - os: macos-14 + xcode: Xcode_16.2 + - os: macos-15 + xcode: Xcode_16.4 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -40,8 +44,8 @@ jobs: with: cache_key: ${{ matrix.os }} - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer - - name: Build Client App –– ${{ matrix.platform }} + run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + - name: Build Client App - ${{ matrix.platform }} run: scripts/third_party/travis/retry.sh ./scripts/build.sh ${{ matrix.scheme }} ${{ matrix.platform }} xcodebuild client-app-spm-source-firestore: @@ -50,12 +54,16 @@ jobs: FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1 FIREBASE_SOURCE_FIRESTORE: 1 strategy: - # TODO: Add Xcode matrix when Xcode 16 is ubiquitous on CI runners. matrix: #TODO(ncooke3): Add multi-platform support: tvOS, macOS, catalyst platform: [iOS] scheme: [ClientApp] os: [macos-14, macos-15] + include: + - os: macos-14 + xcode: Xcode_16.2 + - os: macos-15 + xcode: Xcode_16.4 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -63,18 +71,22 @@ jobs: with: cache_key: ${{ matrix.os }} - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer - - name: Build Client App –– ${{ matrix.platform }} + run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer + - name: Build Client App - ${{ matrix.platform }} run: scripts/third_party/travis/retry.sh ./scripts/build.sh ${{ matrix.scheme }} ${{ matrix.platform }} xcodebuild client-app-cocoapods: # Don't run on private repo unless it is a PR. if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' strategy: - # TODO: Add Xcode matrix when Xcode 16 is ubiquitous on CI runners. matrix: scheme: [ClientApp-CocoaPods] os: [macos-14, macos-15] + include: + - os: macos-14 + xcode: Xcode_16.2 + - os: macos-15 + xcode: Xcode_16.4 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -85,7 +97,7 @@ jobs: - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - name: Prereqs run: scripts/install_prereqs.sh ClientApp iOS xcodebuild - name: Build diff --git a/.github/workflows/common.yml b/.github/workflows/common.yml index 1a82d76b36f..b79680f09b4 100644 --- a/.github/workflows/common.yml +++ b/.github/workflows/common.yml @@ -67,7 +67,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Generate Swift Package.resolved id: swift_package_resolve run: swift package resolve @@ -104,10 +104,6 @@ jobs: key: ${{needs.spm-package-resolved.outputs.cache_key}} - name: Xcode run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - - name: Install visionOS, if needed. - if: matrix.platform == 'visionOS' - run: ls $(xcode-select -p)/Platforms/XROS.platform || \ - { xcodebuild -downloadPlatform visionOS } - name: Run setup command, if needed. if: inputs.setup_command != '' run: ${{ inputs.setup_command }} diff --git a/.github/workflows/common_catalyst.yml b/.github/workflows/common_catalyst.yml index 6948e4e3197..da3911b064c 100644 --- a/.github/workflows/common_catalyst.yml +++ b/.github/workflows/common_catalyst.yml @@ -38,7 +38,7 @@ jobs: - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: timeout_minutes: 120 diff --git a/.github/workflows/core_extension.yml b/.github/workflows/core_extension.yml index 15b86f38538..cc9d602f15d 100644 --- a/.github/workflows/core_extension.yml +++ b/.github/workflows/core_extension.yml @@ -39,7 +39,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: PodLibLint CoreInternal Cron diff --git a/.github/workflows/core_internal.yml b/.github/workflows/core_internal.yml index d1b8dd6cf73..db3d565f69f 100644 --- a/.github/workflows/core_internal.yml +++ b/.github/workflows/core_internal.yml @@ -54,7 +54,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: PodLibLint CoreInternal Cron diff --git a/.github/workflows/crashlytics.yml b/.github/workflows/crashlytics.yml index a32d474a61b..0f5f2cb5643 100644 --- a/.github/workflows/crashlytics.yml +++ b/.github/workflows/crashlytics.yml @@ -53,7 +53,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup quickstart run: scripts/setup_quickstart.sh crashlytics env: @@ -86,7 +86,7 @@ jobs: with: python-version: '3.11' - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup quickstart run: scripts/setup_quickstart.sh crashlytics env: @@ -130,7 +130,7 @@ jobs: - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: timeout_minutes: 120 diff --git a/.github/workflows/database.yml b/.github/workflows/database.yml index 928c3bf28ad..24998fa0deb 100644 --- a/.github/workflows/database.yml +++ b/.github/workflows/database.yml @@ -84,7 +84,7 @@ jobs: run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-database.plist.gpg \ quickstart-ios/database/GoogleService-Info.plist "$plist_secret" - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Test objc quickstart run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Database false) - name: Test swift quickstart @@ -106,7 +106,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: PodLibLint database Cron diff --git a/.github/workflows/firebase_app_check.yml b/.github/workflows/firebase_app_check.yml index ff30db15a66..cd9f8eac577 100644 --- a/.github/workflows/firebase_app_check.yml +++ b/.github/workflows/firebase_app_check.yml @@ -58,7 +58,7 @@ jobs: with: cache_key: ${{ matrix.diagnostics }} - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Initialize xcodebuild run: scripts/setup_spm_tests.sh - name: iOS Unit Tests @@ -84,7 +84,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: PodLibLint FirebaseAppCheck Cron diff --git a/.github/workflows/firebasepod.yml b/.github/workflows/firebasepod.yml index 8f7fd3af5ef..f1e228b7f24 100644 --- a/.github/workflows/firebasepod.yml +++ b/.github/workflows/firebasepod.yml @@ -34,7 +34,7 @@ jobs: - name: Setup Bundler run: scripts/setup_bundler.sh - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Prereqs run: scripts/install_prereqs.sh FirebasePod iOS - name: Build diff --git a/.github/workflows/firestore.yml b/.github/workflows/firestore.yml index 3e927287a2e..d3f61e67b4a 100644 --- a/.github/workflows/firestore.yml +++ b/.github/workflows/firestore.yml @@ -375,6 +375,9 @@ jobs: - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Select Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer + - name: Setup build run: scripts/install_prereqs.sh Firestore ${{ matrix.target }} xcodebuild @@ -578,7 +581,7 @@ jobs: with: cache_key: ${{ matrix.target }} - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Initialize xcodebuild run: scripts/setup_spm_tests.sh - name: Build Test - Binary diff --git a/.github/workflows/inappmessaging.yml b/.github/workflows/inappmessaging.yml index 6650fbb8fc9..feb26e72c65 100644 --- a/.github/workflows/inappmessaging.yml +++ b/.github/workflows/inappmessaging.yml @@ -46,7 +46,7 @@ jobs: # TODO(#8682): Reenable iPad after fixing Xcode 13 test failures. # platform: [iOS, iPad] platform: [iOS] - xcode: [Xcode_16.2] + xcode: [Xcode_16.4] steps: - uses: actions/checkout@v4 - uses: mikehardy/buildcache-action@c87cea0ccd718971d6cc39e672c4f26815b6c126 @@ -78,7 +78,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: PodLibLint InAppMessaging Cron @@ -98,7 +98,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup quickstart run: scripts/setup_quickstart.sh inappmessaging - name: install secret googleservice-info.plist diff --git a/.github/workflows/installations.yml b/.github/workflows/installations.yml index cf4f6795b18..2b149918f0a 100644 --- a/.github/workflows/installations.yml +++ b/.github/workflows/installations.yml @@ -56,7 +56,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup quickstart run: scripts/setup_quickstart.sh installations - name: Copy mock plist @@ -78,7 +78,7 @@ jobs: with: python-version: '3.11' - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup quickstart run: scripts/setup_quickstart.sh installations - name: Copy mock plist @@ -112,7 +112,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: Configure test keychain diff --git a/.github/workflows/messaging.yml b/.github/workflows/messaging.yml index 838ce5fe4d9..db9d8f8ccac 100644 --- a/.github/workflows/messaging.yml +++ b/.github/workflows/messaging.yml @@ -89,7 +89,7 @@ jobs: matrix: include: - os: macos-15 - xcode: Xcode_16.2 + xcode: Xcode_16.4 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -122,7 +122,7 @@ jobs: with: python-version: '3.11' - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup quickstart run: scripts/setup_quickstart.sh messaging - name: Install Secret GoogleService-Info.plist @@ -150,7 +150,7 @@ jobs: os: [macos-14, macos-15] include: - os: macos-15 - xcode: Xcode_16.2 + xcode: Xcode_16.4 tests: --test-specs=unit - os: macos-14 xcode: Xcode_16.2 @@ -187,7 +187,7 @@ jobs: - name: Prereqs run: scripts/install_prereqs.sh MessagingSample iOS - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Build run: ([ -z $plist_secret ] || scripts/build.sh MessagingSample iOS) @@ -212,7 +212,7 @@ jobs: - name: Prereqs run: scripts/install_prereqs.sh SwiftUISample iOS - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Build run: ([ -z $plist_secret ] || scripts/build.sh SwiftUISample iOS) @@ -237,7 +237,7 @@ jobs: - name: Prereqs run: scripts/install_prereqs.sh MessagingSampleStandaloneWatchApp watchOS - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Build run: ([ -z $plist_secret ] || scripts/build.sh MessagingSampleStandaloneWatchApp watchOS) diff --git a/.github/workflows/mlmodeldownloader.yml b/.github/workflows/mlmodeldownloader.yml index 3eddabeadec..931c8edda79 100644 --- a/.github/workflows/mlmodeldownloader.yml +++ b/.github/workflows/mlmodeldownloader.yml @@ -57,7 +57,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: Configure test keychain @@ -83,7 +83,7 @@ jobs: cache_key: build-test${{ matrix.os }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: Install GoogleService-Info.plist diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index b1073dfd11f..61c08473772 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -60,7 +60,7 @@ jobs: cache_key: ${{ matrix.target }}${{ matrix.test }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: Install xcpretty @@ -87,7 +87,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup quickstart run: scripts/setup_quickstart.sh performance - name: Install Secret GoogleService-Info.plist @@ -113,7 +113,7 @@ jobs: with: python-version: '3.11' - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup quickstart run: scripts/setup_quickstart.sh performance - name: Install Secret GoogleService-Info.plist @@ -145,7 +145,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: PodLibLint Performance Cron diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 2cb87713f68..6bdc3749b3f 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -242,7 +242,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh Authentication prerelease_testing - name: Install Secret GoogleService-Info.plist diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index de6631fc6b4..531cc021b2c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -188,7 +188,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh Authentication nightly_release_testing - name: Install Secret GoogleService-Info.plist diff --git a/.github/workflows/sessions-integration-tests.yml b/.github/workflows/sessions-integration-tests.yml index 4d11e4dc065..ccc8d9f15fd 100644 --- a/.github/workflows/sessions-integration-tests.yml +++ b/.github/workflows/sessions-integration-tests.yml @@ -31,7 +31,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - uses: mikehardy/buildcache-action@c87cea0ccd718971d6cc39e672c4f26815b6c126 with: cache_key: sessions-integration-tests diff --git a/.github/workflows/spm.yml b/.github/workflows/spm.yml index 5b807927410..a1227e2ef1c 100644 --- a/.github/workflows/spm.yml +++ b/.github/workflows/spm.yml @@ -98,7 +98,7 @@ jobs: - os: macos-14 xcode: Xcode_16.2 - os: macos-15 - xcode: Xcode_16.2 + xcode: Xcode_16.4 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -127,7 +127,7 @@ jobs: target: [tvOS, macOS, catalyst] include: - os: macos-15 - xcode: Xcode_16.2 + xcode: Xcode_16.4 - os: macos-14 xcode: Xcode_16.2 runs-on: ${{ matrix.os }} diff --git a/.github/workflows/storage.yml b/.github/workflows/storage.yml index 036037b5ca7..740b15c7766 100644 --- a/.github/workflows/storage.yml +++ b/.github/workflows/storage.yml @@ -88,7 +88,7 @@ jobs: # xcode: Xcode_14.2 # TODO: the legacy ObjC quickstart doesn't build with Xcode 15. - swift: swift os: macos-15 - xcode: Xcode_16.2 + xcode: Xcode_16.4 env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} @@ -153,7 +153,7 @@ jobs: - os: macos-14 xcode: Xcode_16.2 - os: macos-15 - xcode: Xcode_16.2 + xcode: Xcode_16.4 runs-on: ${{ matrix.build-env.os }} needs: pod_lib_lint steps: diff --git a/.github/workflows/zip.yml b/.github/workflows/zip.yml index 9879e942885..42a216c1567 100644 --- a/.github/workflows/zip.yml +++ b/.github/workflows/zip.yml @@ -114,9 +114,7 @@ jobs: artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] build-env: - os: macos-15 - xcode: Xcode_16.2 - # - os: macos-15 - # xcode: Xcode_16.4 + xcode: Xcode_16.4 runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 @@ -176,7 +174,7 @@ jobs: artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] include: - os: macos-15 - xcode: Xcode_16.2 + xcode: Xcode_16.4 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -226,9 +224,7 @@ jobs: artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] build-env: - os: macos-15 - xcode: Xcode_16.2 - # - os: macos-15 - # xcode: Xcode_16.4 + xcode: Xcode_16.4 runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 @@ -277,9 +273,7 @@ jobs: artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] build-env: - os: macos-15 - xcode: Xcode_16.2 - # - os: macos-15 - # xcode: Xcode_16.4 + xcode: Xcode_16.4 runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 @@ -403,9 +397,7 @@ jobs: artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] build-env: - os: macos-15 - xcode: Xcode_16.2 - # - os: macos-15 - # xcode: Xcode_16.4 + xcode: Xcode_16.4 runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 @@ -427,6 +419,12 @@ jobs: "${HOME}"/ios_frameworks/Firebase/FirebaseFirestore/* \ "${HOME}"/ios_frameworks/Firebase/FirebaseAuth/* \ "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/* + - name: Upload build logs on failure + if: ${{ failure() }} + uses: actions/upload-artifact@v4 + with: + name: build_logs_firestore_${{ matrix.artifact }}_${{ matrix.build-env.os }} + path: sdk_zip/build_logs/ - name: Xcode run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Install Secret GoogleService-Info.plist @@ -487,9 +485,7 @@ jobs: artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] build-env: - os: macos-15 - xcode: Xcode_16.2 - # - os: macos-15 - # xcode: Xcode_16.4 + xcode: Xcode_16.4 runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 @@ -542,9 +538,7 @@ jobs: artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] build-env: - os: macos-15 - xcode: Xcode_16.2 - # - os: macos-15 - # xcode: Xcode_16.4 + xcode: Xcode_16.4 runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 @@ -597,9 +591,7 @@ jobs: artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic] build-env: - os: macos-15 - xcode: Xcode_16.2 - # - os: macos-15 - # xcode: Xcode_16.4 + xcode: Xcode_16.4 runs-on: ${{ matrix.build-env.os }} steps: - uses: actions/checkout@v4 diff --git a/scripts/build.sh b/scripts/build.sh index 30b84004c3b..2be500a8bbc 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -187,8 +187,11 @@ tvos_flags=( -destination 'platform=tvOS Simulator,name=Apple TV' ) visionos_flags=( + # As of Aug 15, 2025, the default OS "latest" was failing as it matched both + # the visionOS 26 beta and visionOS 2.5 (from Xcode 16.4) simulators; + # explicitly specifying OS=2.5 in destination as a workaround. -sdk 'xrsimulator' - -destination 'platform=visionOS Simulator,name=Apple Vision Pro' + -destination 'platform=visionOS Simulator,OS=2.5,name=Apple Vision Pro' ) catalyst_flags=( ARCHS=x86_64 VALID_ARCHS=x86_64 SUPPORTS_MACCATALYST=YES -sdk macosx @@ -489,12 +492,10 @@ case "$product-$platform-$method" in ../../../FirebaseRemoteConfig/Tests/Swift/AccessToken.json # Integration tests are only run on iOS to minimize flake failures. - # TODO(ncooke3): Remove -sdk and -destination flags and replace with "${xcb_flags[@]}" RunXcodebuild \ -workspace 'gen/FirebaseRemoteConfig/FirebaseRemoteConfig.xcworkspace' \ -scheme "FirebaseRemoteConfig-Unit-swift-api-tests" \ - -sdk 'iphonesimulator' \ - -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.3.1' \ + "${xcb_flags[@]}" \ build \ test ;; @@ -572,12 +573,10 @@ case "$product-$platform-$method" in if check_secrets; then # Integration tests are only run on iOS to minimize flake failures. - # TODO(ncooke3): Add back "${ios_flags[@]}". See #14657. RunXcodebuild \ -workspace 'gen/FirebaseStorage/FirebaseStorage.xcworkspace' \ -scheme "FirebaseStorage-Unit-integration" \ - -sdk 'iphonesimulator' \ - -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.3.1' \ + "${ios_flags[@]}" \ "${xcb_flags[@]}" \ test fi @@ -593,12 +592,10 @@ case "$product-$platform-$method" in if check_secrets; then # Integration tests are only run on iOS to minimize flake failures. - # TODO(ncooke3): Add back "${ios_flags[@]}". See #14657. RunXcodebuild \ -workspace 'gen/FirebaseStorage/FirebaseStorage.xcworkspace' \ -scheme "FirebaseStorage-Unit-ObjCIntegration" \ - -sdk 'iphonesimulator' \ - -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.3.1' \ + "${ios_flags[@]}" \ "${xcb_flags[@]}" \ test fi @@ -617,8 +614,8 @@ case "$product-$platform-$method" in RunXcodebuild \ -workspace 'gen/FirebaseCombineSwift/FirebaseCombineSwift.xcworkspace' \ -scheme "FirebaseCombineSwift-Unit-integration" \ - -sdk 'iphonesimulator' \ - -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.3.1' \ + "${ios_flags[@]}" \ + "${xcb_flags[@]}" \ test fi ;; From 683273b32f12ddd48992a22adfcb41c2b7416fd0 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 18 Aug 2025 11:25:24 -0400 Subject: [PATCH 28/76] [Infra] Update appdistribution.yml (#15214) --- .github/workflows/appdistribution.yml | 38 ++++++++++++++------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/.github/workflows/appdistribution.yml b/.github/workflows/appdistribution.yml index 026e95f81ac..fc7bf7444eb 100644 --- a/.github/workflows/appdistribution.yml +++ b/.github/workflows/appdistribution.yml @@ -22,26 +22,26 @@ concurrency: cancel-in-progress: true jobs: - spm: - uses: ./.github/workflows/common.yml - with: - target: AppDistributionUnit - platforms: iOS - - catalyst: - uses: ./.github/workflows/common_catalyst.yml - with: - product: FirebaseAppDistribution - target: FirebaseAppDistribution-Unit-unit - - pod_lib_lint: - uses: ./.github/workflows/common_cocoapods.yml - with: - product: FirebaseAppDistribution - platforms: iOS # App Distro only supports iOS. + # spm: + # uses: ./.github/workflows/common.yml + # with: + # target: AppDistributionUnit + # platforms: iOS + + # catalyst: + # uses: ./.github/workflows/common_catalyst.yml + # with: + # product: FirebaseAppDistribution + # target: FirebaseAppDistribution-Unit-unit + + # pod_lib_lint: + # uses: ./.github/workflows/common_cocoapods.yml + # with: + # product: FirebaseAppDistribution + # platforms: iOS # App Distro only supports iOS. appdistribution-cron-only: - if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' + # if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' runs-on: macos-15 strategy: @@ -54,6 +54,8 @@ jobs: steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Setup Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: PodLibLint App Distribution Cron From 5caaeea4ae948c1fb10a42b883e0cf25fcb9fe3e Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 18 Aug 2025 11:29:27 -0400 Subject: [PATCH 29/76] Partial Revert "[Infra] Update appdistribution.yml" (#15216) --- .github/workflows/appdistribution.yml | 32 +++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/appdistribution.yml b/.github/workflows/appdistribution.yml index fc7bf7444eb..23a48c746d8 100644 --- a/.github/workflows/appdistribution.yml +++ b/.github/workflows/appdistribution.yml @@ -22,26 +22,26 @@ concurrency: cancel-in-progress: true jobs: - # spm: - # uses: ./.github/workflows/common.yml - # with: - # target: AppDistributionUnit - # platforms: iOS + spm: + uses: ./.github/workflows/common.yml + with: + target: AppDistributionUnit + platforms: iOS - # catalyst: - # uses: ./.github/workflows/common_catalyst.yml - # with: - # product: FirebaseAppDistribution - # target: FirebaseAppDistribution-Unit-unit + catalyst: + uses: ./.github/workflows/common_catalyst.yml + with: + product: FirebaseAppDistribution + target: FirebaseAppDistribution-Unit-unit - # pod_lib_lint: - # uses: ./.github/workflows/common_cocoapods.yml - # with: - # product: FirebaseAppDistribution - # platforms: iOS # App Distro only supports iOS. + pod_lib_lint: + uses: ./.github/workflows/common_cocoapods.yml + with: + product: FirebaseAppDistribution + platforms: iOS # App Distro only supports iOS. appdistribution-cron-only: - # if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' + if: github.event_name == 'schedule' && github.repository == 'Firebase/firebase-ios-sdk' runs-on: macos-15 strategy: From 3a4c3119699f06cc5fa2236784e76af63c4249be Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Mon, 18 Aug 2025 14:15:44 -0400 Subject: [PATCH 30/76] [Firebase AI] Add `includeSafetyAttributes` for Imagen requests (#15191) Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- .github/workflows/firebaseai.yml | 9 ++++++- .../Imagen/ImageGenerationParameters.swift | 3 +++ .../Imagen/ImagenSafetyAttributes.swift | 24 +++++++++++++++++ .../Imagen/ImagenGenerationResponse.swift | 2 ++ .../Types/Public/Imagen/ImagenModel.swift | 3 ++- .../ImageGenerationParametersTests.swift | 26 +++++++++++++------ .../Imagen/ImagenGenerationRequestTests.swift | 6 ++++- 7 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 FirebaseAI/Sources/Types/Internal/Imagen/ImagenSafetyAttributes.swift diff --git a/.github/workflows/firebaseai.yml b/.github/workflows/firebaseai.yml index 7ad2a9dff29..a5303b019a6 100644 --- a/.github/workflows/firebaseai.yml +++ b/.github/workflows/firebaseai.yml @@ -82,10 +82,17 @@ jobs: setup_command: scripts/update_vertexai_responses.sh quickstart: - runs-on: macos-15 + strategy: + matrix: + include: + - os: macos-15 + xcode: Xcode_16.4 + runs-on: ${{ matrix.os }} env: BRANCH_NAME: ${{ github.head_ref || github.ref_name || 'main' }} steps: - uses: actions/checkout@v4 + - name: Xcode + run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - name: Build Quickstart run: scripts/quickstart_build_spm.sh FirebaseAI diff --git a/FirebaseAI/Sources/Types/Internal/Imagen/ImageGenerationParameters.swift b/FirebaseAI/Sources/Types/Internal/Imagen/ImageGenerationParameters.swift index 4189e5fbac7..aa1e1b085c8 100644 --- a/FirebaseAI/Sources/Types/Internal/Imagen/ImageGenerationParameters.swift +++ b/FirebaseAI/Sources/Types/Internal/Imagen/ImageGenerationParameters.swift @@ -23,6 +23,7 @@ struct ImageGenerationParameters { let outputOptions: ImageGenerationOutputOptions? let addWatermark: Bool? let includeResponsibleAIFilterReason: Bool? + let includeSafetyAttributes: Bool? } @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) @@ -42,6 +43,7 @@ extension ImageGenerationParameters: Encodable { case outputOptions case addWatermark case includeResponsibleAIFilterReason = "includeRaiReason" + case includeSafetyAttributes } func encode(to encoder: any Encoder) throws { @@ -58,5 +60,6 @@ extension ImageGenerationParameters: Encodable { includeResponsibleAIFilterReason, forKey: .includeResponsibleAIFilterReason ) + try container.encodeIfPresent(includeSafetyAttributes, forKey: .includeSafetyAttributes) } } diff --git a/FirebaseAI/Sources/Types/Internal/Imagen/ImagenSafetyAttributes.swift b/FirebaseAI/Sources/Types/Internal/Imagen/ImagenSafetyAttributes.swift new file mode 100644 index 00000000000..3dcb93d544a --- /dev/null +++ b/FirebaseAI/Sources/Types/Internal/Imagen/ImagenSafetyAttributes.swift @@ -0,0 +1,24 @@ +// 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. + +import Foundation + +/// A `safetyAttributes` "prediction" from Imagen. +/// +/// This prediction is currently unused by the SDK and is only checked to be valid JSON. This type +/// is currently only used to avoid logging unsupported prediction types. +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +struct ImagenSafetyAttributes: Decodable { + let safetyAttributes: JSONObject +} diff --git a/FirebaseAI/Sources/Types/Public/Imagen/ImagenGenerationResponse.swift b/FirebaseAI/Sources/Types/Public/Imagen/ImagenGenerationResponse.swift index f9816908c6d..9ed52c4d0e9 100644 --- a/FirebaseAI/Sources/Types/Public/Imagen/ImagenGenerationResponse.swift +++ b/FirebaseAI/Sources/Types/Public/Imagen/ImagenGenerationResponse.swift @@ -60,6 +60,8 @@ extension ImagenGenerationResponse: Decodable where T: Decodable { images.append(image) } else if let filteredReason = try? predictionsContainer.decode(RAIFilteredReason.self) { filteredReasons.append(filteredReason.raiFilteredReason) + } else if let _ = try? predictionsContainer.decode(ImagenSafetyAttributes.self) { + // Ignore SafetyAttributes "prediction" to avoid logging in `unsupportedPrediction` below. } else if let unsupportedPrediction = try? predictionsContainer.decode(JSONObject.self) { AILog.warning( code: .decodedUnsupportedImagenPredictionType, diff --git a/FirebaseAI/Sources/Types/Public/Imagen/ImagenModel.swift b/FirebaseAI/Sources/Types/Public/Imagen/ImagenModel.swift index e6f96df511a..729fad9f28d 100644 --- a/FirebaseAI/Sources/Types/Public/Imagen/ImagenModel.swift +++ b/FirebaseAI/Sources/Types/Public/Imagen/ImagenModel.swift @@ -159,7 +159,8 @@ public final class ImagenModel { ) }, addWatermark: generationConfig?.addWatermark, - includeResponsibleAIFilterReason: true + includeResponsibleAIFilterReason: true, + includeSafetyAttributes: true ) } } diff --git a/FirebaseAI/Tests/Unit/Types/Imagen/ImageGenerationParametersTests.swift b/FirebaseAI/Tests/Unit/Types/Imagen/ImageGenerationParametersTests.swift index 494feda9f7a..a96174f3b7d 100644 --- a/FirebaseAI/Tests/Unit/Types/Imagen/ImageGenerationParametersTests.swift +++ b/FirebaseAI/Tests/Unit/Types/Imagen/ImageGenerationParametersTests.swift @@ -34,7 +34,8 @@ final class ImageGenerationParametersTests: XCTestCase { personGeneration: nil, outputOptions: nil, addWatermark: nil, - includeResponsibleAIFilterReason: true + includeResponsibleAIFilterReason: true, + includeSafetyAttributes: true ) let parameters = ImagenModel.imageGenerationParameters( @@ -57,7 +58,8 @@ final class ImageGenerationParametersTests: XCTestCase { personGeneration: nil, outputOptions: nil, addWatermark: nil, - includeResponsibleAIFilterReason: true + includeResponsibleAIFilterReason: true, + includeSafetyAttributes: true ) let parameters = ImagenModel.imageGenerationParameters( @@ -95,7 +97,8 @@ final class ImageGenerationParametersTests: XCTestCase { compressionQuality: imageFormat.compressionQuality ), addWatermark: addWatermark, - includeResponsibleAIFilterReason: true + includeResponsibleAIFilterReason: true, + includeSafetyAttributes: true ) let parameters = ImagenModel.imageGenerationParameters( @@ -124,7 +127,8 @@ final class ImageGenerationParametersTests: XCTestCase { personGeneration: personFilterLevel.rawValue, outputOptions: nil, addWatermark: nil, - includeResponsibleAIFilterReason: true + includeResponsibleAIFilterReason: true, + includeSafetyAttributes: true ) let parameters = ImagenModel.imageGenerationParameters( @@ -170,7 +174,8 @@ final class ImageGenerationParametersTests: XCTestCase { compressionQuality: imageFormat.compressionQuality ), addWatermark: addWatermark, - includeResponsibleAIFilterReason: true + includeResponsibleAIFilterReason: true, + includeSafetyAttributes: true ) let parameters = ImagenModel.imageGenerationParameters( @@ -200,6 +205,7 @@ final class ImageGenerationParametersTests: XCTestCase { let outputOptions = ImageGenerationOutputOptions(mimeType: mimeType, compressionQuality: nil) let addWatermark = false let includeRAIReason = true + let includeSafetyAttributes = true let parameters = ImageGenerationParameters( sampleCount: sampleCount, storageURI: storageURI, @@ -209,7 +215,8 @@ final class ImageGenerationParametersTests: XCTestCase { personGeneration: personGeneration, outputOptions: outputOptions, addWatermark: addWatermark, - includeResponsibleAIFilterReason: includeRAIReason + includeResponsibleAIFilterReason: includeRAIReason, + includeSafetyAttributes: includeSafetyAttributes ) let jsonData = try encoder.encode(parameters) @@ -220,6 +227,7 @@ final class ImageGenerationParametersTests: XCTestCase { "addWatermark" : \(addWatermark), "aspectRatio" : "\(aspectRatio)", "includeRaiReason" : \(includeRAIReason), + "includeSafetyAttributes" : \(includeSafetyAttributes), "negativePrompt" : "\(negativePrompt)", "outputOptions" : { "mimeType" : "\(mimeType)" @@ -246,7 +254,8 @@ final class ImageGenerationParametersTests: XCTestCase { personGeneration: nil, outputOptions: nil, addWatermark: addWatermark, - includeResponsibleAIFilterReason: nil + includeResponsibleAIFilterReason: nil, + includeSafetyAttributes: nil ) let jsonData = try encoder.encode(parameters) @@ -272,7 +281,8 @@ final class ImageGenerationParametersTests: XCTestCase { personGeneration: nil, outputOptions: nil, addWatermark: nil, - includeResponsibleAIFilterReason: nil + includeResponsibleAIFilterReason: nil, + includeSafetyAttributes: nil ) let jsonData = try encoder.encode(parameters) diff --git a/FirebaseAI/Tests/Unit/Types/Imagen/ImagenGenerationRequestTests.swift b/FirebaseAI/Tests/Unit/Types/Imagen/ImagenGenerationRequestTests.swift index eb8b3df83ca..9a48ed7c8a2 100644 --- a/FirebaseAI/Tests/Unit/Types/Imagen/ImagenGenerationRequestTests.swift +++ b/FirebaseAI/Tests/Unit/Types/Imagen/ImagenGenerationRequestTests.swift @@ -25,6 +25,7 @@ final class ImagenGenerationRequestTests: XCTestCase { let aspectRatio = "16:9" let safetyFilterLevel = "block_low_and_above" let includeResponsibleAIFilterReason = true + let includeSafetyAttributes = true lazy var parameters = ImageGenerationParameters( sampleCount: sampleCount, storageURI: nil, @@ -34,7 +35,8 @@ final class ImagenGenerationRequestTests: XCTestCase { personGeneration: nil, outputOptions: nil, addWatermark: nil, - includeResponsibleAIFilterReason: includeResponsibleAIFilterReason + includeResponsibleAIFilterReason: includeResponsibleAIFilterReason, + includeSafetyAttributes: includeSafetyAttributes ) let apiConfig = FirebaseAI.defaultVertexAIAPIConfig @@ -108,6 +110,7 @@ final class ImagenGenerationRequestTests: XCTestCase { "parameters" : { "aspectRatio" : "\(aspectRatio)", "includeRaiReason" : \(includeResponsibleAIFilterReason), + "includeSafetyAttributes" : \(includeSafetyAttributes), "safetySetting" : "\(safetyFilterLevel)", "sampleCount" : \(sampleCount) } @@ -137,6 +140,7 @@ final class ImagenGenerationRequestTests: XCTestCase { "parameters" : { "aspectRatio" : "\(aspectRatio)", "includeRaiReason" : \(includeResponsibleAIFilterReason), + "includeSafetyAttributes" : \(includeSafetyAttributes), "safetySetting" : "\(safetyFilterLevel)", "sampleCount" : \(sampleCount) } From 67b4531975be67c0e52b25e2182a9607a8982bbd Mon Sep 17 00:00:00 2001 From: Daymon <17409137+daymxn@users.noreply.github.com> Date: Mon, 18 Aug 2025 13:25:51 -0500 Subject: [PATCH 31/76] [Infra] Fix auth CI failure (#15217) --- .github/workflows/auth.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/auth.yml b/.github/workflows/auth.yml index 03e8b2526f2..d86c06b7867 100644 --- a/.github/workflows/auth.yml +++ b/.github/workflows/auth.yml @@ -156,6 +156,8 @@ jobs: steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Setup Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: Configure test keychain From 939cf647ea2f9c7ef538d755751bf3caa83983da Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Mon, 18 Aug 2025 15:33:56 -0400 Subject: [PATCH 32/76] [CI] Run `cocoapods-integration` job on Xcode 16.4 (#15215) --- .github/workflows/cocoapods-integration.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/cocoapods-integration.yml b/.github/workflows/cocoapods-integration.yml index 0a86f76e18b..45ca2101d0b 100644 --- a/.github/workflows/cocoapods-integration.yml +++ b/.github/workflows/cocoapods-integration.yml @@ -26,6 +26,8 @@ jobs: - uses: mikehardy/buildcache-action@c87cea0ccd718971d6cc39e672c4f26815b6c126 with: cache_key: ${{ matrix.os }} + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Get realpath run: brew install coreutils - name: Build and test From 435ea5bea6b6124a6d3f54d9027301351ff388bd Mon Sep 17 00:00:00 2001 From: Aashish <112133849+aashishpatil-g@users.noreply.github.com> Date: Mon, 18 Aug 2025 14:01:52 -0700 Subject: [PATCH 33/76] Add Readme and link to Firebase Data Connect (#15220) --- FirebaseDataConnect/README.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 FirebaseDataConnect/README.md diff --git a/FirebaseDataConnect/README.md b/FirebaseDataConnect/README.md new file mode 100644 index 00000000000..aa3562eb19e --- /dev/null +++ b/FirebaseDataConnect/README.md @@ -0,0 +1,5 @@ +# Firebase Data Connect Swift SDK + +**Connect your Swift & SwiftUI apps directly to a managed Google CloudSQL (PostgreSQL) database.** + +The SDK resides in a separate [git repo](https://github.com/firebase/data-connect-ios-sdk) From 070c929365bc6ae2f98f3c095fef90962cf9b453 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 18 Aug 2025 17:26:15 -0400 Subject: [PATCH 34/76] chore(ci): Correct cron schedule comments in GitHub workflows (#15222) --- .github/workflows/abtesting.yml | 2 +- .github/workflows/analytics.yml | 2 +- .github/workflows/appdistribution.yml | 2 +- .github/workflows/archiving.yml | 2 +- .github/workflows/auth.yml | 2 +- .github/workflows/client_app.yml | 2 +- .github/workflows/cocoapods-integration.yml | 2 +- .github/workflows/combine.yml | 2 +- .github/workflows/core.yml | 2 +- .github/workflows/core_extension.yml | 2 +- .github/workflows/core_internal.yml | 2 +- .github/workflows/crashlytics.yml | 2 +- .github/workflows/database.yml | 2 +- .github/workflows/firebase_app_check.yml | 2 +- .github/workflows/firebaseai.yml | 2 +- .github/workflows/firebasepod.yml | 2 +- .github/workflows/firestore.yml | 2 +- .github/workflows/functions.yml | 2 +- .github/workflows/generate_issues.yml | 2 +- .github/workflows/inappmessaging.yml | 2 +- .github/workflows/installations.yml | 2 +- .github/workflows/messaging.yml | 2 +- .github/workflows/mlmodeldownloader.yml | 2 +- .github/workflows/notice_generation.yml | 2 +- .github/workflows/performance-integration-tests.yml | 1 - .github/workflows/performance.yml | 2 +- .github/workflows/prerelease.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/remoteconfig.yml | 2 +- .github/workflows/sessions.yml | 2 +- .github/workflows/shared-swift.yml | 2 +- .github/workflows/spm.yml | 2 +- .github/workflows/storage.yml | 2 +- .github/workflows/symbolcollision.yml | 2 +- .github/workflows/watchos-sample.yml | 2 +- .github/workflows/zip.yml | 2 +- 36 files changed, 35 insertions(+), 36 deletions(-) diff --git a/.github/workflows/abtesting.yml b/.github/workflows/abtesting.yml index a52070bdf10..b4ec5bef578 100644 --- a/.github/workflows/abtesting.yml +++ b/.github/workflows/abtesting.yml @@ -15,7 +15,7 @@ on: - '.github/workflows/common_catalyst.yml' - 'Gemfile*' schedule: - # Run every day at 1am(PST) - cron uses UTC times + # Run every day at 2am (PDT) / 5am (EDT) - cron uses UTC times - cron: '0 9 * * *' concurrency: diff --git a/.github/workflows/analytics.yml b/.github/workflows/analytics.yml index bb8d5c44141..6e835ee1eff 100644 --- a/.github/workflows/analytics.yml +++ b/.github/workflows/analytics.yml @@ -9,7 +9,7 @@ on: - '.github/workflows/analytics.yml' - 'Gemfile*' schedule: - # Run every day at 1am (PST) - cron uses UTC times + # Run every day at 2am (PDT) / 5am (EDT) - cron uses UTC times - cron: '0 9 * * *' concurrency: diff --git a/.github/workflows/appdistribution.yml b/.github/workflows/appdistribution.yml index 23a48c746d8..808e7ffe697 100644 --- a/.github/workflows/appdistribution.yml +++ b/.github/workflows/appdistribution.yml @@ -14,7 +14,7 @@ on: - '.github/workflows/common_catalyst.yml' - 'Gemfile*' schedule: - # Run every day at 1am (PST) - cron uses UTC times + # Run every day at 2am (PDT) / 5am (EDT) - cron uses UTC times - cron: '0 9 * * *' concurrency: diff --git a/.github/workflows/archiving.yml b/.github/workflows/archiving.yml index c70afe14b8e..c69c8f5699e 100644 --- a/.github/workflows/archiving.yml +++ b/.github/workflows/archiving.yml @@ -6,7 +6,7 @@ on: paths: - '.github/workflows/archiving.yml' schedule: - # Run every day at 2am (PST) - cron uses UTC times + # Run every day at 3am (PDT) / 6am (EDT) - cron uses UTC times # This is set to 3 hours after zip workflow finishes so zip testing can run after. - cron: '0 10 * * *' diff --git a/.github/workflows/auth.yml b/.github/workflows/auth.yml index d86c06b7867..6a0447b399d 100644 --- a/.github/workflows/auth.yml +++ b/.github/workflows/auth.yml @@ -16,7 +16,7 @@ on: - 'scripts/gha-encrypted/AuthSample/SwiftApplication.plist.gpg' - 'Gemfile*' schedule: - # Run every day at 1am (PST) - cron uses UTC times + # Run every day at 2am (PDT) / 5am (EDT) - cron uses UTC times - cron: '0 9 * * *' env: diff --git a/.github/workflows/client_app.yml b/.github/workflows/client_app.yml index 8c4f72c4c27..12d64a91d67 100644 --- a/.github/workflows/client_app.yml +++ b/.github/workflows/client_app.yml @@ -13,7 +13,7 @@ on: - "IntegrationTesting/ClientApp/**" - "Gemfile*" schedule: - # Run every day at 12am (PST) - cron uses UTC times + # Run every day at 1am (PDT) / 4am (EDT) - cron uses UTC times - cron: "0 8 * * *" env: diff --git a/.github/workflows/cocoapods-integration.yml b/.github/workflows/cocoapods-integration.yml index 45ca2101d0b..8853b405a55 100644 --- a/.github/workflows/cocoapods-integration.yml +++ b/.github/workflows/cocoapods-integration.yml @@ -8,7 +8,7 @@ on: - '.github/workflows/cocoapods-integration.yml' - 'Gemfile*' schedule: - # Run every day at 2am (PST) - cron uses UTC times + # Run every day at 3am (PDT) / 6am (EDT) - cron uses UTC times - cron: '0 10 * * *' concurrency: diff --git a/.github/workflows/combine.yml b/.github/workflows/combine.yml index 268d7c21d8c..52ab5c638f6 100644 --- a/.github/workflows/combine.yml +++ b/.github/workflows/combine.yml @@ -42,7 +42,7 @@ on: # - 'Firestore/**' # (Disabled to avoid building Firestore in presubmits) schedule: - # Run every day at 11pm (PST) - cron uses UTC times + # Run every day at 12am (PDT) / 3am (EDT) - cron uses UTC times - cron: '0 7 * * *' concurrency: diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index f380a85947b..0c30320895a 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -14,7 +14,7 @@ on: - '.github/workflows/common_catalyst.yml' - 'Gemfile*' schedule: - # Run every day at 2am (PST) - cron uses UTC times + # Run every day at 3am (PDT) / 6am (EDT) - cron uses UTC times - cron: '0 10 * * *' concurrency: diff --git a/.github/workflows/core_extension.yml b/.github/workflows/core_extension.yml index cc9d602f15d..b36caf5c85c 100644 --- a/.github/workflows/core_extension.yml +++ b/.github/workflows/core_extension.yml @@ -14,7 +14,7 @@ on: - '.github/workflows/common_cocoapods.yml' - 'Gemfile*' schedule: - # Run every day at 2am (PST) - cron uses UTC times + # Run every day at 3am (PDT) / 6am (EDT) - cron uses UTC times - cron: '0 10 * * *' jobs: diff --git a/.github/workflows/core_internal.yml b/.github/workflows/core_internal.yml index db3d565f69f..f536f6c4656 100644 --- a/.github/workflows/core_internal.yml +++ b/.github/workflows/core_internal.yml @@ -15,7 +15,7 @@ on: - '.github/workflows/common_catalyst.yml' - 'Gemfile*' schedule: - # Run every day at 2am (PST) - cron uses UTC times + # Run every day at 3am (PDT) / 6am (EDT) - cron uses UTC times - cron: '0 10 * * *' jobs: diff --git a/.github/workflows/crashlytics.yml b/.github/workflows/crashlytics.yml index 0f5f2cb5643..13c307610ea 100644 --- a/.github/workflows/crashlytics.yml +++ b/.github/workflows/crashlytics.yml @@ -16,7 +16,7 @@ on: - 'Interop/Analytics/Public/*.h' - 'Gemfile*' schedule: - # Run every day at 10am (PST) - cron uses UTC times + # Run every day at 7pm (PDT) / 10pm (EDT) - cron uses UTC times - cron: '0 2 * * *' concurrency: diff --git a/.github/workflows/database.yml b/.github/workflows/database.yml index 24998fa0deb..74a5bebe067 100644 --- a/.github/workflows/database.yml +++ b/.github/workflows/database.yml @@ -19,7 +19,7 @@ on: - 'Gemfile*' - 'scripts/run_database_emulator.sh' schedule: - # Run every day at 2am (PST) - cron uses UTC times + # Run every day at 3am (PDT) / 6am (EDT) - cron uses UTC times - cron: '0 10 * * *' concurrency: diff --git a/.github/workflows/firebase_app_check.yml b/.github/workflows/firebase_app_check.yml index cd9f8eac577..fcec95dad4e 100644 --- a/.github/workflows/firebase_app_check.yml +++ b/.github/workflows/firebase_app_check.yml @@ -14,7 +14,7 @@ on: - '.github/workflows/common_catalyst.yml' - 'Gemfile*' schedule: - # Run every day at 11pm (PST) - cron uses UTC times + # Run every day at 12am (PDT) / 3am (EDT) - cron uses UTC times - cron: '0 7 * * *' concurrency: diff --git a/.github/workflows/firebaseai.yml b/.github/workflows/firebaseai.yml index a5303b019a6..16e3fdb08c5 100644 --- a/.github/workflows/firebaseai.yml +++ b/.github/workflows/firebaseai.yml @@ -13,7 +13,7 @@ on: # Do not run for documentation-only PRs. - '!**.md' schedule: - # Run every day at 11pm (PST) - cron uses UTC times + # Run every day at 12am (PDT) / 3am (EDT) - cron uses UTC times - cron: '0 7 * * *' workflow_dispatch: diff --git a/.github/workflows/firebasepod.yml b/.github/workflows/firebasepod.yml index f1e228b7f24..ac61d4735a6 100644 --- a/.github/workflows/firebasepod.yml +++ b/.github/workflows/firebasepod.yml @@ -11,7 +11,7 @@ on: - '.github/workflows/firebasepod.yml' - 'Gemfile*' schedule: - # Run every day at 1am (PST) - cron uses UTC times + # Run every day at 2am (PDT) / 5am (EDT) - cron uses UTC times - cron: '0 9 * * *' concurrency: diff --git a/.github/workflows/firestore.yml b/.github/workflows/firestore.yml index d3f61e67b4a..dbb144924d8 100644 --- a/.github/workflows/firestore.yml +++ b/.github/workflows/firestore.yml @@ -18,7 +18,7 @@ on: workflow_dispatch: pull_request: schedule: - # Run every day at 12am (PST) - cron uses UTC times + # Run every day at 1am (PDT) / 4am (EDT) - cron uses UTC times - cron: '0 8 * * *' concurrency: diff --git a/.github/workflows/functions.yml b/.github/workflows/functions.yml index c7a8b6e54ca..658a78f1952 100644 --- a/.github/workflows/functions.yml +++ b/.github/workflows/functions.yml @@ -20,7 +20,7 @@ on: - 'Gemfile*' schedule: - # Run every day at 1am (PST) - cron uses UTC times + # Run every day at 2am (PDT) / 5am (EDT) - cron uses UTC times - cron: '0 9 * * *' concurrency: diff --git a/.github/workflows/generate_issues.yml b/.github/workflows/generate_issues.yml index 53473cabb05..b4e598c355c 100644 --- a/.github/workflows/generate_issues.yml +++ b/.github/workflows/generate_issues.yml @@ -7,7 +7,7 @@ on: - '.github/workflows/generate_issues.yml' - '.github/actions/testing_report_generation**' schedule: - # Run every day at 4am (PST) - cron uses UTC times + # Run every day at 5am (PDT) / 8am (EDT) - cron uses UTC times - cron: '0 12 * * *' permissions: diff --git a/.github/workflows/inappmessaging.yml b/.github/workflows/inappmessaging.yml index feb26e72c65..edcf7b25b8d 100644 --- a/.github/workflows/inappmessaging.yml +++ b/.github/workflows/inappmessaging.yml @@ -14,7 +14,7 @@ on: - '.github/workflows/common_cocoapods.yml' - 'Gemfile*' schedule: - # Run every day at 10pm (PST) - cron uses UTC times + # Run every day at 11pm (PDT) / 2am (EDT) - cron uses UTC times - cron: '0 6 * * *' concurrency: diff --git a/.github/workflows/installations.yml b/.github/workflows/installations.yml index 2b149918f0a..8a87c9dd341 100644 --- a/.github/workflows/installations.yml +++ b/.github/workflows/installations.yml @@ -14,7 +14,7 @@ on: - '.github/workflows/common_catalyst.yml' - 'Gemfile*' schedule: - # Run every day at 10pm (PST) - cron uses UTC times + # Run every day at 11pm (PDT) / 2am (EDT) - cron uses UTC times - cron: '0 6 * * *' concurrency: diff --git a/.github/workflows/messaging.yml b/.github/workflows/messaging.yml index db9d8f8ccac..24f6a7de304 100644 --- a/.github/workflows/messaging.yml +++ b/.github/workflows/messaging.yml @@ -22,7 +22,7 @@ on: # Rebuild on Ruby infrastructure changes - 'Gemfile*' schedule: - # Run every day at 10pm (PST) - cron uses UTC times + # Run every day at 11pm (PDT) / 2am (EDT) - cron uses UTC times - cron: '0 6 * * *' concurrency: diff --git a/.github/workflows/mlmodeldownloader.yml b/.github/workflows/mlmodeldownloader.yml index 931c8edda79..d4bb6f1a5c7 100644 --- a/.github/workflows/mlmodeldownloader.yml +++ b/.github/workflows/mlmodeldownloader.yml @@ -14,7 +14,7 @@ on: - '.github/workflows/common_catalyst.yml' - 'Gemfile*' schedule: - # Run every day at 11pm (PST) - cron uses UTC times + # Run every day at 12am (PDT) / 3am (EDT) - cron uses UTC times - cron: '0 7 * * *' concurrency: diff --git a/.github/workflows/notice_generation.yml b/.github/workflows/notice_generation.yml index a7a87cf4251..6d769c509d1 100644 --- a/.github/workflows/notice_generation.yml +++ b/.github/workflows/notice_generation.yml @@ -10,7 +10,7 @@ on: - '.github/workflows/notice_generation.yml' - '.github/actions/notices_generation**' schedule: - # Run every day at 2am (PST) - cron uses UTC times + # Run every day at 3am (PDT) / 6am (EDT) - cron uses UTC times - cron: '0 10 * * *' jobs: generate_a_notice: diff --git a/.github/workflows/performance-integration-tests.yml b/.github/workflows/performance-integration-tests.yml index 1092ba0df0f..95d486d39e6 100644 --- a/.github/workflows/performance-integration-tests.yml +++ b/.github/workflows/performance-integration-tests.yml @@ -13,7 +13,6 @@ on: # - https://crontab.guru/ schedule: # Runs every 4 hours. - # TODO: Validate when the timer starts after job is triggered. - cron: '0 */4 * * *' concurrency: diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 61c08473772..d788c81a968 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -22,7 +22,7 @@ on: # Rebuild on Ruby infrastructure changes - 'Gemfile*' schedule: - # Run every day at 11pm (PST) - cron uses UTC times + # Run every day at 12am (PDT) / 3am (EDT) - cron uses UTC times # Specified in format 'minutes hours day month dayofweek' - cron: '0 7 * * *' diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 6bdc3749b3f..de7187ddb9b 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -9,7 +9,7 @@ on: types: [closed] workflow_dispatch: schedule: - # Run every day at 9pm (PST) - cron uses UTC times + # Run every day at 10pm (PDT) / 1am (EDT) - cron uses UTC times - cron: '0 5 * * *' env: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 531cc021b2c..d7bbc90cd13 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,7 +8,7 @@ on: - 'Gemfile*' workflow_dispatch: schedule: - # Run every day at 9pm (PST) - cron uses UTC times + # Run every day at 10pm (PDT) / 1am (EDT) - cron uses UTC times - cron: '0 5 * * *' env: diff --git a/.github/workflows/remoteconfig.yml b/.github/workflows/remoteconfig.yml index 199fd669f41..6b7ca4d68b3 100644 --- a/.github/workflows/remoteconfig.yml +++ b/.github/workflows/remoteconfig.yml @@ -17,7 +17,7 @@ on: - 'scripts/generate_access_token.sh' - 'scripts/gha-encrypted/RemoteConfigSwiftAPI/**' schedule: - # Run every day at 12am (PST) - cron uses UTC times + # Run every day at 1am (PDT) / 4am (EDT) - cron uses UTC times - cron: '0 8 * * *' concurrency: diff --git a/.github/workflows/sessions.yml b/.github/workflows/sessions.yml index d3ec5adb7f1..f0df72c44c2 100644 --- a/.github/workflows/sessions.yml +++ b/.github/workflows/sessions.yml @@ -15,7 +15,7 @@ on: - '.github/workflows/common_catalyst.yml' - 'Gemfile*' schedule: - # Run every day at 9am (PST) - cron uses UTC times + # Run every day at 6pm (PDT) / 9pm (EDT) - cron uses UTC times - cron: '0 1 * * *' concurrency: diff --git a/.github/workflows/shared-swift.yml b/.github/workflows/shared-swift.yml index b1292ebb253..fa13d6e9a4c 100644 --- a/.github/workflows/shared-swift.yml +++ b/.github/workflows/shared-swift.yml @@ -14,7 +14,7 @@ on: - 'Gemfile*' schedule: - # Run every day at 3am (PST) - cron uses UTC times + # Run every day at 4am (PDT) / 7am (EDT) - cron uses UTC times - cron: '0 11 * * *' concurrency: diff --git a/.github/workflows/spm.yml b/.github/workflows/spm.yml index a1227e2ef1c..6d583ebd780 100644 --- a/.github/workflows/spm.yml +++ b/.github/workflows/spm.yml @@ -12,7 +12,7 @@ on: - 'SwiftPM-PlatformExclude' - 'Gemfile*' schedule: - # Run every day at 12am (PST) - cron uses UTC times + # Run every day at 1am (PDT) / 4am (EDT) - cron uses UTC times - cron: '0 8 * * *' # This workflow builds and tests the Swift Package Manager. Only iOS runs on PRs diff --git a/.github/workflows/storage.yml b/.github/workflows/storage.yml index 740b15c7766..fd109429a5e 100644 --- a/.github/workflows/storage.yml +++ b/.github/workflows/storage.yml @@ -16,7 +16,7 @@ on: # Rebuild on Ruby infrastructure changes. - 'Gemfile*' schedule: - # Run every day at 12am (PST) - cron uses UTC times + # Run every day at 1am (PDT) / 4am (EDT) - cron uses UTC times - cron: '0 8 * * *' concurrency: diff --git a/.github/workflows/symbolcollision.yml b/.github/workflows/symbolcollision.yml index 00fcde3c3e9..298f7fd4f10 100644 --- a/.github/workflows/symbolcollision.yml +++ b/.github/workflows/symbolcollision.yml @@ -10,7 +10,7 @@ on: - 'SymbolCollisionTest/**' - 'Gemfile*' schedule: - # Run every day at 12am (PST) - cron uses UTC times + # Run every day at 1am (PDT) / 4am (EDT) - cron uses UTC times - cron: '0 8 * * *' concurrency: diff --git a/.github/workflows/watchos-sample.yml b/.github/workflows/watchos-sample.yml index 665dfbea350..b8589288863 100644 --- a/.github/workflows/watchos-sample.yml +++ b/.github/workflows/watchos-sample.yml @@ -18,7 +18,7 @@ on: # Rebuild on Ruby infrastructure changes - 'Gemfile*' schedule: - # Run every day at 10pm (PST) - cron uses UTC times + # Run every day at 11pm (PDT) / 2am (EDT) - cron uses UTC times - cron: '0 6 * * *' concurrency: diff --git a/.github/workflows/zip.yml b/.github/workflows/zip.yml index 42a216c1567..87bca8ad3f1 100644 --- a/.github/workflows/zip.yml +++ b/.github/workflows/zip.yml @@ -12,7 +12,7 @@ on: # Don't run based on any markdown only changes. - '!ReleaseTooling/*.md' schedule: - # Run every day at 8pm(PST) - cron uses UTC times + # Run every day at 9pm (PDT) / 12am (EDT) - cron uses UTC times - cron: '0 4 * * *' workflow_dispatch: From f2d5abe489c54b626e1b19d72c1ef81febce1dcd Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 18 Aug 2025 18:03:17 -0400 Subject: [PATCH 35/76] fix(ci): Use Xcode 16.4 in `archiving.yml` & `release.yml` (#15225) --- .github/workflows/archiving.yml | 4 ++++ .github/workflows/release.yml | 26 ++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/.github/workflows/archiving.yml b/.github/workflows/archiving.yml index c69c8f5699e..c3b58ebbb69 100644 --- a/.github/workflows/archiving.yml +++ b/.github/workflows/archiving.yml @@ -27,6 +27,8 @@ jobs: pod: ["FirebaseAppDistribution", "FirebaseInAppMessaging", "FirebasePerformance"] steps: - uses: actions/checkout@v4 + - name: Set Xcode version + run: sudo xcode-select -s /Applications/Xcode_16.4.app - uses: mikehardy/buildcache-action@c87cea0ccd718971d6cc39e672c4f26815b6c126 with: cache_key: cron-${{ matrix.os }} @@ -50,6 +52,8 @@ jobs: pod: ["FirebaseABTesting", "FirebaseAuth", "FirebaseCore", "FirebaseCrashlytics", "FirebaseDatabase", "FirebaseFirestore", "FirebaseFunctions", "FirebaseMessaging", "FirebaseRemoteConfig", "FirebaseStorage"] steps: - uses: actions/checkout@v4 + - name: Set Xcode version + run: sudo xcode-select -s /Applications/Xcode_16.4.app - uses: mikehardy/buildcache-action@c87cea0ccd718971d6cc39e672c4f26815b6c126 with: cache_key: pods-${{ matrix.os }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d7bbc90cd13..3b28e2fb8ec 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -86,6 +86,8 @@ jobs: targeted_pod: FirebaseCore steps: - uses: actions/checkout@v4 + - name: Set Xcode version + run: sudo xcode-select -s /Applications/Xcode_16.4.app - uses: actions/download-artifact@v4.1.7 with: name: firebase-ios-sdk @@ -119,6 +121,8 @@ jobs: targeted_pod: ${{ matrix.podspec }} steps: - uses: actions/checkout@v4 + - name: Set Xcode version + run: sudo xcode-select -s /Applications/Xcode_16.4.app - uses: actions/download-artifact@v4.1.7 with: name: firebase-ios-sdk @@ -152,6 +156,8 @@ jobs: runs-on: macos-14 steps: - uses: actions/checkout@v4 + - name: Set Xcode version + run: sudo xcode-select -s /Applications/Xcode_16.4.app - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Setup testing repo and quickstart env: @@ -186,9 +192,9 @@ jobs: runs-on: macos-15 steps: - uses: actions/checkout@v4 + - name: Set Xcode version + run: sudo xcode-select -s /Applications/Xcode_16.4.app - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh Authentication nightly_release_testing - name: Install Secret GoogleService-Info.plist @@ -218,6 +224,8 @@ jobs: runs-on: macos-14 steps: - uses: actions/checkout@v4 + - name: Set Xcode version + run: sudo xcode-select -s /Applications/Xcode_16.4.app - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Setup testing repo and quickstart env: @@ -259,6 +267,8 @@ jobs: runs-on: macos-14 steps: - uses: actions/checkout@v4 + - name: Set Xcode version + run: sudo xcode-select -s /Applications/Xcode_16.4.app - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh database nightly_release_testing @@ -291,6 +301,8 @@ jobs: runs-on: macos-14 steps: - uses: actions/checkout@v4 + - name: Set Xcode version + run: sudo xcode-select -s /Applications/Xcode_16.4.app - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh firestore nightly_release_testing @@ -360,6 +372,8 @@ jobs: runs-on: macos-14 steps: - uses: actions/checkout@v4 + - name: Set Xcode version + run: sudo xcode-select -s /Applications/Xcode_16.4.app - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh inappmessaging nightly_release_testing @@ -394,6 +408,8 @@ jobs: runs-on: macos-14 steps: - uses: actions/checkout@v4 + - name: Set Xcode version + run: sudo xcode-select -s /Applications/Xcode_16.4.app - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh messaging nightly_release_testing @@ -426,6 +442,8 @@ jobs: runs-on: macos-14 steps: - uses: actions/checkout@v4 + - name: Set Xcode version + run: sudo xcode-select -s /Applications/Xcode_16.4.app - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh config nightly_release_testing @@ -457,6 +475,8 @@ jobs: runs-on: macos-14 steps: - uses: actions/checkout@v4 + - name: Set Xcode version + run: sudo xcode-select -s /Applications/Xcode_16.4.app - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh storage nightly_release_testing @@ -487,6 +507,8 @@ jobs: runs-on: macos-14 steps: - uses: actions/checkout@v4 + - name: Set Xcode version + run: sudo xcode-select -s /Applications/Xcode_16.4.app - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh Performance nightly_release_testing From 258956b0477f1dd9e2b8c71c6bbdaacf87592fe7 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 18 Aug 2025 18:05:41 -0400 Subject: [PATCH 36/76] fix(ci): Select Xcode 16.4 in combine workflow (#15224) --- .github/workflows/combine.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/combine.yml b/.github/workflows/combine.yml index 52ab5c638f6..37e6741ca04 100644 --- a/.github/workflows/combine.yml +++ b/.github/workflows/combine.yml @@ -67,6 +67,9 @@ jobs: - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer + - name: Install xcpretty run: gem install xcpretty @@ -88,6 +91,8 @@ jobs: with: cache_key: ${{ matrix.os }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: Install xcpretty From 3a8d1c28a630f438594d2046fb06a7b749455081 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 18 Aug 2025 18:05:54 -0400 Subject: [PATCH 37/76] [Infra] Fix zip.yml workflow (#15219) --- .github/workflows/zip.yml | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/zip.yml b/.github/workflows/zip.yml index 87bca8ad3f1..10a02312ce0 100644 --- a/.github/workflows/zip.yml +++ b/.github/workflows/zip.yml @@ -123,6 +123,8 @@ jobs: with: name: ${{ matrix.artifact }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup Bundler run: ./scripts/setup_bundler.sh - name: Move frameworks @@ -130,8 +132,6 @@ jobs: mkdir -p "${HOME}"/ios_frameworks/ find "${GITHUB_WORKSPACE}" -name "Firebase*latest.zip" -exec unzip -d "${HOME}"/ios_frameworks/ {} + - uses: actions/checkout@v4 - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup quickstart env: LEGACY: true @@ -183,14 +183,14 @@ jobs: with: name: ${{ matrix.artifact }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - name: Setup Bundler run: ./scripts/setup_bundler.sh - name: Move frameworks run: | mkdir -p "${HOME}"/ios_frameworks/ find "${GITHUB_WORKSPACE}" -name "Firebase*latest.zip" -exec unzip -d "${HOME}"/ios_frameworks/ {} + - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - name: Setup Swift Quickstart run: SAMPLE="$SDK" TARGET="${SDK}Example" NON_FIREBASE_SDKS="FBSDKLoginKit FBSDKCoreKit FBSDKCoreKit_Basics FBAEMKit" scripts/setup_quickstart_framework.sh \ "${HOME}"/ios_frameworks/Firebase/NonFirebaseSDKs/* \ @@ -233,14 +233,14 @@ jobs: with: name: ${{ matrix.artifact }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup Bundler run: ./scripts/setup_bundler.sh - name: Move frameworks run: | mkdir -p "${HOME}"/ios_frameworks/ find "${GITHUB_WORKSPACE}" -name "Firebase*latest.zip" -exec unzip -d "${HOME}"/ios_frameworks/ {} + - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup Swift Quickstart run: SAMPLE="$SDK" TARGET="${SDK}Example" scripts/setup_quickstart_framework.sh \ @@ -282,6 +282,8 @@ jobs: with: name: ${{ matrix.artifact }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup Bundler run: ./scripts/setup_bundler.sh - name: Move frameworks @@ -289,8 +291,6 @@ jobs: mkdir -p "${HOME}"/ios_frameworks/ find "${GITHUB_WORKSPACE}" -name "Firebase*latest.zip" -exec unzip -d "${HOME}"/ios_frameworks/ {} + - uses: actions/checkout@v4 - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup quickstart env: LEGACY: true @@ -353,6 +353,8 @@ jobs: with: name: ${{ matrix.artifact }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - name: Setup Bundler run: ./scripts/setup_bundler.sh - name: Move frameworks @@ -360,8 +362,6 @@ jobs: mkdir -p "${HOME}"/ios_frameworks/ find "${GITHUB_WORKSPACE}" -name "Firebase*latest.zip" -exec unzip -d "${HOME}"/ios_frameworks/ {} + - uses: actions/checkout@v4 - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - name: Setup quickstart run: SAMPLE="$SDK" TARGET="${SDK}Example" NON_FIREBASE_SDKS="FirebaseDatabaseUI" scripts/setup_quickstart_framework.sh \ "${HOME}"/ios_frameworks/Firebase/FirebaseDatabase/* \ @@ -406,6 +406,8 @@ jobs: with: name: ${{ matrix.artifact }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup Bundler run: ./scripts/setup_bundler.sh - name: Move frameworks @@ -425,8 +427,6 @@ jobs: with: name: build_logs_firestore_${{ matrix.artifact }}_${{ matrix.build-env.os }} path: sdk_zip/build_logs/ - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Install Secret GoogleService-Info.plist run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-firestore.plist.gpg \ quickstart-ios/firestore/GoogleService-Info.plist "$plist_secret" @@ -494,6 +494,8 @@ jobs: with: name: ${{ matrix.artifact }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup Bundler run: ./scripts/setup_bundler.sh - name: Move frameworks @@ -505,8 +507,6 @@ jobs: run: SAMPLE="$SDK" TARGET="${SDK}Example" scripts/setup_quickstart_framework.sh \ "${HOME}"/ios_frameworks/Firebase/FirebaseInAppMessaging/* \ "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/* - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup swift quickstart run: SAMPLE="$SDK" TARGET="${SDK}ExampleSwift" scripts/setup_quickstart_framework.sh - name: Install Secret GoogleService-Info.plist @@ -547,6 +547,8 @@ jobs: with: name: ${{ matrix.artifact }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup Bundler run: ./scripts/setup_bundler.sh - name: Move frameworks @@ -558,8 +560,6 @@ jobs: run: SAMPLE="$SDK" TARGET="${SDK}Example" scripts/setup_quickstart_framework.sh \ "${HOME}"/ios_frameworks/Firebase/FirebaseMessaging/* \ "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/* - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup swift quickstart run: SAMPLE="$SDK" TARGET="${SDK}ExampleSwift" scripts/setup_quickstart_framework.sh - name: Install Secret GoogleService-Info.plist @@ -600,6 +600,8 @@ jobs: with: name: ${{ matrix.artifact }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup Bundler run: ./scripts/setup_bundler.sh - name: Move frameworks @@ -614,8 +616,6 @@ jobs: "${HOME}"/ios_frameworks/Firebase/FirebaseStorage/* \ "${HOME}"/ios_frameworks/Firebase/FirebaseAuth/* \ "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/* - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer - name: Setup swift quickstart env: LEGACY: true From e176f012f7893080d031e6032f22c40064168ef5 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Mon, 18 Aug 2025 19:44:47 -0400 Subject: [PATCH 38/76] [Firebase AI] Add support for thought summaries (#15096) --- FirebaseAI/CHANGELOG.md | 6 +- FirebaseAI/Sources/Chat.swift | 53 ++-- .../Sources/GenerateContentResponse.swift | 72 +++-- FirebaseAI/Sources/ModelContent.swift | 132 +++++--- .../Sources/Types/Internal/InternalPart.swift | 3 + FirebaseAI/Sources/Types/Public/Part.swift | 63 +++- .../Sources/Types/Public/ThinkingConfig.swift | 14 +- .../GenerateContentIntegrationTests.swift | 156 ++++++++-- .../Unit/GenerativeModelGoogleAITests.swift | 112 +++++++ .../Unit/GenerativeModelVertexAITests.swift | 50 +++ .../Tests/Unit/Types/InternalPartTests.swift | 286 ++++++++++++++++++ 11 files changed, 838 insertions(+), 109 deletions(-) create mode 100644 FirebaseAI/Tests/Unit/Types/InternalPartTests.swift diff --git a/FirebaseAI/CHANGELOG.md b/FirebaseAI/CHANGELOG.md index 47b2627da67..ea7fd44941e 100644 --- a/FirebaseAI/CHANGELOG.md +++ b/FirebaseAI/CHANGELOG.md @@ -1,5 +1,9 @@ +# 12.2.0 +- [feature] Added support for returning thought summaries, which are synthesized + versions of a model's internal reasoning process. (#15096) + # 12.0.0 -- [added] Added support for Grounding with Google Search. (#15014) +- [feature] Added support for Grounding with Google Search. (#15014) - [removed] Removed `CountTokensResponse.totalBillableCharacters` which was deprecated in 11.15.0. Use `totalTokens` instead. (#15056) diff --git a/FirebaseAI/Sources/Chat.swift b/FirebaseAI/Sources/Chat.swift index 42da2ef4a6d..80e908a8f57 100644 --- a/FirebaseAI/Sources/Chat.swift +++ b/FirebaseAI/Sources/Chat.swift @@ -147,31 +147,48 @@ public final class Chat: Sendable { } private func aggregatedChunks(_ chunks: [ModelContent]) -> ModelContent { - var parts: [any Part] = [] + var parts: [InternalPart] = [] var combinedText = "" - for aggregate in chunks { - // Loop through all the parts, aggregating the text and adding the images. - for part in aggregate.parts { - switch part { - case let textPart as TextPart: - combinedText += textPart.text - - default: - // Don't combine it, just add to the content. If there's any text pending, add that as - // a part. + var combinedThoughts = "" + + func flush() { + if !combinedThoughts.isEmpty { + parts.append(InternalPart(.text(combinedThoughts), isThought: true, thoughtSignature: nil)) + combinedThoughts = "" + } + if !combinedText.isEmpty { + parts.append(InternalPart(.text(combinedText), isThought: nil, thoughtSignature: nil)) + combinedText = "" + } + } + + // Loop through all the parts, aggregating the text. + for part in chunks.flatMap({ $0.internalParts }) { + // Only text parts may be combined. + if case let .text(text) = part.data, part.thoughtSignature == nil { + // Thought summaries must not be combined with regular text. + if part.isThought ?? false { + // If we were combining regular text, flush it before handling "thoughts". if !combinedText.isEmpty { - parts.append(TextPart(combinedText)) - combinedText = "" + flush() } - - parts.append(part) + combinedThoughts += text + } else { + // If we were combining "thoughts", flush it before handling regular text. + if !combinedThoughts.isEmpty { + flush() + } + combinedText += text } + } else { + // This is a non-combinable part (not text), flush any pending text. + flush() + parts.append(part) } } - if !combinedText.isEmpty { - parts.append(TextPart(combinedText)) - } + // Flush any remaining text. + flush() return ModelContent(role: "model", parts: parts) } diff --git a/FirebaseAI/Sources/GenerateContentResponse.swift b/FirebaseAI/Sources/GenerateContentResponse.swift index 1cc9874e795..0756d2afd9a 100644 --- a/FirebaseAI/Sources/GenerateContentResponse.swift +++ b/FirebaseAI/Sources/GenerateContentResponse.swift @@ -57,30 +57,19 @@ public struct GenerateContentResponse: Sendable { public let usageMetadata: UsageMetadata? /// The response's content as text, if it exists. + /// + /// - Note: This does not include thought summaries; see ``thoughtSummary`` for more details. public var text: String? { - guard let candidate = candidates.first else { - AILog.error( - code: .generateContentResponseNoCandidates, - "Could not get text from a response that had no candidates." - ) - return nil - } - let textValues: [String] = candidate.content.parts.compactMap { part in - switch part { - case let textPart as TextPart: - return textPart.text - default: - return nil - } - } - guard textValues.count > 0 else { - AILog.error( - code: .generateContentResponseNoText, - "Could not get a text part from the first candidate." - ) - return nil - } - return textValues.joined(separator: " ") + return text(isThought: false) + } + + /// A summary of the model's thinking process, if available. + /// + /// - Important: Thought summaries are only available when `includeThoughts` is enabled in the + /// ``ThinkingConfig``. For more information, see the + /// [Thinking](https://firebase.google.com/docs/ai-logic/thinking) documentation. + public var thoughtSummary: String? { + return text(isThought: true) } /// Returns function calls found in any `Part`s of the first candidate of the response, if any. @@ -89,12 +78,10 @@ public struct GenerateContentResponse: Sendable { return [] } return candidate.content.parts.compactMap { part in - switch part { - case let functionCallPart as FunctionCallPart: - return functionCallPart - default: + guard let functionCallPart = part as? FunctionCallPart, !part.isThought else { return nil } + return functionCallPart } } @@ -107,7 +94,12 @@ public struct GenerateContentResponse: Sendable { """) return [] } - return candidate.content.parts.compactMap { $0 as? InlineDataPart } + return candidate.content.parts.compactMap { part in + guard let inlineDataPart = part as? InlineDataPart, !part.isThought else { + return nil + } + return inlineDataPart + } } /// Initializer for SwiftUI previews or tests. @@ -117,6 +109,30 @@ public struct GenerateContentResponse: Sendable { self.promptFeedback = promptFeedback self.usageMetadata = usageMetadata } + + func text(isThought: Bool) -> String? { + guard let candidate = candidates.first else { + AILog.error( + code: .generateContentResponseNoCandidates, + "Could not get text from a response that had no candidates." + ) + return nil + } + let textValues: [String] = candidate.content.parts.compactMap { part in + guard let textPart = part as? TextPart, part.isThought == isThought else { + return nil + } + return textPart.text + } + guard textValues.count > 0 else { + AILog.error( + code: .generateContentResponseNoText, + "Could not get a text part from the first candidate." + ) + return nil + } + return textValues.joined(separator: " ") + } } /// A struct representing a possible reply to a content generation prompt. Each content generation diff --git a/FirebaseAI/Sources/ModelContent.swift b/FirebaseAI/Sources/ModelContent.swift index 7d82bd76445..1a0aa6f5f09 100644 --- a/FirebaseAI/Sources/ModelContent.swift +++ b/FirebaseAI/Sources/ModelContent.swift @@ -31,41 +31,62 @@ extension [ModelContent] { } } -/// A type describing data in media formats interpretable by an AI model. Each generative AI -/// request or response contains an `Array` of ``ModelContent``s, and each ``ModelContent`` value -/// may comprise multiple heterogeneous ``Part``s. @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) -public struct ModelContent: Equatable, Sendable { - enum InternalPart: Equatable, Sendable { +struct InternalPart: Equatable, Sendable { + enum OneOfData: Equatable, Sendable { case text(String) - case inlineData(mimetype: String, Data) - case fileData(mimetype: String, uri: String) + case inlineData(InlineData) + case fileData(FileData) case functionCall(FunctionCall) case functionResponse(FunctionResponse) } + let data: OneOfData + + let isThought: Bool? + + let thoughtSignature: String? + + init(_ data: OneOfData, isThought: Bool?, thoughtSignature: String?) { + self.data = data + self.isThought = isThought + self.thoughtSignature = thoughtSignature + } +} + +/// A type describing data in media formats interpretable by an AI model. Each generative AI +/// request or response contains an `Array` of ``ModelContent``s, and each ``ModelContent`` value +/// may comprise multiple heterogeneous ``Part``s. +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +public struct ModelContent: Equatable, Sendable { /// The role of the entity creating the ``ModelContent``. For user-generated client requests, /// for example, the role is `user`. public let role: String? /// The data parts comprising this ``ModelContent`` value. public var parts: [any Part] { - var convertedParts = [any Part]() - for part in internalParts { - switch part { + return internalParts.map { part -> any Part in + switch part.data { case let .text(text): - convertedParts.append(TextPart(text)) - case let .inlineData(mimetype, data): - convertedParts.append(InlineDataPart(data: data, mimeType: mimetype)) - case let .fileData(mimetype, uri): - convertedParts.append(FileDataPart(uri: uri, mimeType: mimetype)) + return TextPart(text, isThought: part.isThought, thoughtSignature: part.thoughtSignature) + case let .inlineData(inlineData): + return InlineDataPart( + inlineData, isThought: part.isThought, thoughtSignature: part.thoughtSignature + ) + case let .fileData(fileData): + return FileDataPart( + fileData, isThought: part.isThought, thoughtSignature: part.thoughtSignature + ) case let .functionCall(functionCall): - convertedParts.append(FunctionCallPart(functionCall)) + return FunctionCallPart( + functionCall, isThought: part.isThought, thoughtSignature: part.thoughtSignature + ) case let .functionResponse(functionResponse): - convertedParts.append(FunctionResponsePart(functionResponse)) + return FunctionResponsePart( + functionResponse, isThought: part.isThought, thoughtSignature: part.thoughtSignature + ) } } - return convertedParts } // TODO: Refactor this @@ -78,17 +99,35 @@ public struct ModelContent: Equatable, Sendable { for part in parts { switch part { case let textPart as TextPart: - convertedParts.append(.text(textPart.text)) + convertedParts.append(InternalPart( + .text(textPart.text), + isThought: textPart._isThought, + thoughtSignature: textPart.thoughtSignature + )) case let inlineDataPart as InlineDataPart: - let inlineData = inlineDataPart.inlineData - convertedParts.append(.inlineData(mimetype: inlineData.mimeType, inlineData.data)) + convertedParts.append(InternalPart( + .inlineData(inlineDataPart.inlineData), + isThought: inlineDataPart._isThought, + thoughtSignature: inlineDataPart.thoughtSignature + )) case let fileDataPart as FileDataPart: - let fileData = fileDataPart.fileData - convertedParts.append(.fileData(mimetype: fileData.mimeType, uri: fileData.fileURI)) + convertedParts.append(InternalPart( + .fileData(fileDataPart.fileData), + isThought: fileDataPart._isThought, + thoughtSignature: fileDataPart.thoughtSignature + )) case let functionCallPart as FunctionCallPart: - convertedParts.append(.functionCall(functionCallPart.functionCall)) + convertedParts.append(InternalPart( + .functionCall(functionCallPart.functionCall), + isThought: functionCallPart._isThought, + thoughtSignature: functionCallPart.thoughtSignature + )) case let functionResponsePart as FunctionResponsePart: - convertedParts.append(.functionResponse(functionResponsePart.functionResponse)) + convertedParts.append(InternalPart( + .functionResponse(functionResponsePart.functionResponse), + isThought: functionResponsePart._isThought, + thoughtSignature: functionResponsePart.thoughtSignature + )) default: fatalError() } @@ -102,6 +141,11 @@ public struct ModelContent: Equatable, Sendable { let content = parts.flatMap { $0.partsValue } self.init(role: role, parts: content) } + + init(role: String?, parts: [InternalPart]) { + self.role = role + internalParts = parts + } } // MARK: Codable Conformances @@ -121,7 +165,29 @@ extension ModelContent: Codable { } @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) -extension ModelContent.InternalPart: Codable { +extension InternalPart: Codable { + enum CodingKeys: String, CodingKey { + case isThought = "thought" + case thoughtSignature + } + + public func encode(to encoder: Encoder) throws { + try data.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(isThought, forKey: .isThought) + try container.encodeIfPresent(thoughtSignature, forKey: .thoughtSignature) + } + + public init(from decoder: Decoder) throws { + data = try OneOfData(from: decoder) + let container = try decoder.container(keyedBy: CodingKeys.self) + isThought = try container.decodeIfPresent(Bool.self, forKey: .isThought) + thoughtSignature = try container.decodeIfPresent(String.self, forKey: .thoughtSignature) + } +} + +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +extension InternalPart.OneOfData: Codable { enum CodingKeys: String, CodingKey { case text case inlineData @@ -135,10 +201,10 @@ extension ModelContent.InternalPart: Codable { switch self { case let .text(text): try container.encode(text, forKey: .text) - case let .inlineData(mimetype, bytes): - try container.encode(InlineData(data: bytes, mimeType: mimetype), forKey: .inlineData) - case let .fileData(mimetype: mimetype, url): - try container.encode(FileData(fileURI: url, mimeType: mimetype), forKey: .fileData) + case let .inlineData(inlineData): + try container.encode(inlineData, forKey: .inlineData) + case let .fileData(fileData): + try container.encode(fileData, forKey: .fileData) case let .functionCall(functionCall): try container.encode(functionCall, forKey: .functionCall) case let .functionResponse(functionResponse): @@ -151,11 +217,9 @@ extension ModelContent.InternalPart: Codable { if values.contains(.text) { self = try .text(values.decode(String.self, forKey: .text)) } else if values.contains(.inlineData) { - let inlineData = try values.decode(InlineData.self, forKey: .inlineData) - self = .inlineData(mimetype: inlineData.mimeType, inlineData.data) + self = try .inlineData(values.decode(InlineData.self, forKey: .inlineData)) } else if values.contains(.fileData) { - let fileData = try values.decode(FileData.self, forKey: .fileData) - self = .fileData(mimetype: fileData.mimeType, uri: fileData.fileURI) + self = try .fileData(values.decode(FileData.self, forKey: .fileData)) } else if values.contains(.functionCall) { self = try .functionCall(values.decode(FunctionCall.self, forKey: .functionCall)) } else if values.contains(.functionResponse) { diff --git a/FirebaseAI/Sources/Types/Internal/InternalPart.swift b/FirebaseAI/Sources/Types/Internal/InternalPart.swift index d543fb80f38..bb62dd4c0b5 100644 --- a/FirebaseAI/Sources/Types/Internal/InternalPart.swift +++ b/FirebaseAI/Sources/Types/Internal/InternalPart.swift @@ -67,6 +67,9 @@ struct FunctionResponse: Codable, Equatable, Sendable { struct ErrorPart: Part, Error { let error: Error + let isThought = false + let thoughtSignature: String? = nil + init(_ error: Error) { self.error = error } diff --git a/FirebaseAI/Sources/Types/Public/Part.swift b/FirebaseAI/Sources/Types/Public/Part.swift index 4890b725f4d..fb743d1025d 100644 --- a/FirebaseAI/Sources/Types/Public/Part.swift +++ b/FirebaseAI/Sources/Types/Public/Part.swift @@ -18,7 +18,14 @@ import Foundation /// /// Within a single value of ``Part``, different data types may not mix. @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) -public protocol Part: PartsRepresentable, Codable, Sendable, Equatable {} +public protocol Part: PartsRepresentable, Codable, Sendable, Equatable { + /// Indicates whether this `Part` is a summary of the model's internal thinking process. + /// + /// When `includeThoughts` is set to `true` in ``ThinkingConfig``, the model may return one or + /// more "thought" parts that provide insight into how it reasoned through the prompt to arrive + /// at the final answer. These parts will have `isThought` set to `true`. + var isThought: Bool { get } +} /// A text part containing a string value. @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) @@ -26,8 +33,20 @@ public struct TextPart: Part { /// Text value. public let text: String + public var isThought: Bool { _isThought ?? false } + + let thoughtSignature: String? + + let _isThought: Bool? + public init(_ text: String) { + self.init(text, isThought: nil, thoughtSignature: nil) + } + + init(_ text: String, isThought: Bool?, thoughtSignature: String?) { self.text = text + _isThought = isThought + self.thoughtSignature = thoughtSignature } } @@ -45,6 +64,7 @@ public struct TextPart: Part { @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct InlineDataPart: Part { let inlineData: InlineData + let _isThought: Bool? /// The data provided in the inline data part. public var data: Data { inlineData.data } @@ -52,6 +72,10 @@ public struct InlineDataPart: Part { /// The IANA standard MIME type of the data. public var mimeType: String { inlineData.mimeType } + public var isThought: Bool { _isThought ?? false } + + let thoughtSignature: String? + /// Creates an inline data part from data and a MIME type. /// /// > Important: Supported input types depend on the model on the model being used; see [input @@ -67,11 +91,13 @@ public struct InlineDataPart: Part { /// requirements](https://firebase.google.com/docs/vertex-ai/input-file-requirements) for /// supported values. public init(data: Data, mimeType: String) { - self.init(InlineData(data: data, mimeType: mimeType)) + self.init(InlineData(data: data, mimeType: mimeType), isThought: nil, thoughtSignature: nil) } - init(_ inlineData: InlineData) { + init(_ inlineData: InlineData, isThought: Bool?, thoughtSignature: String?) { self.inlineData = inlineData + _isThought = isThought + self.thoughtSignature = thoughtSignature } } @@ -79,9 +105,12 @@ public struct InlineDataPart: Part { @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct FileDataPart: Part { let fileData: FileData + let _isThought: Bool? + let thoughtSignature: String? public var uri: String { fileData.fileURI } public var mimeType: String { fileData.mimeType } + public var isThought: Bool { _isThought ?? false } /// Constructs a new file data part. /// @@ -93,11 +122,13 @@ public struct FileDataPart: Part { /// requirements](https://firebase.google.com/docs/vertex-ai/input-file-requirements) for /// supported values. public init(uri: String, mimeType: String) { - self.init(FileData(fileURI: uri, mimeType: mimeType)) + self.init(FileData(fileURI: uri, mimeType: mimeType), isThought: nil, thoughtSignature: nil) } - init(_ fileData: FileData) { + init(_ fileData: FileData, isThought: Bool?, thoughtSignature: String?) { self.fileData = fileData + _isThought = isThought + self.thoughtSignature = thoughtSignature } } @@ -105,6 +136,8 @@ public struct FileDataPart: Part { @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct FunctionCallPart: Part { let functionCall: FunctionCall + let _isThought: Bool? + let thoughtSignature: String? /// The name of the function to call. public var name: String { functionCall.name } @@ -112,6 +145,8 @@ public struct FunctionCallPart: Part { /// The function parameters and values. public var args: JSONObject { functionCall.args } + public var isThought: Bool { _isThought ?? false } + /// Constructs a new function call part. /// /// > Note: A `FunctionCallPart` is typically received from the model, rather than created @@ -121,11 +156,13 @@ public struct FunctionCallPart: Part { /// - name: The name of the function to call. /// - args: The function parameters and values. public init(name: String, args: JSONObject) { - self.init(FunctionCall(name: name, args: args)) + self.init(FunctionCall(name: name, args: args), isThought: nil, thoughtSignature: nil) } - init(_ functionCall: FunctionCall) { + init(_ functionCall: FunctionCall, isThought: Bool?, thoughtSignature: String?) { self.functionCall = functionCall + _isThought = isThought + self.thoughtSignature = thoughtSignature } } @@ -137,6 +174,8 @@ public struct FunctionCallPart: Part { @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct FunctionResponsePart: Part { let functionResponse: FunctionResponse + let _isThought: Bool? + let thoughtSignature: String? /// The name of the function that was called. public var name: String { functionResponse.name } @@ -144,16 +183,22 @@ public struct FunctionResponsePart: Part { /// The function's response or return value. public var response: JSONObject { functionResponse.response } + public var isThought: Bool { _isThought ?? false } + /// Constructs a new `FunctionResponse`. /// /// - Parameters: /// - name: The name of the function that was called. /// - response: The function's response. public init(name: String, response: JSONObject) { - self.init(FunctionResponse(name: name, response: response)) + self.init( + FunctionResponse(name: name, response: response), isThought: nil, thoughtSignature: nil + ) } - init(_ functionResponse: FunctionResponse) { + init(_ functionResponse: FunctionResponse, isThought: Bool?, thoughtSignature: String?) { self.functionResponse = functionResponse + _isThought = isThought + self.thoughtSignature = thoughtSignature } } diff --git a/FirebaseAI/Sources/Types/Public/ThinkingConfig.swift b/FirebaseAI/Sources/Types/Public/ThinkingConfig.swift index c0e8f31465b..a339f8fa1d1 100644 --- a/FirebaseAI/Sources/Types/Public/ThinkingConfig.swift +++ b/FirebaseAI/Sources/Types/Public/ThinkingConfig.swift @@ -37,12 +37,24 @@ public struct ThinkingConfig: Sendable { /// feature or if the specified budget is not within the model's supported range. let thinkingBudget: Int? + /// Whether summaries of the model's "thoughts" are included in responses. + /// + /// When `includeThoughts` is set to `true`, the model will return a summary of its internal + /// thinking process alongside the final answer. This can provide valuable insight into how the + /// model arrived at its conclusion, which is particularly useful for complex or creative tasks. + /// + /// If you don't specify a value for `includeThoughts` (`nil`), the model will use its default + /// behavior (which is typically to not include thought summaries). + let includeThoughts: Bool? + /// Initializes a new `ThinkingConfig`. /// /// - Parameters: /// - thinkingBudget: The maximum number of tokens to be used for the model's thinking process. - public init(thinkingBudget: Int? = nil) { + /// - includeThoughts: If true, summaries of the model's "thoughts" are included in responses. + public init(thinkingBudget: Int? = nil, includeThoughts: Bool? = nil) { self.thinkingBudget = thinkingBudget + self.includeThoughts = includeThoughts } } diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift index d83c300623d..61bcf240442 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift @@ -134,47 +134,83 @@ struct GenerateContentIntegrationTests { #expect(candidatesTokensDetails.tokenCount == usageMetadata.candidatesTokenCount) } - @Test(arguments: [ - (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2_5_Flash, 0), - (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2_5_Flash, 24576), - (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2_5_Pro, 128), - (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2_5_Pro, 32768), - (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_Flash, 0), - (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_Flash, 24576), - (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_Pro, 128), - (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_Pro, 32768), - (InstanceConfig.googleAI_v1beta_freeTier, ModelNames.gemini2_5_Flash, 0), - (InstanceConfig.googleAI_v1beta_freeTier, ModelNames.gemini2_5_Flash, 24576), - ]) + @Test( + arguments: [ + (.vertexAI_v1beta, ModelNames.gemini2_5_Flash, ThinkingConfig(thinkingBudget: 0)), + (.vertexAI_v1beta, ModelNames.gemini2_5_Flash, ThinkingConfig(thinkingBudget: 24576)), + (.vertexAI_v1beta, ModelNames.gemini2_5_Flash, ThinkingConfig( + thinkingBudget: 24576, includeThoughts: true + )), + (.vertexAI_v1beta_global, ModelNames.gemini2_5_Pro, ThinkingConfig(thinkingBudget: 128)), + (.vertexAI_v1beta_global, ModelNames.gemini2_5_Pro, ThinkingConfig(thinkingBudget: 32768)), + (.vertexAI_v1beta_global, ModelNames.gemini2_5_Pro, ThinkingConfig( + thinkingBudget: 32768, includeThoughts: true + )), + (.googleAI_v1beta, ModelNames.gemini2_5_Flash, ThinkingConfig(thinkingBudget: 0)), + (.googleAI_v1beta, ModelNames.gemini2_5_Flash, ThinkingConfig(thinkingBudget: 24576)), + (.googleAI_v1beta, ModelNames.gemini2_5_Flash, ThinkingConfig( + thinkingBudget: 24576, includeThoughts: true + )), + (.googleAI_v1beta, ModelNames.gemini2_5_Pro, ThinkingConfig(thinkingBudget: 128)), + (.googleAI_v1beta, ModelNames.gemini2_5_Pro, ThinkingConfig(thinkingBudget: 32768)), + (.googleAI_v1beta, ModelNames.gemini2_5_Pro, ThinkingConfig( + thinkingBudget: 32768, includeThoughts: true + )), + (.googleAI_v1beta_freeTier, ModelNames.gemini2_5_Flash, ThinkingConfig(thinkingBudget: 0)), + ( + .googleAI_v1beta_freeTier, + ModelNames.gemini2_5_Flash, + ThinkingConfig(thinkingBudget: 24576) + ), + (.googleAI_v1beta_freeTier, ModelNames.gemini2_5_Flash, ThinkingConfig( + thinkingBudget: 24576, includeThoughts: true + )), + (.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2_5_Flash, ThinkingConfig( + thinkingBudget: 0 + )), + (.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2_5_Flash, ThinkingConfig( + thinkingBudget: 24576 + )), + (.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2_5_Flash, ThinkingConfig( + thinkingBudget: 24576, includeThoughts: true + )), + ] as [(InstanceConfig, String, ThinkingConfig)] + ) func generateContentThinking(_ config: InstanceConfig, modelName: String, - thinkingBudget: Int) async throws { + thinkingConfig: ThinkingConfig) async throws { let model = FirebaseAI.componentInstance(config).generativeModel( modelName: modelName, generationConfig: GenerationConfig( temperature: 0.0, topP: 0.0, topK: 1, - thinkingConfig: ThinkingConfig(thinkingBudget: thinkingBudget) + thinkingConfig: thinkingConfig ), safetySettings: safetySettings ) + let chat = model.startChat() let prompt = "Where is Google headquarters located? Answer with the city name only." - let response = try await model.generateContent(prompt) + let response = try await chat.sendMessage(prompt) let text = try #require(response.text).trimmingCharacters(in: .whitespacesAndNewlines) #expect(text == "Mountain View") + let candidate = try #require(response.candidates.first) + let thoughtParts = candidate.content.parts.compactMap { $0.isThought ? $0 : nil } + #expect(thoughtParts.isEmpty != (thinkingConfig.includeThoughts ?? false)) + let usageMetadata = try #require(response.usageMetadata) #expect(usageMetadata.promptTokenCount.isEqual(to: 13, accuracy: tokenCountAccuracy)) #expect(usageMetadata.promptTokensDetails.count == 1) let promptTokensDetails = try #require(usageMetadata.promptTokensDetails.first) #expect(promptTokensDetails.modality == .text) #expect(promptTokensDetails.tokenCount == usageMetadata.promptTokenCount) - if thinkingBudget == 0 { - #expect(usageMetadata.thoughtsTokenCount == 0) - } else { + if let thinkingBudget = thinkingConfig.thinkingBudget, thinkingBudget > 0 { + #expect(usageMetadata.thoughtsTokenCount > 0) #expect(usageMetadata.thoughtsTokenCount <= thinkingBudget) + } else { + #expect(usageMetadata.thoughtsTokenCount == 0) } #expect(usageMetadata.candidatesTokenCount.isEqual(to: 3, accuracy: tokenCountAccuracy)) // The `candidatesTokensDetails` field is erroneously omitted when using the Google AI (Gemini @@ -195,6 +231,90 @@ struct GenerateContentIntegrationTests { )) } + @Test( + arguments: [ + (.vertexAI_v1beta_global, ModelNames.gemini2_5_Flash, ThinkingConfig(thinkingBudget: -1)), + (.vertexAI_v1beta_global, ModelNames.gemini2_5_Flash, ThinkingConfig( + thinkingBudget: -1, includeThoughts: true + )), + (.vertexAI_v1beta_global, ModelNames.gemini2_5_Pro, ThinkingConfig(thinkingBudget: -1)), + (.vertexAI_v1beta_global, ModelNames.gemini2_5_Pro, ThinkingConfig( + thinkingBudget: -1, includeThoughts: true + )), + (.googleAI_v1beta, ModelNames.gemini2_5_Flash, ThinkingConfig(thinkingBudget: -1)), + (.googleAI_v1beta, ModelNames.gemini2_5_Flash, ThinkingConfig( + thinkingBudget: -1, includeThoughts: true + )), + (.googleAI_v1beta, ModelNames.gemini2_5_Pro, ThinkingConfig(thinkingBudget: -1)), + (.googleAI_v1beta, ModelNames.gemini2_5_Pro, ThinkingConfig( + thinkingBudget: -1, includeThoughts: true + )), + ] as [(InstanceConfig, String, ThinkingConfig)] + ) + func generateContentThinkingFunctionCalling(_ config: InstanceConfig, modelName: String, + thinkingConfig: ThinkingConfig) async throws { + let getTemperatureDeclaration = FunctionDeclaration( + name: "getTemperature", + description: "Returns the current temperature in Celsius for the specified location", + parameters: [ + "city": .string(), + "region": .string(description: "The province or state"), + "country": .string(), + ] + ) + let model = FirebaseAI.componentInstance(config).generativeModel( + modelName: modelName, + generationConfig: GenerationConfig( + temperature: 0.0, + topP: 0.0, + topK: 1, + thinkingConfig: thinkingConfig + ), + safetySettings: safetySettings, + tools: [.functionDeclarations([getTemperatureDeclaration])], + systemInstruction: ModelContent(parts: """ + You are a weather bot that specializes in reporting outdoor temperatures in Celsius. + + Always use the `getTemperature` function to determine the current temperature in a location. + + Always respond in the format: + - Location: City, Province/State, Country + - Temperature: #C + """) + ) + let chat = model.startChat() + let prompt = "What is the current temperature in Waterloo, Ontario, Canada?" + + let response = try await chat.sendMessage(prompt) + + #expect(response.functionCalls.count == 1) + let temperatureFunctionCall = try #require(response.functionCalls.first) + try #require(temperatureFunctionCall.name == getTemperatureDeclaration.name) + #expect(temperatureFunctionCall.args == [ + "city": .string("Waterloo"), + "region": .string("Ontario"), + "country": .string("Canada"), + ]) + #expect(temperatureFunctionCall.isThought == false) + let thoughtSignature = try #require(temperatureFunctionCall.thoughtSignature) + #expect(!thoughtSignature.isEmpty) + + let temperatureFunctionResponse = FunctionResponsePart( + name: temperatureFunctionCall.name, + response: [ + "temperature": .number(25), + "units": .string("Celsius"), + ] + ) + + let response2 = try await chat.sendMessage(temperatureFunctionResponse) + + #expect(response2.functionCalls.isEmpty) + let finalText = try #require(response2.text).trimmingCharacters(in: .whitespacesAndNewlines) + #expect(finalText.contains("Waterloo")) + #expect(finalText.contains("25")) + } + @Test(arguments: [ InstanceConfig.vertexAI_v1beta, InstanceConfig.vertexAI_v1beta_global, diff --git a/FirebaseAI/Tests/Unit/GenerativeModelGoogleAITests.swift b/FirebaseAI/Tests/Unit/GenerativeModelGoogleAITests.swift index 103943e6f92..00e0d398855 100644 --- a/FirebaseAI/Tests/Unit/GenerativeModelGoogleAITests.swift +++ b/FirebaseAI/Tests/Unit/GenerativeModelGoogleAITests.swift @@ -262,6 +262,52 @@ final class GenerativeModelGoogleAITests: XCTestCase { ) } + func testGenerateContent_success_thinking_thoughtSummary() async throws { + MockURLProtocol.requestHandler = try GenerativeModelTestUtil.httpRequestHandler( + forResource: "unary-success-thinking-reply-thought-summary", + withExtension: "json", + subdirectory: googleAISubdirectory + ) + + let response = try await model.generateContent(testPrompt) + + XCTAssertEqual(response.candidates.count, 1) + let candidate = try XCTUnwrap(response.candidates.first) + XCTAssertEqual(candidate.content.parts.count, 2) + let thoughtPart = try XCTUnwrap(candidate.content.parts.first as? TextPart) + XCTAssertTrue(thoughtPart.isThought) + XCTAssertTrue(thoughtPart.text.hasPrefix("**Thinking About Google's Headquarters**")) + XCTAssertEqual(thoughtPart.text, response.thoughtSummary) + let textPart = try XCTUnwrap(candidate.content.parts.last as? TextPart) + XCTAssertFalse(textPart.isThought) + XCTAssertEqual(textPart.text, "Mountain View") + XCTAssertEqual(textPart.text, response.text) + } + + func testGenerateContent_success_thinking_functionCall_thoughtSummaryAndSignature() async throws { + MockURLProtocol.requestHandler = try GenerativeModelTestUtil.httpRequestHandler( + forResource: "unary-success-thinking-function-call-thought-summary-signature", + withExtension: "json", + subdirectory: googleAISubdirectory + ) + + let response = try await model.generateContent(testPrompt) + + XCTAssertEqual(response.candidates.count, 1) + let candidate = try XCTUnwrap(response.candidates.first) + XCTAssertEqual(candidate.finishReason, .stop) + XCTAssertEqual(candidate.content.parts.count, 2) + let thoughtPart = try XCTUnwrap(candidate.content.parts.first as? TextPart) + XCTAssertTrue(thoughtPart.isThought) + XCTAssertTrue(thoughtPart.text.hasPrefix("**Thinking Through the New Year's Eve Calculation**")) + let functionCallPart = try XCTUnwrap(candidate.content.parts.last as? FunctionCallPart) + XCTAssertFalse(functionCallPart.isThought) + XCTAssertEqual(functionCallPart.name, "now") + XCTAssertTrue(functionCallPart.args.isEmpty) + let thoughtSignature = try XCTUnwrap(functionCallPart.thoughtSignature) + XCTAssertTrue(thoughtSignature.hasPrefix("CtQOAVSoXO74PmYr9AFu")) + } + func testGenerateContent_failure_invalidAPIKey() async throws { let expectedStatusCode = 400 MockURLProtocol.requestHandler = try GenerativeModelTestUtil.httpRequestHandler( @@ -397,6 +443,72 @@ final class GenerativeModelGoogleAITests: XCTestCase { XCTAssertNil(citation.publicationDate) } + func testGenerateContentStream_successWithThoughtSummary() async throws { + MockURLProtocol.requestHandler = try GenerativeModelTestUtil.httpRequestHandler( + forResource: "streaming-success-thinking-reply-thought-summary", + withExtension: "txt", + subdirectory: googleAISubdirectory + ) + + var thoughtSummary = "" + var text = "" + let stream = try model.generateContentStream("Hi") + for try await response in stream { + let candidate = try XCTUnwrap(response.candidates.first) + XCTAssertEqual(candidate.content.parts.count, 1) + let textPart = try XCTUnwrap(candidate.content.parts.first as? TextPart) + if textPart.isThought { + let newThought = try XCTUnwrap(response.thoughtSummary) + XCTAssertEqual(textPart.text, newThought) + thoughtSummary.append(newThought) + } else { + let newText = try XCTUnwrap(response.text) + XCTAssertEqual(textPart.text, newText) + text.append(newText) + } + } + + XCTAssertTrue(thoughtSummary.hasPrefix("**Exploring Sky Color**")) + XCTAssertTrue(text.hasPrefix("The sky is blue because")) + } + + func testGenerateContentStream_success_thinking_functionCall_thoughtSummary_signature() async throws { + MockURLProtocol.requestHandler = try GenerativeModelTestUtil.httpRequestHandler( + forResource: "streaming-success-thinking-function-call-thought-summary-signature", + withExtension: "txt", + subdirectory: googleAISubdirectory + ) + + var thoughtSummary = "" + var functionCalls: [FunctionCallPart] = [] + let stream = try model.generateContentStream("Hi") + for try await response in stream { + let candidate = try XCTUnwrap(response.candidates.first) + XCTAssertEqual(candidate.content.parts.count, 1) + let part = try XCTUnwrap(candidate.content.parts.first) + if part.isThought { + let textPart = try XCTUnwrap(part as? TextPart) + let newThought = try XCTUnwrap(response.thoughtSummary) + XCTAssertEqual(textPart.text, newThought) + thoughtSummary.append(newThought) + } else { + let functionCallPart = try XCTUnwrap(part as? FunctionCallPart) + XCTAssertEqual(response.functionCalls.count, 1) + let newFunctionCall = try XCTUnwrap(response.functionCalls.first) + XCTAssertEqual(functionCallPart, newFunctionCall) + functionCalls.append(newFunctionCall) + } + } + + XCTAssertTrue(thoughtSummary.hasPrefix("**Calculating the Days**")) + XCTAssertEqual(functionCalls.count, 1) + let functionCall = try XCTUnwrap(functionCalls.first) + XCTAssertEqual(functionCall.name, "now") + XCTAssertTrue(functionCall.args.isEmpty) + let thoughtSignature = try XCTUnwrap(functionCall.thoughtSignature) + XCTAssertTrue(thoughtSignature.hasPrefix("CiIBVKhc7vB+vaaq6rA")) + } + func testGenerateContentStream_failureInvalidAPIKey() async throws { MockURLProtocol.requestHandler = try GenerativeModelTestUtil.httpRequestHandler( forResource: "unary-failure-api-key", diff --git a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift index 6557735ccc4..7c23726f152 100644 --- a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift +++ b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift @@ -434,6 +434,29 @@ final class GenerativeModelVertexAITests: XCTestCase { XCTAssertEqual(text, "The sum of [1, 2, 3] is") } + func testGenerateContent_success_thinking_thoughtSummary() async throws { + MockURLProtocol.requestHandler = try GenerativeModelTestUtil.httpRequestHandler( + forResource: "unary-success-thinking-reply-thought-summary", + withExtension: "json", + subdirectory: vertexSubdirectory + ) + + let response = try await model.generateContent(testPrompt) + + XCTAssertEqual(response.candidates.count, 1) + let candidate = try XCTUnwrap(response.candidates.first) + XCTAssertEqual(candidate.finishReason, .stop) + XCTAssertEqual(candidate.content.parts.count, 2) + let thoughtPart = try XCTUnwrap(candidate.content.parts.first as? TextPart) + XCTAssertTrue(thoughtPart.isThought) + XCTAssertTrue(thoughtPart.text.hasPrefix("Right, someone needs the city where Google")) + XCTAssertEqual(response.thoughtSummary, thoughtPart.text) + let textPart = try XCTUnwrap(candidate.content.parts.last as? TextPart) + XCTAssertFalse(textPart.isThought) + XCTAssertEqual(textPart.text, "Mountain View") + XCTAssertEqual(response.text, textPart.text) + } + func testGenerateContent_success_image_invalidSafetyRatingsIgnored() async throws { MockURLProtocol.requestHandler = try GenerativeModelTestUtil.httpRequestHandler( forResource: "unary-success-image-invalid-safety-ratings", @@ -1330,6 +1353,33 @@ final class GenerativeModelVertexAITests: XCTestCase { XCTAssertFalse(citations.contains { $0.license?.isEmpty ?? false }) } + func testGenerateContentStream_successWithThinking_thoughtSummary() async throws { + MockURLProtocol.requestHandler = try GenerativeModelTestUtil.httpRequestHandler( + forResource: "streaming-success-thinking-reply-thought-summary", + withExtension: "txt", + subdirectory: vertexSubdirectory + ) + + var thoughtSummary = "" + var text = "" + let stream = try model.generateContentStream("Hi") + for try await response in stream { + let candidate = try XCTUnwrap(response.candidates.first) + XCTAssertEqual(candidate.content.parts.count, 1) + let part = try XCTUnwrap(candidate.content.parts.first) + let textPart = try XCTUnwrap(part as? TextPart) + if textPart.isThought { + let newThought = try XCTUnwrap(response.thoughtSummary) + thoughtSummary.append(newThought) + } else { + text.append(textPart.text) + } + } + + XCTAssertTrue(thoughtSummary.hasPrefix("**Understanding the Core Question**")) + XCTAssertTrue(text.hasPrefix("The sky is blue due to a phenomenon")) + } + func testGenerateContentStream_successWithInvalidSafetyRatingsIgnored() async throws { MockURLProtocol.requestHandler = try GenerativeModelTestUtil.httpRequestHandler( forResource: "streaming-success-image-invalid-safety-ratings", diff --git a/FirebaseAI/Tests/Unit/Types/InternalPartTests.swift b/FirebaseAI/Tests/Unit/Types/InternalPartTests.swift new file mode 100644 index 00000000000..2cd5c5fee2a --- /dev/null +++ b/FirebaseAI/Tests/Unit/Types/InternalPartTests.swift @@ -0,0 +1,286 @@ +// Copyright 2024 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. + +@testable import FirebaseAI +import XCTest + +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +final class InternalPartTests: XCTestCase { + let decoder = JSONDecoder() + + func testDecodeTextPartWithThought() throws { + let json = """ + { + "text": "This is a thought.", + "thought": true + } + """ + let jsonData = try XCTUnwrap(json.data(using: .utf8)) + + let part = try decoder.decode(InternalPart.self, from: jsonData) + + XCTAssertEqual(part.isThought, true) + guard case let .text(text) = part.data else { + XCTFail("Decoded part is not a text part.") + return + } + XCTAssertEqual(text, "This is a thought.") + } + + func testDecodeTextPartWithoutThought() throws { + let json = """ + { + "text": "This is not a thought." + } + """ + let jsonData = try XCTUnwrap(json.data(using: .utf8)) + + let part = try decoder.decode(InternalPart.self, from: jsonData) + + XCTAssertNil(part.isThought) + guard case let .text(text) = part.data else { + XCTFail("Decoded part is not a text part.") + return + } + XCTAssertEqual(text, "This is not a thought.") + } + + func testDecodeInlineDataPartWithThought() throws { + let imageBase64 = + "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg==" + let mimeType = "image/png" + let json = """ + { + "inlineData": { + "mimeType": "\(mimeType)", + "data": "\(imageBase64)" + }, + "thought": true + } + """ + let jsonData = try XCTUnwrap(json.data(using: .utf8)) + + let part = try decoder.decode(InternalPart.self, from: jsonData) + + XCTAssertEqual(part.isThought, true) + guard case let .inlineData(inlineData) = part.data else { + XCTFail("Decoded part is not an inlineData part.") + return + } + XCTAssertEqual(inlineData.mimeType, mimeType) + XCTAssertEqual(inlineData.data, Data(base64Encoded: imageBase64)) + } + + func testDecodeInlineDataPartWithoutThought() throws { + let imageBase64 = "aGVsbG8=" + let mimeType = "image/png" + let json = """ + { + "inlineData": { + "mimeType": "\(mimeType)", + "data": "\(imageBase64)" + } + } + """ + let jsonData = try XCTUnwrap(json.data(using: .utf8)) + + let part = try decoder.decode(InternalPart.self, from: jsonData) + + XCTAssertNil(part.isThought) + guard case let .inlineData(inlineData) = part.data else { + XCTFail("Decoded part is not an inlineData part.") + return + } + XCTAssertEqual(inlineData.mimeType, mimeType) + XCTAssertEqual(inlineData.data, Data(base64Encoded: imageBase64)) + } + + func testDecodeFileDataPartWithThought() throws { + let uri = "file:///path/to/file.mp3" + let mimeType = "audio/mpeg" + let json = """ + { + "fileData": { + "fileUri": "\(uri)", + "mimeType": "\(mimeType)" + }, + "thought": true + } + """ + let jsonData = try XCTUnwrap(json.data(using: .utf8)) + + let part = try decoder.decode(InternalPart.self, from: jsonData) + + XCTAssertEqual(part.isThought, true) + guard case let .fileData(fileData) = part.data else { + XCTFail("Decoded part is not a fileData part.") + return + } + XCTAssertEqual(fileData.fileURI, uri) + XCTAssertEqual(fileData.mimeType, mimeType) + } + + func testDecodeFileDataPartWithoutThought() throws { + let uri = "file:///path/to/file.mp3" + let mimeType = "audio/mpeg" + let json = """ + { + "fileData": { + "fileUri": "\(uri)", + "mimeType": "\(mimeType)" + } + } + """ + let jsonData = try XCTUnwrap(json.data(using: .utf8)) + + let part = try decoder.decode(InternalPart.self, from: jsonData) + + XCTAssertNil(part.isThought) + guard case let .fileData(fileData) = part.data else { + XCTFail("Decoded part is not a fileData part.") + return + } + XCTAssertEqual(fileData.fileURI, uri) + XCTAssertEqual(fileData.mimeType, mimeType) + } + + func testDecodeFunctionCallPartWithThoughtSignature() throws { + let functionName = "someFunction" + let expectedThoughtSignature = "some_signature" + let json = """ + { + "functionCall": { + "name": "\(functionName)", + "args": { + "arg1": "value1" + }, + }, + "thoughtSignature": "\(expectedThoughtSignature)" + } + """ + let jsonData = try XCTUnwrap(json.data(using: .utf8)) + + let part = try decoder.decode(InternalPart.self, from: jsonData) + + let thoughtSignature = try XCTUnwrap(part.thoughtSignature) + XCTAssertEqual(thoughtSignature, expectedThoughtSignature) + XCTAssertNil(part.isThought) + guard case let .functionCall(functionCall) = part.data else { + XCTFail("Decoded part is not a functionCall part.") + return + } + XCTAssertEqual(functionCall.name, functionName) + XCTAssertEqual(functionCall.args, ["arg1": .string("value1")]) + } + + func testDecodeFunctionCallPartWithoutThoughtSignature() throws { + let functionName = "someFunction" + let json = """ + { + "functionCall": { + "name": "\(functionName)", + "args": { + "arg1": "value1" + } + } + } + """ + let jsonData = try XCTUnwrap(json.data(using: .utf8)) + + let part = try decoder.decode(InternalPart.self, from: jsonData) + + XCTAssertNil(part.isThought) + XCTAssertNil(part.thoughtSignature) + guard case let .functionCall(functionCall) = part.data else { + XCTFail("Decoded part is not a functionCall part.") + return + } + XCTAssertEqual(functionCall.name, functionName) + XCTAssertEqual(functionCall.args, ["arg1": .string("value1")]) + } + + func testDecodeFunctionCallPartWithoutArgs() throws { + let functionName = "someFunction" + let json = """ + { + "functionCall": { + "name": "\(functionName)" + } + } + """ + let jsonData = try XCTUnwrap(json.data(using: .utf8)) + + let part = try decoder.decode(InternalPart.self, from: jsonData) + + XCTAssertNil(part.isThought) + XCTAssertNil(part.thoughtSignature) + guard case let .functionCall(functionCall) = part.data else { + XCTFail("Decoded part is not a functionCall part.") + return + } + XCTAssertEqual(functionCall.name, functionName) + XCTAssertEqual(functionCall.args, JSONObject()) + } + + func testDecodeFunctionResponsePartWithThought() throws { + let functionName = "someFunction" + let json = """ + { + "functionResponse": { + "name": "\(functionName)", + "response": { + "output": "someValue" + } + }, + "thought": true + } + """ + let jsonData = try XCTUnwrap(json.data(using: .utf8)) + + let part = try decoder.decode(InternalPart.self, from: jsonData) + + XCTAssertEqual(part.isThought, true) + guard case let .functionResponse(functionResponse) = part.data else { + XCTFail("Decoded part is not a functionResponse part.") + return + } + XCTAssertEqual(functionResponse.name, functionName) + XCTAssertEqual(functionResponse.response, ["output": .string("someValue")]) + } + + func testDecodeFunctionResponsePartWithoutThought() throws { + let functionName = "someFunction" + let json = """ + { + "functionResponse": { + "name": "\(functionName)", + "response": { + "output": "someValue" + } + } + } + """ + let jsonData = try XCTUnwrap(json.data(using: .utf8)) + + let part = try decoder.decode(InternalPart.self, from: jsonData) + + XCTAssertNil(part.isThought) + guard case let .functionResponse(functionResponse) = part.data else { + XCTFail("Decoded part is not a functionResponse part.") + return + } + XCTAssertEqual(functionResponse.name, functionName) + XCTAssertEqual(functionResponse.response, ["output": .string("someValue")]) + } +} From e5962228d77cf20c2795a65d9ad85f91aa3e1082 Mon Sep 17 00:00:00 2001 From: pcfba <111909874+pcfba@users.noreply.github.com> Date: Tue, 19 Aug 2025 10:42:26 -0700 Subject: [PATCH 39/76] Fix Readme template indentation in ReleaseTooling (#15228) --- ReleaseTooling/Template/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ReleaseTooling/Template/README.md b/ReleaseTooling/Template/README.md index 2c97c76f470..495301380e2 100644 --- a/ReleaseTooling/Template/README.md +++ b/ReleaseTooling/Template/README.md @@ -70,15 +70,15 @@ To integrate a Firebase SDK with your app: 10. If you're using Firebase Analytics, disable GoogleAdsOnDeviceConversion.xcframework for Mac Catalyst: - a. In your project settings, open the **Settings** panel for your target. + a. In your project settings, open the **Settings** panel for your target. - b. Go to the Build Phases tab and find the - **GoogleAdsOnDeviceConversion.xcframework** setting in the **Link Binary - With Libraries** section. + b. Go to the Build Phases tab and find the + **GoogleAdsOnDeviceConversion.xcframework** setting in the **Link Binary + With Libraries** section. - c. Click on the filter icon button in the - **GoogleAdsOnDeviceConversion.xcframework** row and deselect the Mac Catalyst - checkbox. + c. Click on the filter icon button in the + **GoogleAdsOnDeviceConversion.xcframework** row and deselect the Mac Catalyst + checkbox. 11. Drag the `Firebase.h` header in this directory into your project. This will allow you to `#import "Firebase.h"` and start using any Firebase SDK that you From 6706aa8fd87a49d580563dffa69fae5af4f1bdfb Mon Sep 17 00:00:00 2001 From: Daymon <17409137+daymxn@users.noreply.github.com> Date: Tue, 19 Aug 2025 17:50:13 -0500 Subject: [PATCH 40/76] [FAL] Add limited-use token support (#15099) --- FirebaseAI/CHANGELOG.md | 7 +++ FirebaseAI/Sources/FirebaseAI.swift | 54 ++++++++++++++++--- FirebaseAI/Sources/GenerativeAIService.swift | 54 ++++++++++++++++++- FirebaseAI/Sources/GenerativeModel.swift | 8 ++- .../Types/Public/Imagen/ImagenModel.swift | 6 ++- .../Tests/Utilities/InstanceConfig.swift | 6 ++- .../Unit/Fakes/AppCheckInteropFake.swift | 11 ++-- .../Unit/GenerativeModelVertexAITests.swift | 25 +++++++++ FirebaseAI/Tests/Unit/README.md | 2 +- .../Tests/Unit/VertexComponentTests.swift | 30 ++++++++--- .../FIRAppCheckTokenResultInterop.h | 1 + .../Sources/Core/FIRAppCheckTokenResult.h | 1 + 12 files changed, 179 insertions(+), 26 deletions(-) diff --git a/FirebaseAI/CHANGELOG.md b/FirebaseAI/CHANGELOG.md index ea7fd44941e..b5f3199a797 100644 --- a/FirebaseAI/CHANGELOG.md +++ b/FirebaseAI/CHANGELOG.md @@ -1,6 +1,13 @@ # 12.2.0 - [feature] Added support for returning thought summaries, which are synthesized versions of a model's internal reasoning process. (#15096) +- [feature] Added a new configuration option to use limited-use App + Check tokens for attesting Firebase AI Logic requests. This enhances + security against replay attacks. To use this feature, configure it + explicitly via the new `useLimitedUseAppCheckTokens` parameter when + initializing `FirebaseAI`. We recommend migrating to limited-use + tokens now, so your app will be ready to take advantage of replay + protection when it becomes available for Firebase AI Logic. (#15099) # 12.0.0 - [feature] Added support for Grounding with Google Search. (#15014) diff --git a/FirebaseAI/Sources/FirebaseAI.swift b/FirebaseAI/Sources/FirebaseAI.swift index 48f7183d4e6..d4c2e9d545d 100644 --- a/FirebaseAI/Sources/FirebaseAI.swift +++ b/FirebaseAI/Sources/FirebaseAI.swift @@ -32,13 +32,33 @@ public final class FirebaseAI: Sendable { /// ``FirebaseApp``. /// - backend: The backend API for the Firebase AI SDK; if not specified, uses the default /// ``Backend/googleAI()`` (Gemini Developer API). + /// - useLimitedUseAppCheckTokens: When sending tokens to the backend, this option enables + /// the usage of App Check's limited-use tokens instead of the standard cached tokens. + /// + /// A new limited-use tokens will be generated for each request; providing a smaller attack + /// surface for malicious parties to hijack tokens. When used alongside replay protection, + /// limited-use tokens are also _consumed_ after each request, ensuring they can't be used + /// again. + /// + /// _This flag is set to `false` by default._ + /// + /// > Important: Replay protection is not currently supported for the FirebaseAI backend. + /// > While this feature is being developed, you can still migrate to using + /// > limited-use tokens. Because limited-use tokens are backwards compatible, you can still + /// > use them without replay protection. Due to their shorter TTL over standard App Check + /// > tokens, they still provide a security benefit. + /// > + /// > Migrating to limited-use tokens sooner minimizes disruption when support for replay + /// > protection is added. /// - Returns: A `FirebaseAI` instance, configured with the custom `FirebaseApp`. public static func firebaseAI(app: FirebaseApp? = nil, - backend: Backend = .googleAI()) -> FirebaseAI { + backend: Backend = .googleAI(), + useLimitedUseAppCheckTokens: Bool = false) -> FirebaseAI { let instance = createInstance( app: app, location: backend.location, - apiConfig: backend.apiConfig + apiConfig: backend.apiConfig, + useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens ) // Verify that the `FirebaseAI` instance is always configured with the production endpoint since // this is the public API surface for creating an instance. @@ -90,7 +110,8 @@ public final class FirebaseAI: Sendable { tools: tools, toolConfig: toolConfig, systemInstruction: systemInstruction, - requestOptions: requestOptions + requestOptions: requestOptions, + useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens ) } @@ -126,7 +147,8 @@ public final class FirebaseAI: Sendable { apiConfig: apiConfig, generationConfig: generationConfig, safetySettings: safetySettings, - requestOptions: requestOptions + requestOptions: requestOptions, + useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens ) } @@ -141,6 +163,8 @@ public final class FirebaseAI: Sendable { let apiConfig: APIConfig + let useLimitedUseAppCheckTokens: Bool + /// A map of active `FirebaseAI` instances keyed by the `FirebaseApp` name and the `location`, /// in the format `appName:location`. private nonisolated(unsafe) static var instances: [InstanceKey: FirebaseAI] = [:] @@ -156,7 +180,8 @@ public final class FirebaseAI: Sendable { ) static func createInstance(app: FirebaseApp?, location: String?, - apiConfig: APIConfig) -> FirebaseAI { + apiConfig: APIConfig, + useLimitedUseAppCheckTokens: Bool) -> FirebaseAI { guard let app = app ?? FirebaseApp.app() else { fatalError("No instance of the default Firebase app was found.") } @@ -166,16 +191,27 @@ public final class FirebaseAI: Sendable { // Unlock before the function returns. defer { os_unfair_lock_unlock(&instancesLock) } - let instanceKey = InstanceKey(appName: app.name, location: location, apiConfig: apiConfig) + let instanceKey = InstanceKey( + appName: app.name, + location: location, + apiConfig: apiConfig, + useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens + ) if let instance = instances[instanceKey] { return instance } - let newInstance = FirebaseAI(app: app, location: location, apiConfig: apiConfig) + let newInstance = FirebaseAI( + app: app, + location: location, + apiConfig: apiConfig, + useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens + ) instances[instanceKey] = newInstance return newInstance } - init(app: FirebaseApp, location: String?, apiConfig: APIConfig) { + init(app: FirebaseApp, location: String?, apiConfig: APIConfig, + useLimitedUseAppCheckTokens: Bool) { guard let projectID = app.options.projectID else { fatalError("The Firebase app named \"\(app.name)\" has no project ID in its configuration.") } @@ -195,6 +231,7 @@ public final class FirebaseAI: Sendable { ) self.apiConfig = apiConfig self.location = location + self.useLimitedUseAppCheckTokens = useLimitedUseAppCheckTokens } func modelResourceName(modelName: String) -> String { @@ -249,5 +286,6 @@ public final class FirebaseAI: Sendable { let appName: String let location: String? let apiConfig: APIConfig + let useLimitedUseAppCheckTokens: Bool } } diff --git a/FirebaseAI/Sources/GenerativeAIService.swift b/FirebaseAI/Sources/GenerativeAIService.swift index e1538af997f..5b676162c94 100644 --- a/FirebaseAI/Sources/GenerativeAIService.swift +++ b/FirebaseAI/Sources/GenerativeAIService.swift @@ -30,9 +30,12 @@ struct GenerativeAIService { private let urlSession: URLSession - init(firebaseInfo: FirebaseInfo, urlSession: URLSession) { + private let useLimitedUseAppCheckTokens: Bool + + init(firebaseInfo: FirebaseInfo, urlSession: URLSession, useLimitedUseAppCheckTokens: Bool) { self.firebaseInfo = firebaseInfo self.urlSession = urlSession + self.useLimitedUseAppCheckTokens = useLimitedUseAppCheckTokens } func loadRequest(request: T) async throws -> T.Response { @@ -177,7 +180,7 @@ struct GenerativeAIService { urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") if let appCheck = firebaseInfo.appCheck { - let tokenResult = await appCheck.getToken(forcingRefresh: false) + let tokenResult = try await fetchAppCheckToken(appCheck: appCheck) urlRequest.setValue(tokenResult.token, forHTTPHeaderField: "X-Firebase-AppCheck") if let error = tokenResult.error { AILog.error( @@ -207,6 +210,53 @@ struct GenerativeAIService { return urlRequest } + private func fetchAppCheckToken(appCheck: AppCheckInterop) async throws + -> FIRAppCheckTokenResultInterop { + if useLimitedUseAppCheckTokens { + if let token = await getLimitedUseAppCheckToken(appCheck: appCheck) { + return token + } + + let errorMessage = + "The provided App Check token provider doesn't implement getLimitedUseToken(), but requireLimitedUseTokens was enabled." + + #if Debug + fatalError(errorMessage) + #else + throw NSError( + domain: "\(Constants.baseErrorDomain).\(Self.self)", + code: AILog.MessageCode.appCheckTokenFetchFailed.rawValue, + userInfo: [NSLocalizedDescriptionKey: errorMessage] + ) + #endif + } + + return await appCheck.getToken(forcingRefresh: false) + } + + private func getLimitedUseAppCheckToken(appCheck: AppCheckInterop) async + -> FIRAppCheckTokenResultInterop? { + // At the moment, `await` doesn’t get along with Objective-C’s optional protocol methods. + await withCheckedContinuation { (continuation: CheckedContinuation< + FIRAppCheckTokenResultInterop?, + Never + >) in + guard + useLimitedUseAppCheckTokens, + // `getLimitedUseToken(completion:)` is an optional protocol method. Optional binding + // is performed to make sure `continuation` is called even if the method’s not implemented. + let limitedUseTokenClosure = appCheck.getLimitedUseToken + else { + return continuation.resume(returning: nil) + } + + limitedUseTokenClosure { tokenResult in + // The placeholder token should be used in the case of App Check error. + continuation.resume(returning: tokenResult) + } + } + } + private func httpResponse(urlResponse: URLResponse) throws -> HTTPURLResponse { // The following condition should always be true: "Whenever you make HTTP URL load requests, any // response objects you get back from the URLSession, NSURLConnection, or NSURLDownload class diff --git a/FirebaseAI/Sources/GenerativeModel.swift b/FirebaseAI/Sources/GenerativeModel.swift index 8d3f5e043a7..2807022de59 100644 --- a/FirebaseAI/Sources/GenerativeModel.swift +++ b/FirebaseAI/Sources/GenerativeModel.swift @@ -76,6 +76,8 @@ public final class GenerativeModel: Sendable { /// only text content is supported. /// - requestOptions: Configuration parameters for sending requests to the backend. /// - urlSession: The `URLSession` to use for requests; defaults to `URLSession.shared`. + /// - useLimitedUseAppCheckTokens: Use App Check's limited-use tokens instead of the standard + /// cached tokens. init(modelName: String, modelResourceName: String, firebaseInfo: FirebaseInfo, @@ -86,13 +88,15 @@ public final class GenerativeModel: Sendable { toolConfig: ToolConfig? = nil, systemInstruction: ModelContent? = nil, requestOptions: RequestOptions, - urlSession: URLSession = GenAIURLSession.default) { + urlSession: URLSession = GenAIURLSession.default, + useLimitedUseAppCheckTokens: Bool = false) { self.modelName = modelName self.modelResourceName = modelResourceName self.apiConfig = apiConfig generativeAIService = GenerativeAIService( firebaseInfo: firebaseInfo, - urlSession: urlSession + urlSession: urlSession, + useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens ) self.generationConfig = generationConfig self.safetySettings = safetySettings diff --git a/FirebaseAI/Sources/Types/Public/Imagen/ImagenModel.swift b/FirebaseAI/Sources/Types/Public/Imagen/ImagenModel.swift index 729fad9f28d..542f842362c 100644 --- a/FirebaseAI/Sources/Types/Public/Imagen/ImagenModel.swift +++ b/FirebaseAI/Sources/Types/Public/Imagen/ImagenModel.swift @@ -53,12 +53,14 @@ public final class ImagenModel { generationConfig: ImagenGenerationConfig?, safetySettings: ImagenSafetySettings?, requestOptions: RequestOptions, - urlSession: URLSession = GenAIURLSession.default) { + urlSession: URLSession = GenAIURLSession.default, + useLimitedUseAppCheckTokens: Bool = false) { self.modelResourceName = modelResourceName self.apiConfig = apiConfig generativeAIService = GenerativeAIService( firebaseInfo: firebaseInfo, - urlSession: urlSession + urlSession: urlSession, + useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens ) self.generationConfig = generationConfig self.safetySettings = safetySettings diff --git a/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift b/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift index 21554d28250..2c6dceb24fd 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift @@ -121,7 +121,8 @@ extension FirebaseAI { return FirebaseAI.createInstance( app: instanceConfig.app, location: location, - apiConfig: instanceConfig.apiConfig + apiConfig: instanceConfig.apiConfig, + useLimitedUseAppCheckTokens: false ) case .googleAI: assert( @@ -131,7 +132,8 @@ extension FirebaseAI { return FirebaseAI.createInstance( app: instanceConfig.app, location: nil, - apiConfig: instanceConfig.apiConfig + apiConfig: instanceConfig.apiConfig, + useLimitedUseAppCheckTokens: false ) } } diff --git a/FirebaseAI/Tests/Unit/Fakes/AppCheckInteropFake.swift b/FirebaseAI/Tests/Unit/Fakes/AppCheckInteropFake.swift index 62fc753ae68..81b6ac1bb7c 100644 --- a/FirebaseAI/Tests/Unit/Fakes/AppCheckInteropFake.swift +++ b/FirebaseAI/Tests/Unit/Fakes/AppCheckInteropFake.swift @@ -40,6 +40,10 @@ class AppCheckInteropFake: NSObject, AppCheckInterop { return AppCheckTokenResultInteropFake(token: token, error: error) } + func getLimitedUseToken() async -> any FIRAppCheckTokenResultInterop { + return AppCheckTokenResultInteropFake(token: "limited_use_\(token)", error: error) + } + func tokenDidChangeNotificationName() -> String { fatalError("\(#function) not implemented.") } @@ -52,9 +56,10 @@ class AppCheckInteropFake: NSObject, AppCheckInterop { fatalError("\(#function) not implemented.") } - private class AppCheckTokenResultInteropFake: NSObject, FIRAppCheckTokenResultInterop { - var token: String - var error: Error? + private class AppCheckTokenResultInteropFake: NSObject, FIRAppCheckTokenResultInterop, + @unchecked Sendable { + let token: String + let error: Error? init(token: String, error: Error?) { self.token = token diff --git a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift index 7c23726f152..80a383eb461 100644 --- a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift +++ b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift @@ -501,6 +501,31 @@ final class GenerativeModelVertexAITests: XCTestCase { _ = try await model.generateContent(testPrompt) } + func testGenerateContent_appCheck_validToken_limitedUse() async throws { + let appCheckToken = "test-valid-token" + model = GenerativeModel( + modelName: testModelName, + modelResourceName: testModelResourceName, + firebaseInfo: GenerativeModelTestUtil.testFirebaseInfo( + appCheck: AppCheckInteropFake(token: appCheckToken) + ), + apiConfig: apiConfig, + tools: nil, + requestOptions: RequestOptions(), + urlSession: urlSession, + useLimitedUseAppCheckTokens: true + ) + MockURLProtocol + .requestHandler = try GenerativeModelTestUtil.httpRequestHandler( + forResource: "unary-success-basic-reply-short", + withExtension: "json", + subdirectory: vertexSubdirectory, + appCheckToken: "limited_use_\(appCheckToken)" + ) + + _ = try await model.generateContent(testPrompt) + } + func testGenerateContent_dataCollectionOff() async throws { let appCheckToken = "test-valid-token" model = GenerativeModel( diff --git a/FirebaseAI/Tests/Unit/README.md b/FirebaseAI/Tests/Unit/README.md index 9463d595294..88019041f9f 100644 --- a/FirebaseAI/Tests/Unit/README.md +++ b/FirebaseAI/Tests/Unit/README.md @@ -1,3 +1,3 @@ See the Firebase AI SDK -[README](https://github.com/firebase/firebase-ios-sdk/tree/main/FirebaseVertexAI#unit-tests) +[README](https://github.com/firebase/firebase-ios-sdk/tree/main/FirebaseAI#unit-tests) for required setup instructions. diff --git a/FirebaseAI/Tests/Unit/VertexComponentTests.swift b/FirebaseAI/Tests/Unit/VertexComponentTests.swift index 7202e01f4d6..702c6e50871 100644 --- a/FirebaseAI/Tests/Unit/VertexComponentTests.swift +++ b/FirebaseAI/Tests/Unit/VertexComponentTests.swift @@ -155,12 +155,14 @@ class VertexComponentTests: XCTestCase { let vertex1 = FirebaseAI.createInstance( app: VertexComponentTests.app, location: location, - apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta) + apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta), + useLimitedUseAppCheckTokens: false ) let vertex2 = FirebaseAI.createInstance( app: VertexComponentTests.app, location: location, - apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1) + apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1), + useLimitedUseAppCheckTokens: false ) // Ensure they are different instances. @@ -181,7 +183,8 @@ class VertexComponentTests: XCTestCase { let vertex = FirebaseAI( app: app1, location: "transitory location", - apiConfig: FirebaseAI.defaultVertexAIAPIConfig + apiConfig: FirebaseAI.defaultVertexAIAPIConfig, + useLimitedUseAppCheckTokens: false ) weakVertex = vertex XCTAssertNotNil(weakVertex) @@ -208,7 +211,12 @@ class VertexComponentTests: XCTestCase { func testModelResourceName_developerAPI_generativeLanguage() throws { let app = try XCTUnwrap(VertexComponentTests.app) let apiConfig = APIConfig(service: .googleAI(endpoint: .googleAIBypassProxy), version: .v1beta) - let vertex = FirebaseAI.createInstance(app: app, location: nil, apiConfig: apiConfig) + let vertex = FirebaseAI.createInstance( + app: app, + location: nil, + apiConfig: apiConfig, + useLimitedUseAppCheckTokens: false + ) let model = "test-model-name" let modelResourceName = vertex.modelResourceName(modelName: model) @@ -222,7 +230,12 @@ class VertexComponentTests: XCTestCase { service: .googleAI(endpoint: .firebaseProxyStaging), version: .v1beta ) - let vertex = FirebaseAI.createInstance(app: app, location: nil, apiConfig: apiConfig) + let vertex = FirebaseAI.createInstance( + app: app, + location: nil, + apiConfig: apiConfig, + useLimitedUseAppCheckTokens: false + ) let model = "test-model-name" let projectID = vertex.firebaseInfo.projectID @@ -253,7 +266,12 @@ class VertexComponentTests: XCTestCase { service: .googleAI(endpoint: .firebaseProxyStaging), version: .v1beta ) - let vertex = FirebaseAI.createInstance(app: app, location: nil, apiConfig: apiConfig) + let vertex = FirebaseAI.createInstance( + app: app, + location: nil, + apiConfig: apiConfig, + useLimitedUseAppCheckTokens: false + ) let modelResourceName = vertex.modelResourceName(modelName: modelName) let expectedSystemInstruction = ModelContent(role: nil, parts: systemInstruction.parts) diff --git a/FirebaseAppCheck/Interop/Public/FirebaseAppCheckInterop/FIRAppCheckTokenResultInterop.h b/FirebaseAppCheck/Interop/Public/FirebaseAppCheckInterop/FIRAppCheckTokenResultInterop.h index cb86a1bffe8..f87820b9790 100644 --- a/FirebaseAppCheck/Interop/Public/FirebaseAppCheckInterop/FIRAppCheckTokenResultInterop.h +++ b/FirebaseAppCheck/Interop/Public/FirebaseAppCheckInterop/FIRAppCheckTokenResultInterop.h @@ -18,6 +18,7 @@ NS_ASSUME_NONNULL_BEGIN +NS_SWIFT_SENDABLE @protocol FIRAppCheckTokenResultInterop /// App Check token in the case of success or a dummy token in the case of a failure. diff --git a/FirebaseAppCheck/Sources/Core/FIRAppCheckTokenResult.h b/FirebaseAppCheck/Sources/Core/FIRAppCheckTokenResult.h index 37b57b2adef..9cf6ddadec1 100644 --- a/FirebaseAppCheck/Sources/Core/FIRAppCheckTokenResult.h +++ b/FirebaseAppCheck/Sources/Core/FIRAppCheckTokenResult.h @@ -20,6 +20,7 @@ NS_ASSUME_NONNULL_BEGIN +NS_SWIFT_SENDABLE @interface FIRAppCheckTokenResult : NSObject - (instancetype)initWithToken:(NSString *)token error:(nullable NSError *)error; From 4ca80d5e0b8bff270b94b69e053fc921ce1dbd4d Mon Sep 17 00:00:00 2001 From: pcfba <111909874+pcfba@users.noreply.github.com> Date: Tue, 19 Aug 2025 16:27:38 -0700 Subject: [PATCH 41/76] Analytics 12.2.0 (#15232) --- FirebaseAnalytics.podspec | 2 +- GoogleAppMeasurement.podspec | 4 ++-- Package.swift | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index 4a6e7393d68..67515303300 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.authors = 'Google, Inc.' s.source = { - :http => 'https://dl.google.com/firebase/ios/analytics/f8b1e0fb38da4d8c/FirebaseAnalytics-12.1.0.tar.gz' + :http => 'https://dl.google.com/firebase/ios/analytics/20f7f19c421351ed/FirebaseAnalytics-12.2.0.tar.gz' } s.cocoapods_version = '>= 1.12.0' diff --git a/GoogleAppMeasurement.podspec b/GoogleAppMeasurement.podspec index 5b649c66cbb..244898bbd48 100644 --- a/GoogleAppMeasurement.podspec +++ b/GoogleAppMeasurement.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |s| s.authors = 'Google, Inc.' s.source = { - :http => 'https://dl.google.com/firebase/ios/analytics/40ed69179ccc9278/GoogleAppMeasurement-12.1.0.tar.gz' + :http => 'https://dl.google.com/firebase/ios/analytics/47d80ee1ff340179/GoogleAppMeasurement-12.2.0.tar.gz' } s.cocoapods_version = '>= 1.12.0' @@ -39,7 +39,7 @@ Pod::Spec.new do |s| s.subspec 'Default' do |ss| ss.dependency 'GoogleAppMeasurement/Core', '12.2.0' ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.2.0' - ss.ios.dependency 'GoogleAdsOnDeviceConversion', '2.2.0' + ss.ios.dependency 'GoogleAdsOnDeviceConversion', '2.3.0' end s.subspec 'Core' do |ss| diff --git a/Package.swift b/Package.swift index 1de488a3886..f1f118874fb 100644 --- a/Package.swift +++ b/Package.swift @@ -329,8 +329,8 @@ let package = Package( ), .binaryTarget( name: "FirebaseAnalytics", - url: "https://dl.google.com/firebase/ios/swiftpm/12.1.0/FirebaseAnalytics.zip", - checksum: "57ab43b31bc0b804bb09db48d77d713fa7834085bc5aa7e2cd1b5369e63a697d" + url: "https://dl.google.com/firebase/ios/swiftpm/12.2.0/FirebaseAnalytics.zip", + checksum: "f1b07dabcdf3f2b6c495af72baa55e40672a625b8a1b6c631fb43ec74a2ec1ca" ), .testTarget( name: "AnalyticsSwiftUnit", @@ -1384,7 +1384,7 @@ func googleAppMeasurementDependency() -> Package.Dependency { return .package(url: appMeasurementURL, branch: "main") } - return .package(url: appMeasurementURL, exact: "12.1.0") + return .package(url: appMeasurementURL, exact: "12.2.0") } func abseilDependency() -> Package.Dependency { From f33b4cb1a2ca40799d9897fa5dce2a557fda0373 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Tue, 19 Aug 2025 19:57:03 -0400 Subject: [PATCH 42/76] [Firebase AI] Add App Check Limited-Use mode integration tests (#15230) --- .../GenerateContentIntegrationTests.swift | 54 +++++++++++-------- .../Tests/Utilities/InstanceConfig.swift | 47 +++++++++++++--- 2 files changed, 73 insertions(+), 28 deletions(-) diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift index 61bcf240442..ef0f19be217 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift @@ -50,13 +50,18 @@ struct GenerateContentIntegrationTests { @Test(arguments: [ (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2FlashLite), (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2FlashLite), - (InstanceConfig.vertexAI_v1beta_staging, ModelNames.gemini2FlashLite), + (InstanceConfig.vertexAI_v1beta_global_appCheckLimitedUse, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta, ModelNames.gemini2FlashLite), + (InstanceConfig.googleAI_v1beta_appCheckLimitedUse, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta, ModelNames.gemma3_4B), - (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemini2FlashLite), - (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemma3_4B), - (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2FlashLite), - (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemma3_4B), + (InstanceConfig.googleAI_v1beta_freeTier, ModelNames.gemini2FlashLite), + (InstanceConfig.googleAI_v1beta_freeTier, ModelNames.gemma3_4B), + // Note: The following configs are commented out for easy one-off manual testing. + // (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemini2FlashLite), + // (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemma3_4B), + // (InstanceConfig.vertexAI_v1beta_staging, ModelNames.gemini2FlashLite), + // (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2FlashLite), + // (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemma3_4B), ]) func generateContent(_ config: InstanceConfig, modelName: String) async throws { let model = FirebaseAI.componentInstance(config).generativeModel( @@ -165,15 +170,16 @@ struct GenerateContentIntegrationTests { (.googleAI_v1beta_freeTier, ModelNames.gemini2_5_Flash, ThinkingConfig( thinkingBudget: 24576, includeThoughts: true )), - (.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2_5_Flash, ThinkingConfig( - thinkingBudget: 0 - )), - (.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2_5_Flash, ThinkingConfig( - thinkingBudget: 24576 - )), - (.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2_5_Flash, ThinkingConfig( - thinkingBudget: 24576, includeThoughts: true - )), + // Note: The following configs are commented out for easy one-off manual testing. + // (.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2_5_Flash, ThinkingConfig( + // thinkingBudget: 0 + // )), + // (.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2_5_Flash, ThinkingConfig( + // thinkingBudget: 24576 + // )), + // (.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2_5_Flash, ThinkingConfig( + // thinkingBudget: 24576, includeThoughts: true + // )), ] as [(InstanceConfig, String, ThinkingConfig)] ) func generateContentThinking(_ config: InstanceConfig, modelName: String, @@ -319,8 +325,9 @@ struct GenerateContentIntegrationTests { InstanceConfig.vertexAI_v1beta, InstanceConfig.vertexAI_v1beta_global, InstanceConfig.googleAI_v1beta, - InstanceConfig.googleAI_v1beta_staging, - InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, + // Note: The following configs are commented out for easy one-off manual testing. + // InstanceConfig.googleAI_v1beta_staging, + // InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ]) func generateImage(_ config: InstanceConfig) async throws { let generationConfig = GenerationConfig( @@ -416,13 +423,18 @@ struct GenerateContentIntegrationTests { @Test(arguments: [ (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2FlashLite), (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2FlashLite), - (InstanceConfig.vertexAI_v1beta_staging, ModelNames.gemini2FlashLite), + (InstanceConfig.vertexAI_v1beta_global_appCheckLimitedUse, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta, ModelNames.gemini2FlashLite), + (InstanceConfig.googleAI_v1beta_appCheckLimitedUse, ModelNames.gemini2FlashLite), (InstanceConfig.googleAI_v1beta, ModelNames.gemma3_4B), - (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemini2FlashLite), - (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemma3_4B), - (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2FlashLite), - (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemma3_4B), + (InstanceConfig.googleAI_v1beta_freeTier, ModelNames.gemini2FlashLite), + (InstanceConfig.googleAI_v1beta_freeTier, ModelNames.gemma3_4B), + // Note: The following configs are commented out for easy one-off manual testing. + // (InstanceConfig.vertexAI_v1beta_staging, ModelNames.gemini2FlashLite), + // (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemini2FlashLite), + // (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemma3_4B), + // (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemini2FlashLite), + // (InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, ModelNames.gemma3_4B), ]) func generateContentStream(_ config: InstanceConfig, modelName: String) async throws { let expectedResponse = [ diff --git a/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift b/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift index 2c6dceb24fd..df06f43c91f 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift @@ -27,12 +27,20 @@ struct InstanceConfig: Equatable, Encodable { location: "global", apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta) ) + static let vertexAI_v1beta_global_appCheckLimitedUse = InstanceConfig( + location: "global", + useLimitedUseAppCheckTokens: true, + apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta) + ) static let vertexAI_v1beta_staging = InstanceConfig( apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyStaging), version: .v1beta) ) static let googleAI_v1beta = InstanceConfig( apiConfig: APIConfig(service: .googleAI(endpoint: .firebaseProxyProd), version: .v1beta) ) + static let googleAI_v1beta_appCheckLimitedUse = InstanceConfig( + apiConfig: APIConfig(service: .googleAI(endpoint: .firebaseProxyProd), version: .v1beta) + ) static let googleAI_v1beta_staging = InstanceConfig( apiConfig: APIConfig(service: .googleAI(endpoint: .firebaseProxyStaging), version: .v1beta) ) @@ -48,33 +56,54 @@ struct InstanceConfig: Equatable, Encodable { static let allConfigs = [ vertexAI_v1beta, vertexAI_v1beta_global, - vertexAI_v1beta_staging, + vertexAI_v1beta_global_appCheckLimitedUse, googleAI_v1beta, - googleAI_v1beta_staging, - googleAI_v1beta_freeTier_bypassProxy, + googleAI_v1beta_appCheckLimitedUse, + googleAI_v1beta_freeTier, + // Note: The following configs are commented out for easy one-off manual testing. + // vertexAI_v1beta_staging, + // googleAI_v1beta_staging, + // googleAI_v1beta_freeTier_bypassProxy, ] static let vertexAI_v1beta_appCheckNotConfigured = InstanceConfig( appName: FirebaseAppNames.appCheckNotConfigured, apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta) ) + static let vertexAI_v1beta_appCheckNotConfigured_limitedUseTokens = InstanceConfig( + appName: FirebaseAppNames.appCheckNotConfigured, + useLimitedUseAppCheckTokens: true, + apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta) + ) static let googleAI_v1beta_appCheckNotConfigured = InstanceConfig( appName: FirebaseAppNames.appCheckNotConfigured, apiConfig: APIConfig(service: .googleAI(endpoint: .firebaseProxyProd), version: .v1beta) ) + static let googleAI_v1beta_appCheckNotConfigured_limitedUseTokens = InstanceConfig( + appName: FirebaseAppNames.appCheckNotConfigured, + useLimitedUseAppCheckTokens: true, + apiConfig: APIConfig(service: .googleAI(endpoint: .firebaseProxyProd), version: .v1beta) + ) static let appCheckNotConfiguredConfigs = [ vertexAI_v1beta_appCheckNotConfigured, + vertexAI_v1beta_appCheckNotConfigured_limitedUseTokens, googleAI_v1beta_appCheckNotConfigured, + googleAI_v1beta_appCheckNotConfigured_limitedUseTokens, ] let appName: String? let location: String? + let useLimitedUseAppCheckTokens: Bool let apiConfig: APIConfig - init(appName: String? = nil, location: String? = nil, apiConfig: APIConfig) { + init(appName: String? = nil, + location: String? = nil, + useLimitedUseAppCheckTokens: Bool = false, + apiConfig: APIConfig) { self.appName = appName self.location = location + self.useLimitedUseAppCheckTokens = useLimitedUseAppCheckTokens self.apiConfig = apiConfig } @@ -108,8 +137,12 @@ extension InstanceConfig: CustomTestStringConvertible { " - Bypass Proxy" } let locationSuffix = location.map { " - \($0)" } ?? "" + let appCheckLimitedUseDesignator = useLimitedUseAppCheckTokens ? " - FAC Limited-Use" : "" - return "\(serviceName) (\(versionName))\(freeTierDesignator)\(endpointSuffix)\(locationSuffix)" + return """ + \(serviceName) (\(versionName))\(freeTierDesignator)\(endpointSuffix)\(locationSuffix)\ + \(appCheckLimitedUseDesignator) + """ } } @@ -122,7 +155,7 @@ extension FirebaseAI { app: instanceConfig.app, location: location, apiConfig: instanceConfig.apiConfig, - useLimitedUseAppCheckTokens: false + useLimitedUseAppCheckTokens: instanceConfig.useLimitedUseAppCheckTokens ) case .googleAI: assert( @@ -133,7 +166,7 @@ extension FirebaseAI { app: instanceConfig.app, location: nil, apiConfig: instanceConfig.apiConfig, - useLimitedUseAppCheckTokens: false + useLimitedUseAppCheckTokens: instanceConfig.useLimitedUseAppCheckTokens ) } } From 69b57a7c6aeef8f58bac715dd11fbccf977b2d54 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Tue, 19 Aug 2025 20:56:11 -0400 Subject: [PATCH 43/76] [Auth] Update changelog entry for 12.2.0 (#15233) --- FirebaseAuth/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index cd04d3440d7..2b725886b45 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,4 +1,4 @@ -# Unreleased +# 12.2.0 - [added] Added TOTP support for macOS. # 12.1.0 From 815e3e9a52e6d5633dac663e9defdcb2505d11bf Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 19 Aug 2025 21:40:59 -0400 Subject: [PATCH 44/76] fix(tooling): Use module name over spec name in XCFramework module maps (#15229) --- ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift | 2 +- ReleaseTooling/Sources/ZipBuilder/ModuleMapBuilder.swift | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift b/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift index cd87fd3272e..c29eaeb3305 100755 --- a/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift +++ b/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift @@ -272,7 +272,7 @@ struct FrameworkBuilder { /// /// - Parameter framework: The name of the pod to be built. /// - Returns: The corresponding framework/module name. - private static func frameworkBuildName(_ framework: String) -> String { + static func frameworkBuildName(_ framework: String) -> String { switch framework { case "abseil": return "absl" diff --git a/ReleaseTooling/Sources/ZipBuilder/ModuleMapBuilder.swift b/ReleaseTooling/Sources/ZipBuilder/ModuleMapBuilder.swift index dc781d6a0d4..a1ccd32243e 100755 --- a/ReleaseTooling/Sources/ZipBuilder/ModuleMapBuilder.swift +++ b/ReleaseTooling/Sources/ZipBuilder/ModuleMapBuilder.swift @@ -248,6 +248,11 @@ struct ModuleMapBuilder { installedPods[name]?.transitiveFrameworks = transitiveFrameworkDeps installedPods[name]?.transitiveLibraries = transitiveLibraryDeps - return ModuleMapContents(module: name, frameworks: myFrameworkDeps, libraries: myLibraryDeps) + let moduleName = FrameworkBuilder.frameworkBuildName(name) + return ModuleMapContents( + module: moduleName, + frameworks: myFrameworkDeps, + libraries: myLibraryDeps + ) } } From e2a3c3fbcaa1df3fd549b5b3f1175bc8a11912fd Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 19 Aug 2025 22:58:44 -0400 Subject: [PATCH 45/76] fix(config): Address race condition from concurrent network session recreation (#15231) --- FirebaseRemoteConfig/CHANGELOG.md | 4 ++++ FirebaseRemoteConfig/Sources/FIRRemoteConfig.m | 6 +++--- FirebaseRemoteConfig/Sources/RCNConfigFetch.m | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/FirebaseRemoteConfig/CHANGELOG.md b/FirebaseRemoteConfig/CHANGELOG.md index f1b25939183..36ced2c9a19 100644 --- a/FirebaseRemoteConfig/CHANGELOG.md +++ b/FirebaseRemoteConfig/CHANGELOG.md @@ -1,3 +1,7 @@ +# 12.2.0 +- [fixed] Fixed a race condition that could lead to a crash during network + session recreation. (#15087) + # 12.0.0 - [added] Improved how the SDK handles real-time requests when a Firebase project has exceeded its available quota for real-time services. diff --git a/FirebaseRemoteConfig/Sources/FIRRemoteConfig.m b/FirebaseRemoteConfig/Sources/FIRRemoteConfig.m index 443265800b2..258eb362fe7 100644 --- a/FirebaseRemoteConfig/Sources/FIRRemoteConfig.m +++ b/FirebaseRemoteConfig/Sources/FIRRemoteConfig.m @@ -700,6 +700,8 @@ - (FIRRemoteConfigSettings *)configSettings { dispatch_sync(_queue, ^{ minimumFetchInterval = self->_settings.minimumFetchInterval; fetchTimeout = self->_settings.fetchTimeout; + // The NSURLSession needs to be recreated whenever the fetch timeout may be updated. + [_configFetch recreateNetworkSession]; }); FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000066", @"Successfully read configSettings. Minimum Fetch Interval:%f, " @@ -708,8 +710,6 @@ - (FIRRemoteConfigSettings *)configSettings { FIRRemoteConfigSettings *settings = [[FIRRemoteConfigSettings alloc] init]; settings.minimumFetchInterval = minimumFetchInterval; settings.fetchTimeout = fetchTimeout; - /// The NSURLSession needs to be recreated whenever the fetch timeout may be updated. - [_configFetch recreateNetworkSession]; return settings; } @@ -721,7 +721,7 @@ - (void)setConfigSettings:(FIRRemoteConfigSettings *)configSettings { self->_settings.minimumFetchInterval = configSettings.minimumFetchInterval; self->_settings.fetchTimeout = configSettings.fetchTimeout; - /// The NSURLSession needs to be recreated whenever the fetch timeout may be updated. + // The NSURLSession needs to be recreated whenever the fetch timeout may be updated. [self->_configFetch recreateNetworkSession]; FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000067", @"Successfully set configSettings. Minimum Fetch Interval:%f, " diff --git a/FirebaseRemoteConfig/Sources/RCNConfigFetch.m b/FirebaseRemoteConfig/Sources/RCNConfigFetch.m index 85e86f85e36..1df80385972 100644 --- a/FirebaseRemoteConfig/Sources/RCNConfigFetch.m +++ b/FirebaseRemoteConfig/Sources/RCNConfigFetch.m @@ -113,6 +113,7 @@ - (instancetype)initWithContent:(RCNConfigContent *)content } /// Force a new NSURLSession creation for updated config. +/// - Warning: This API is **not** thread-safe. - (void)recreateNetworkSession { if (_fetchSession) { [_fetchSession invalidateAndCancel]; From 5663aa0813a72a69460e2ff733d13085e91aac89 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 20 Aug 2025 16:52:32 -0400 Subject: [PATCH 46/76] fix(ci): Resolve Xcode version issues for messaging and (pre)release workflows (#15227) --- .github/workflows/messaging.yml | 4 ++-- .github/workflows/prerelease.yml | 34 ++++++++++++++++++++++++++++++++ .github/workflows/release.yml | 23 ++++++++++++--------- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/.github/workflows/messaging.yml b/.github/workflows/messaging.yml index 24f6a7de304..d2f57632bfc 100644 --- a/.github/workflows/messaging.yml +++ b/.github/workflows/messaging.yml @@ -178,6 +178,8 @@ jobs: with: cache_key: sample${{ matrix.os }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: Install Secret GoogleService-Info.plist @@ -186,8 +188,6 @@ jobs: FirebaseMessaging/Apps/Shared/GoogleService-Info.plist "$plist_secret" - name: Prereqs run: scripts/install_prereqs.sh MessagingSample iOS - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Build run: ([ -z $plist_secret ] || scripts/build.sh MessagingSample iOS) diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index de7187ddb9b..628dca33d25 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -35,6 +35,8 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Generate matrix id: generate_matrix run: | @@ -80,6 +82,7 @@ jobs: path: | *.podspec *.podspec.json + buildup_SpecsTesting_repo_FirebaseCore: needs: specs_checking # Don't run on private repo unless it is a PR. @@ -92,6 +95,8 @@ jobs: targeted_pod: FirebaseCore steps: - uses: actions/checkout@v4 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - uses: actions/download-artifact@v4.1.7 with: name: firebase-ios-sdk @@ -127,10 +132,17 @@ jobs: targeted_pod: ${{ matrix.podspec }} steps: - uses: actions/checkout@v4 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - uses: actions/download-artifact@v4.1.7 with: name: firebase-ios-sdk path: ${{ env.local_sdk_repo_dir }} + # Addresses flaky pushes due to missing git config on runner. + - name: Set git config + run: | + git config --global user.email "google-oss-bot@example.com" + git config --global user.name "google-oss-bot" - name: Update SpecsTesting repo run: | [[ ${{ matrix.allowwarnings }} == true ]] && ALLOWWARNINGS=true @@ -163,6 +175,8 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Update SpecsTesting repo setup run: | # Update/create a nightly tag to the head of the main branch. @@ -207,6 +221,8 @@ jobs: steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup testing repo and quickstart env: LEGACY: true @@ -273,6 +289,8 @@ jobs: steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup testing repo and quickstart env: LEGACY: true @@ -314,6 +332,8 @@ jobs: steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh database prerelease_testing - name: Install Secret GoogleService-Info.plist @@ -346,6 +366,8 @@ jobs: steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh firestore prerelease_testing - name: Install Secret GoogleService-Info.plist @@ -380,6 +402,8 @@ jobs: # steps: # - uses: actions/checkout@v4 # - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + # - name: Xcode + # run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer # - name: Setup testing repo and quickstart # run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh functions prerelease_testing # - name: install secret googleservice-info.plist @@ -416,6 +440,8 @@ jobs: steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh inappmessaging prerelease_testing - name: install secret googleservice-info.plist @@ -450,6 +476,8 @@ jobs: steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh messaging prerelease_testing - name: Install Secret GoogleService-Info.plist @@ -482,6 +510,8 @@ jobs: steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh config prerelease_testing - name: Install Secret GoogleService-Info.plist @@ -513,6 +543,8 @@ jobs: steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh storage prerelease_testing - name: Install Secret GoogleService-Info.plist @@ -543,6 +575,8 @@ jobs: steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh Performance prerelease_testing - name: Install Secret GoogleService-Info.plist diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3b28e2fb8ec..d29131a857e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -127,6 +127,11 @@ jobs: with: name: firebase-ios-sdk path: ${{ env.local_sdk_repo_dir }} + # Addresses flaky pushes due to missing git config on runner. + - name: Set git config + run: | + git config --global user.email "google-oss-bot@example.com" + git config --global user.name "google-oss-bot" - name: Update SpecsReleasing repo run: | [[ ${{ matrix.allowwarnings }} == true ]] && ALLOWWARNINGS=true @@ -153,7 +158,7 @@ jobs: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 - name: Set Xcode version @@ -221,7 +226,7 @@ jobs: botaccess: ${{ secrets.RELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 - name: Set Xcode version @@ -264,7 +269,7 @@ jobs: botaccess: ${{ secrets.RELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 - name: Set Xcode version @@ -298,7 +303,7 @@ jobs: botaccess: ${{ secrets.RELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 - name: Set Xcode version @@ -369,7 +374,7 @@ jobs: botaccess: ${{ secrets.RELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 - name: Set Xcode version @@ -405,7 +410,7 @@ jobs: botaccess: ${{ secrets.RELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 - name: Set Xcode version @@ -439,7 +444,7 @@ jobs: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 - name: Set Xcode version @@ -472,7 +477,7 @@ jobs: testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" LEGACY: true - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 - name: Set Xcode version @@ -504,7 +509,7 @@ jobs: botaccess: ${{ secrets.RELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 - name: Set Xcode version From ca537d979bd09d723ae940e7259dd9f8f04b06eb Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Thu, 21 Aug 2025 15:41:04 -0400 Subject: [PATCH 47/76] fix(ci): Set git config in prerelease.yml (#15236) --- .github/workflows/prerelease.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 628dca33d25..45cb46e10ab 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -101,6 +101,11 @@ jobs: with: name: firebase-ios-sdk path: ${{ env.local_sdk_repo_dir }} + # Addresses flaky pushes due to missing git config on runner. + - name: Set git config + run: | + git config --global user.email "google-oss-bot@example.com" + git config --global user.name "google-oss-bot" - name: Update SpecsTesting repo run: | cd scripts/create_spec_repo/ From b0fe0e016820fb05ad806711d08816c2ad2cd2e8 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Thu, 21 Aug 2025 15:51:21 -0400 Subject: [PATCH 48/76] chore(ci): Catch xcodebuild log on failure for watchOS sample build in messaging.yml (#15237) --- .github/workflows/messaging.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/messaging.yml b/.github/workflows/messaging.yml index d2f57632bfc..2dd09288c22 100644 --- a/.github/workflows/messaging.yml +++ b/.github/workflows/messaging.yml @@ -240,4 +240,10 @@ jobs: run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Build run: ([ -z $plist_secret ] || scripts/build.sh MessagingSampleStandaloneWatchApp watchOS) + - name: Upload xcodebuild logs + if: failure() + uses: actions/upload-artifact@v4 + with: + name: xcodebuild-logs-${{ matrix.target }} + path: xcodebuild-*.log From 52ae69acb741d75b895c675b8506b77ebce1537e Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Thu, 21 Aug 2025 16:05:28 -0400 Subject: [PATCH 49/76] fix(ml): Re-generate MLModelDownloader proto (#15239) --- .../proto/firebase_ml_log_sdk.pb.swift | 210 ++++++------------ 1 file changed, 72 insertions(+), 138 deletions(-) diff --git a/FirebaseMLModelDownloader/Sources/proto/firebase_ml_log_sdk.pb.swift b/FirebaseMLModelDownloader/Sources/proto/firebase_ml_log_sdk.pb.swift index e7f83207e8f..ff94e2d8db6 100644 --- a/FirebaseMLModelDownloader/Sources/proto/firebase_ml_log_sdk.pb.swift +++ b/FirebaseMLModelDownloader/Sources/proto/firebase_ml_log_sdk.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: firebase_ml_log_sdk.proto @@ -21,7 +22,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Foundation import SwiftProtobuf // If the compiler emits an error on this type, it is because this file @@ -34,7 +34,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -enum EventName: SwiftProtobuf.Enum { +enum EventName: SwiftProtobuf.Enum, Swift.CaseIterable { typealias RawValue = Int case unknownEvent // = 0 case modelDownload // = 100 @@ -66,25 +66,19 @@ enum EventName: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension EventName: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. - static var allCases: [EventName] = [ + static let allCases: [EventName] = [ .unknownEvent, .modelDownload, .modelUpdate, .remoteModelDeleteOnDevice, ] -} -#endif // swift(>=4.2) +} /// A list of error codes for various components of the system. For model downloading, the /// range of error codes is 100 to 199. -enum ErrorCode: SwiftProtobuf.Enum { +enum ErrorCode: SwiftProtobuf.Enum, Swift.CaseIterable { typealias RawValue = Int /// No error at all. @@ -156,13 +150,8 @@ enum ErrorCode: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension ErrorCode: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. - static var allCases: [ErrorCode] = [ + static let allCases: [ErrorCode] = [ .noError, .uriExpired, .noNetworkConnection, @@ -173,12 +162,11 @@ extension ErrorCode: CaseIterable { .modelHashMismatch, .unknownError, ] -} -#endif // swift(>=4.2) +} /// Information about various parts of the system: app, Firebase, SDK. -struct SystemInfo { +struct SystemInfo: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -206,7 +194,7 @@ struct SystemInfo { } /// Information about models. -struct ModelInfo { +struct ModelInfo: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -229,7 +217,7 @@ struct ModelInfo { /// The model type is currently envisioned to be used mainly for model /// download/update. - enum ModelType: SwiftProtobuf.Enum { + enum ModelType: SwiftProtobuf.Enum, Swift.CaseIterable { typealias RawValue = Int case typeUnknown // = 0 case custom // = 1 @@ -255,26 +243,20 @@ struct ModelInfo { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + static let allCases: [ModelInfo.ModelType] = [ + .typeUnknown, + .custom, + ] + } init() {} } -#if swift(>=4.2) - -extension ModelInfo.ModelType: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - static var allCases: [ModelInfo.ModelType] = [ - .typeUnknown, - .custom, - ] -} - -#endif // swift(>=4.2) - /// Detailed information about a model. /// The message used to be named "CustomModelOptions". -struct ModelOptions { +struct ModelOptions: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -303,7 +285,7 @@ struct ModelOptions { /// result in multiple log entries. "download_status" in the log entry indicates /// during which stage it is logged. /// This message used to be named "CustomModelDownloadLogEvent". -struct ModelDownloadLogEvent { +struct ModelDownloadLogEvent: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -352,7 +334,7 @@ struct ModelDownloadLogEvent { /// or explicitly does not affect the later stages of the download. As a /// result, later stages (i.e. enum tag 3+) do not distinguish between explicit /// and implicit triggering. - enum DownloadStatus: SwiftProtobuf.Enum { + enum DownloadStatus: SwiftProtobuf.Enum, Swift.CaseIterable { typealias RawValue = Int case unknownStatus // = 0 @@ -422,6 +404,20 @@ struct ModelDownloadLogEvent { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + static let allCases: [ModelDownloadLogEvent.DownloadStatus] = [ + .unknownStatus, + .explicitlyRequested, + .implicitlyRequested, + .modelInfoRetrievalSucceeded, + .modelInfoRetrievalFailed, + .scheduled, + .downloading, + .succeeded, + .failed, + .updateAvailable, + ] + } init() {} @@ -429,28 +425,8 @@ struct ModelDownloadLogEvent { fileprivate var _options: ModelOptions? = nil } -#if swift(>=4.2) - -extension ModelDownloadLogEvent.DownloadStatus: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - static var allCases: [ModelDownloadLogEvent.DownloadStatus] = [ - .unknownStatus, - .explicitlyRequested, - .implicitlyRequested, - .modelInfoRetrievalSucceeded, - .modelInfoRetrievalFailed, - .scheduled, - .downloading, - .succeeded, - .failed, - .updateAvailable, - ] -} - -#endif // swift(>=4.2) - /// Information about deleting a downloaded model on device. -struct DeleteModelLogEvent { +struct DeleteModelLogEvent: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -469,7 +445,7 @@ struct DeleteModelLogEvent { /// Main log event for FirebaseMl, that contains individual API events, like model /// download. /// NEXT ID: 44. -struct FirebaseMlLogEvent { +struct FirebaseMlLogEvent: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -520,37 +496,16 @@ struct FirebaseMlLogEvent { // MARK: - Code below here is support for the SwiftProtobuf runtime. extension EventName: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "UNKNOWN_EVENT"), - 100: .same(proto: "MODEL_DOWNLOAD"), - 101: .same(proto: "MODEL_UPDATE"), - 252: .same(proto: "REMOTE_MODEL_DELETE_ON_DEVICE"), - ] + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0UNKNOWN_EVENT\0\u{2}d\u{1}MODEL_DOWNLOAD\0\u{1}MODEL_UPDATE\0\u{2}W\u{2}REMOTE_MODEL_DELETE_ON_DEVICE\0") } extension ErrorCode: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "NO_ERROR"), - 101: .same(proto: "URI_EXPIRED"), - 102: .same(proto: "NO_NETWORK_CONNECTION"), - 104: .same(proto: "DOWNLOAD_FAILED"), - 105: .same(proto: "MODEL_INFO_DOWNLOAD_UNSUCCESSFUL_HTTP_STATUS"), - 106: .same(proto: "MODEL_INFO_DOWNLOAD_NO_HASH"), - 107: .same(proto: "MODEL_INFO_DOWNLOAD_CONNECTION_FAILED"), - 116: .same(proto: "MODEL_HASH_MISMATCH"), - 9999: .same(proto: "UNKNOWN_ERROR"), - ] + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0NO_ERROR\0\u{2}e\u{1}URI_EXPIRED\0\u{1}NO_NETWORK_CONNECTION\0\u{2}\u{2}DOWNLOAD_FAILED\0\u{1}MODEL_INFO_DOWNLOAD_UNSUCCESSFUL_HTTP_STATUS\0\u{1}MODEL_INFO_DOWNLOAD_NO_HASH\0\u{1}MODEL_INFO_DOWNLOAD_CONNECTION_FAILED\0\u{2}\u{9}MODEL_HASH_MISMATCH\0\u{2}[Z\u{2}UNKNOWN_ERROR\0") } extension SystemInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = "SystemInfo" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .standard(proto: "app_id"), - 2: .standard(proto: "app_version"), - 3: .standard(proto: "firebase_project_id"), - 4: .standard(proto: "ml_sdk_version"), - 7: .standard(proto: "api_key"), - ] + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}app_id\0\u{3}app_version\0\u{3}firebase_project_id\0\u{3}ml_sdk_version\0\u{4}\u{3}api_key\0") mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -600,12 +555,7 @@ extension SystemInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio extension ModelInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = "ModelInfo" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "name"), - 2: .same(proto: "version"), - 5: .same(proto: "hash"), - 6: .standard(proto: "model_type"), - ] + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}version\0\u{2}\u{3}hash\0\u{3}model_type\0") mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -649,18 +599,12 @@ extension ModelInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation } extension ModelInfo.ModelType: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "TYPE_UNKNOWN"), - 1: .same(proto: "CUSTOM"), - ] + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0TYPE_UNKNOWN\0\u{1}CUSTOM\0") } extension ModelOptions: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = "ModelOptions" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .standard(proto: "model_info"), - 4: .standard(proto: "is_model_update_enabled"), - ] + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}model_info\0\u{4}\u{3}is_model_update_enabled\0") mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -676,9 +620,13 @@ extension ModelOptions: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat } func traverse(visitor: inout V) throws { - if let v = self._modelInfo { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._modelInfo { try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } + } }() if self.isModelUpdateEnabled != false { try visitor.visitSingularBoolField(value: self.isModelUpdateEnabled, fieldNumber: 4) } @@ -695,14 +643,7 @@ extension ModelOptions: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat extension ModelDownloadLogEvent: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = "ModelDownloadLogEvent" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "options"), - 2: .standard(proto: "rough_download_duration_ms"), - 3: .standard(proto: "error_code"), - 4: .standard(proto: "exact_download_duration_ms"), - 5: .standard(proto: "download_status"), - 6: .standard(proto: "download_failure_status"), - ] + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}options\0\u{3}rough_download_duration_ms\0\u{3}error_code\0\u{3}exact_download_duration_ms\0\u{3}download_status\0\u{3}download_failure_status\0") mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -722,9 +663,13 @@ extension ModelDownloadLogEvent: SwiftProtobuf.Message, SwiftProtobuf._MessageIm } func traverse(visitor: inout V) throws { - if let v = self._options { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._options { try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } + } }() if self.roughDownloadDurationMs != 0 { try visitor.visitSingularUInt64Field(value: self.roughDownloadDurationMs, fieldNumber: 2) } @@ -756,26 +701,12 @@ extension ModelDownloadLogEvent: SwiftProtobuf.Message, SwiftProtobuf._MessageIm } extension ModelDownloadLogEvent.DownloadStatus: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "UNKNOWN_STATUS"), - 1: .same(proto: "EXPLICITLY_REQUESTED"), - 2: .same(proto: "IMPLICITLY_REQUESTED"), - 3: .same(proto: "MODEL_INFO_RETRIEVAL_SUCCEEDED"), - 4: .same(proto: "MODEL_INFO_RETRIEVAL_FAILED"), - 5: .same(proto: "SCHEDULED"), - 6: .same(proto: "DOWNLOADING"), - 7: .same(proto: "SUCCEEDED"), - 8: .same(proto: "FAILED"), - 10: .same(proto: "UPDATE_AVAILABLE"), - ] + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0UNKNOWN_STATUS\0\u{1}EXPLICITLY_REQUESTED\0\u{1}IMPLICITLY_REQUESTED\0\u{1}MODEL_INFO_RETRIEVAL_SUCCEEDED\0\u{1}MODEL_INFO_RETRIEVAL_FAILED\0\u{1}SCHEDULED\0\u{1}DOWNLOADING\0\u{1}SUCCEEDED\0\u{1}FAILED\0\u{2}\u{2}UPDATE_AVAILABLE\0") } extension DeleteModelLogEvent: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = "DeleteModelLogEvent" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .standard(proto: "model_type"), - 2: .standard(proto: "is_successful"), - ] + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}model_type\0\u{3}is_successful\0") mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -810,12 +741,7 @@ extension DeleteModelLogEvent: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl extension FirebaseMlLogEvent: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = "FirebaseMlLogEvent" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .standard(proto: "system_info"), - 2: .standard(proto: "event_name"), - 3: .standard(proto: "model_download_log_event"), - 40: .standard(proto: "delete_model_log_event"), - ] + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}system_info\0\u{3}event_name\0\u{3}model_download_log_event\0\u{4}%delete_model_log_event\0") fileprivate class _StorageClass { var _systemInfo: SystemInfo? = nil @@ -823,7 +749,11 @@ extension FirebaseMlLogEvent: SwiftProtobuf.Message, SwiftProtobuf._MessageImple var _modelDownloadLogEvent: ModelDownloadLogEvent? = nil var _deleteModelLogEvent: DeleteModelLogEvent? = nil - static let defaultInstance = _StorageClass() + // This property is used as the initial default value for new instances of the type. + // The type itself is protecting the reference to its storage via CoW semantics. + // This will force a copy to be made of this reference when the first mutation occurs; + // hence, it is safe to mark this as `nonisolated(unsafe)`. + static nonisolated(unsafe) let defaultInstance = _StorageClass() private init() {} @@ -862,18 +792,22 @@ extension FirebaseMlLogEvent: SwiftProtobuf.Message, SwiftProtobuf._MessageImple func traverse(visitor: inout V) throws { try withExtendedLifetime(_storage) { (_storage: _StorageClass) in - if let v = _storage._systemInfo { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = _storage._systemInfo { try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } + } }() if _storage._eventName != .unknownEvent { try visitor.visitSingularEnumField(value: _storage._eventName, fieldNumber: 2) } - if let v = _storage._modelDownloadLogEvent { + try { if let v = _storage._modelDownloadLogEvent { try visitor.visitSingularMessageField(value: v, fieldNumber: 3) - } - if let v = _storage._deleteModelLogEvent { + } }() + try { if let v = _storage._deleteModelLogEvent { try visitor.visitSingularMessageField(value: v, fieldNumber: 40) - } + } }() } try unknownFields.traverse(visitor: &visitor) } From d3c23e6c15bff9ecf1aba5ed9c953ffb04e9ef7a Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 25 Aug 2025 12:01:22 -0400 Subject: [PATCH 50/76] fix(ci): Perf. int. tests need Xcode 16.4 and should run daily (#15242) --- .github/workflows/performance-integration-tests.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/performance-integration-tests.yml b/.github/workflows/performance-integration-tests.yml index 95d486d39e6..2bae0f30b4a 100644 --- a/.github/workflows/performance-integration-tests.yml +++ b/.github/workflows/performance-integration-tests.yml @@ -12,8 +12,8 @@ on: # - https://docs.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events-schedule # - https://crontab.guru/ schedule: - # Runs every 4 hours. - - cron: '0 */4 * * *' + # Runs once a day. + - cron: '0 0 * * *' concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} @@ -33,6 +33,8 @@ jobs: with: cache_key: integration - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Setup Bundler run: scripts/setup_bundler.sh - name: Install xcpretty From b98d6cb2d990a9a1873b7c01e48e0e385fa59ab7 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 25 Aug 2025 14:27:15 -0400 Subject: [PATCH 51/76] chore(ci): Retry workflows on error or timeout (#15243) --- .github/workflows/auth.yml | 6 ++---- .github/workflows/common.yml | 3 +-- .github/workflows/common_catalyst.yml | 3 +-- .github/workflows/common_cocoapods.yml | 3 +-- .github/workflows/crashlytics.yml | 3 +-- .github/workflows/spm.yml | 3 +-- .github/workflows/storage.yml | 3 +-- 7 files changed, 8 insertions(+), 16 deletions(-) diff --git a/.github/workflows/auth.yml b/.github/workflows/auth.yml index 6a0447b399d..a8b04befda4 100644 --- a/.github/workflows/auth.yml +++ b/.github/workflows/auth.yml @@ -86,9 +86,8 @@ jobs: run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: - timeout_minutes: 120 + timeout_minutes: 15 max_attempts: 3 - retry_on: error retry_wait_seconds: 120 command: ([ -z $plist_secret ] || scripts/build.sh Auth iOS ${{ matrix.scheme }}) @@ -164,8 +163,7 @@ jobs: run: scripts/configure_test_keychain.sh - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: - timeout_minutes: 120 + timeout_minutes: 15 max_attempts: 3 - retry_on: error retry_wait_seconds: 120 command: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseAuth.podspec --platforms=${{ matrix.target }} ${{ matrix.flags }} diff --git a/.github/workflows/common.yml b/.github/workflows/common.yml index b79680f09b4..16ba348c402 100644 --- a/.github/workflows/common.yml +++ b/.github/workflows/common.yml @@ -112,9 +112,8 @@ jobs: - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 if: contains(join(inputs.platforms), matrix.platform) || matrix.os == 'macos-14' with: - timeout_minutes: 120 + timeout_minutes: 15 max_attempts: 3 - retry_on: error retry_wait_seconds: 120 command: | ./scripts/build.sh \ diff --git a/.github/workflows/common_catalyst.yml b/.github/workflows/common_catalyst.yml index da3911b064c..dd235d3847d 100644 --- a/.github/workflows/common_catalyst.yml +++ b/.github/workflows/common_catalyst.yml @@ -41,9 +41,8 @@ jobs: run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: - timeout_minutes: 120 + timeout_minutes: 15 max_attempts: 3 - retry_on: error retry_wait_seconds: 120 command: | scripts/test_catalyst.sh \ diff --git a/.github/workflows/common_cocoapods.yml b/.github/workflows/common_cocoapods.yml index cf054ef7743..e672dabcaf9 100644 --- a/.github/workflows/common_cocoapods.yml +++ b/.github/workflows/common_cocoapods.yml @@ -139,9 +139,8 @@ jobs: - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 if: contains(join(inputs.platforms), matrix.platform) || matrix.os == 'macos-14' with: - timeout_minutes: 120 + timeout_minutes: 15 max_attempts: 3 - retry_on: error retry_wait_seconds: 120 command: | scripts/pod_lib_lint.rb ${{ inputs.product }}.podspec --platforms=${{ matrix.platform }} \ diff --git a/.github/workflows/crashlytics.yml b/.github/workflows/crashlytics.yml index 13c307610ea..6d61284351a 100644 --- a/.github/workflows/crashlytics.yml +++ b/.github/workflows/crashlytics.yml @@ -133,8 +133,7 @@ jobs: run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: - timeout_minutes: 120 + timeout_minutes: 15 max_attempts: 3 - retry_on: error retry_wait_seconds: 120 command: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseCrashlytics.podspec --platforms=${{ matrix.target }} ${{ matrix.flags }} diff --git a/.github/workflows/spm.yml b/.github/workflows/spm.yml index 6d583ebd780..f4f8c05a539 100644 --- a/.github/workflows/spm.yml +++ b/.github/workflows/spm.yml @@ -81,9 +81,8 @@ jobs: run: FirebaseFunctions/Backend/start.sh synchronous - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: - timeout_minutes: 120 + timeout_minutes: 15 max_attempts: 3 - retry_on: error retry_wait_seconds: 120 command: scripts/build.sh Firebase-Package iOS ${{ matrix.test }} diff --git a/.github/workflows/storage.yml b/.github/workflows/storage.yml index fd109429a5e..47d19b294c6 100644 --- a/.github/workflows/storage.yml +++ b/.github/workflows/storage.yml @@ -71,9 +71,8 @@ jobs: run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: - timeout_minutes: 120 + timeout_minutes: 15 max_attempts: 3 - retry_on: error retry_wait_seconds: 120 command: ([ -z $plist_secret ] || scripts/build.sh Storage${{ matrix.language }} all) From d1196974ea61374fdd9677935e7d553ebffad5e3 Mon Sep 17 00:00:00 2001 From: Daymon <17409137+daymxn@users.noreply.github.com> Date: Mon, 25 Aug 2025 14:10:17 -0500 Subject: [PATCH 52/76] [FAL] Move useLimitedUseAppCheckTokens property into FirebaseInfo + Update docs (#15234) --- FirebaseAI/CHANGELOG.md | 11 +++---- FirebaseAI/Sources/FirebaseAI.swift | 29 +++++-------------- FirebaseAI/Sources/FirebaseInfo.swift | 5 +++- FirebaseAI/Sources/GenerativeAIService.swift | 9 ++---- FirebaseAI/Sources/GenerativeModel.swift | 8 ++--- .../Types/Public/Imagen/ImagenModel.swift | 6 ++-- FirebaseAI/Tests/Unit/ChatTests.swift | 3 +- .../Unit/GenerativeModelVertexAITests.swift | 6 ++-- .../GenerativeModelTestUtil.swift | 6 ++-- 9 files changed, 32 insertions(+), 51 deletions(-) diff --git a/FirebaseAI/CHANGELOG.md b/FirebaseAI/CHANGELOG.md index b5f3199a797..1cc90f6028e 100644 --- a/FirebaseAI/CHANGELOG.md +++ b/FirebaseAI/CHANGELOG.md @@ -1,13 +1,10 @@ # 12.2.0 - [feature] Added support for returning thought summaries, which are synthesized versions of a model's internal reasoning process. (#15096) -- [feature] Added a new configuration option to use limited-use App - Check tokens for attesting Firebase AI Logic requests. This enhances - security against replay attacks. To use this feature, configure it - explicitly via the new `useLimitedUseAppCheckTokens` parameter when - initializing `FirebaseAI`. We recommend migrating to limited-use - tokens now, so your app will be ready to take advantage of replay - protection when it becomes available for Firebase AI Logic. (#15099) +- [feature] Added support for limited-use tokens with Firebase App Check. These short-lived tokens + provide greater protection for the APIs that give you access to Gemini and Imagen models. Learn + how to [enable usage of limited-use tokens](https://firebase.google.com/docs/ai-logic/app-check). + (#15099) # 12.0.0 - [feature] Added support for Grounding with Google Search. (#15014) diff --git a/FirebaseAI/Sources/FirebaseAI.swift b/FirebaseAI/Sources/FirebaseAI.swift index d4c2e9d545d..7cb33e30a33 100644 --- a/FirebaseAI/Sources/FirebaseAI.swift +++ b/FirebaseAI/Sources/FirebaseAI.swift @@ -33,21 +33,12 @@ public final class FirebaseAI: Sendable { /// - backend: The backend API for the Firebase AI SDK; if not specified, uses the default /// ``Backend/googleAI()`` (Gemini Developer API). /// - useLimitedUseAppCheckTokens: When sending tokens to the backend, this option enables - /// the usage of App Check's limited-use tokens instead of the standard cached tokens. - /// - /// A new limited-use tokens will be generated for each request; providing a smaller attack - /// surface for malicious parties to hijack tokens. When used alongside replay protection, - /// limited-use tokens are also _consumed_ after each request, ensuring they can't be used - /// again. + /// the usage of App Check's limited-use tokens instead of the standard cached tokens. Learn + /// more about [limited-use tokens](https://firebase.google.com/docs/ai-logic/app-check), + /// including their nuances, when to use them, and best practices for integrating them into + /// your app. /// /// _This flag is set to `false` by default._ - /// - /// > Important: Replay protection is not currently supported for the FirebaseAI backend. - /// > While this feature is being developed, you can still migrate to using - /// > limited-use tokens. Because limited-use tokens are backwards compatible, you can still - /// > use them without replay protection. Due to their shorter TTL over standard App Check - /// > tokens, they still provide a security benefit. - /// > /// > Migrating to limited-use tokens sooner minimizes disruption when support for replay /// > protection is added. /// - Returns: A `FirebaseAI` instance, configured with the custom `FirebaseApp`. @@ -110,8 +101,7 @@ public final class FirebaseAI: Sendable { tools: tools, toolConfig: toolConfig, systemInstruction: systemInstruction, - requestOptions: requestOptions, - useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens + requestOptions: requestOptions ) } @@ -147,8 +137,7 @@ public final class FirebaseAI: Sendable { apiConfig: apiConfig, generationConfig: generationConfig, safetySettings: safetySettings, - requestOptions: requestOptions, - useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens + requestOptions: requestOptions ) } @@ -163,8 +152,6 @@ public final class FirebaseAI: Sendable { let apiConfig: APIConfig - let useLimitedUseAppCheckTokens: Bool - /// A map of active `FirebaseAI` instances keyed by the `FirebaseApp` name and the `location`, /// in the format `appName:location`. private nonisolated(unsafe) static var instances: [InstanceKey: FirebaseAI] = [:] @@ -227,11 +214,11 @@ public final class FirebaseAI: Sendable { projectID: projectID, apiKey: apiKey, firebaseAppID: app.options.googleAppID, - firebaseApp: app + firebaseApp: app, + useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens ) self.apiConfig = apiConfig self.location = location - self.useLimitedUseAppCheckTokens = useLimitedUseAppCheckTokens } func modelResourceName(modelName: String) -> String { diff --git a/FirebaseAI/Sources/FirebaseInfo.swift b/FirebaseAI/Sources/FirebaseInfo.swift index c1f27aa7fe3..6b10dec4e5f 100644 --- a/FirebaseAI/Sources/FirebaseInfo.swift +++ b/FirebaseAI/Sources/FirebaseInfo.swift @@ -27,6 +27,7 @@ struct FirebaseInfo: Sendable { let projectID: String let apiKey: String let firebaseAppID: String + let useLimitedUseAppCheckTokens: Bool let app: FirebaseApp init(appCheck: AppCheckInterop? = nil, @@ -34,12 +35,14 @@ struct FirebaseInfo: Sendable { projectID: String, apiKey: String, firebaseAppID: String, - firebaseApp: FirebaseApp) { + firebaseApp: FirebaseApp, + useLimitedUseAppCheckTokens: Bool) { self.appCheck = appCheck self.auth = auth self.projectID = projectID self.apiKey = apiKey self.firebaseAppID = firebaseAppID + self.useLimitedUseAppCheckTokens = useLimitedUseAppCheckTokens app = firebaseApp } } diff --git a/FirebaseAI/Sources/GenerativeAIService.swift b/FirebaseAI/Sources/GenerativeAIService.swift index 5b676162c94..8056d4172b8 100644 --- a/FirebaseAI/Sources/GenerativeAIService.swift +++ b/FirebaseAI/Sources/GenerativeAIService.swift @@ -30,12 +30,9 @@ struct GenerativeAIService { private let urlSession: URLSession - private let useLimitedUseAppCheckTokens: Bool - - init(firebaseInfo: FirebaseInfo, urlSession: URLSession, useLimitedUseAppCheckTokens: Bool) { + init(firebaseInfo: FirebaseInfo, urlSession: URLSession) { self.firebaseInfo = firebaseInfo self.urlSession = urlSession - self.useLimitedUseAppCheckTokens = useLimitedUseAppCheckTokens } func loadRequest(request: T) async throws -> T.Response { @@ -212,7 +209,7 @@ struct GenerativeAIService { private func fetchAppCheckToken(appCheck: AppCheckInterop) async throws -> FIRAppCheckTokenResultInterop { - if useLimitedUseAppCheckTokens { + if firebaseInfo.useLimitedUseAppCheckTokens { if let token = await getLimitedUseAppCheckToken(appCheck: appCheck) { return token } @@ -242,7 +239,7 @@ struct GenerativeAIService { Never >) in guard - useLimitedUseAppCheckTokens, + firebaseInfo.useLimitedUseAppCheckTokens, // `getLimitedUseToken(completion:)` is an optional protocol method. Optional binding // is performed to make sure `continuation` is called even if the method’s not implemented. let limitedUseTokenClosure = appCheck.getLimitedUseToken diff --git a/FirebaseAI/Sources/GenerativeModel.swift b/FirebaseAI/Sources/GenerativeModel.swift index 2807022de59..8d3f5e043a7 100644 --- a/FirebaseAI/Sources/GenerativeModel.swift +++ b/FirebaseAI/Sources/GenerativeModel.swift @@ -76,8 +76,6 @@ public final class GenerativeModel: Sendable { /// only text content is supported. /// - requestOptions: Configuration parameters for sending requests to the backend. /// - urlSession: The `URLSession` to use for requests; defaults to `URLSession.shared`. - /// - useLimitedUseAppCheckTokens: Use App Check's limited-use tokens instead of the standard - /// cached tokens. init(modelName: String, modelResourceName: String, firebaseInfo: FirebaseInfo, @@ -88,15 +86,13 @@ public final class GenerativeModel: Sendable { toolConfig: ToolConfig? = nil, systemInstruction: ModelContent? = nil, requestOptions: RequestOptions, - urlSession: URLSession = GenAIURLSession.default, - useLimitedUseAppCheckTokens: Bool = false) { + urlSession: URLSession = GenAIURLSession.default) { self.modelName = modelName self.modelResourceName = modelResourceName self.apiConfig = apiConfig generativeAIService = GenerativeAIService( firebaseInfo: firebaseInfo, - urlSession: urlSession, - useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens + urlSession: urlSession ) self.generationConfig = generationConfig self.safetySettings = safetySettings diff --git a/FirebaseAI/Sources/Types/Public/Imagen/ImagenModel.swift b/FirebaseAI/Sources/Types/Public/Imagen/ImagenModel.swift index 542f842362c..729fad9f28d 100644 --- a/FirebaseAI/Sources/Types/Public/Imagen/ImagenModel.swift +++ b/FirebaseAI/Sources/Types/Public/Imagen/ImagenModel.swift @@ -53,14 +53,12 @@ public final class ImagenModel { generationConfig: ImagenGenerationConfig?, safetySettings: ImagenSafetySettings?, requestOptions: RequestOptions, - urlSession: URLSession = GenAIURLSession.default, - useLimitedUseAppCheckTokens: Bool = false) { + urlSession: URLSession = GenAIURLSession.default) { self.modelResourceName = modelResourceName self.apiConfig = apiConfig generativeAIService = GenerativeAIService( firebaseInfo: firebaseInfo, - urlSession: urlSession, - useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens + urlSession: urlSession ) self.generationConfig = generationConfig self.safetySettings = safetySettings diff --git a/FirebaseAI/Tests/Unit/ChatTests.swift b/FirebaseAI/Tests/Unit/ChatTests.swift index 4bf89f8cb51..7ecebf42e28 100644 --- a/FirebaseAI/Tests/Unit/ChatTests.swift +++ b/FirebaseAI/Tests/Unit/ChatTests.swift @@ -68,7 +68,8 @@ final class ChatTests: XCTestCase { projectID: "my-project-id", apiKey: "API_KEY", firebaseAppID: "My app ID", - firebaseApp: app + firebaseApp: app, + useLimitedUseAppCheckTokens: false ), apiConfig: FirebaseAI.defaultVertexAIAPIConfig, tools: nil, diff --git a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift index 80a383eb461..0e33ba557e6 100644 --- a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift +++ b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift @@ -507,13 +507,13 @@ final class GenerativeModelVertexAITests: XCTestCase { modelName: testModelName, modelResourceName: testModelResourceName, firebaseInfo: GenerativeModelTestUtil.testFirebaseInfo( - appCheck: AppCheckInteropFake(token: appCheckToken) + appCheck: AppCheckInteropFake(token: appCheckToken), + useLimitedUseAppCheckTokens: true ), apiConfig: apiConfig, tools: nil, requestOptions: RequestOptions(), - urlSession: urlSession, - useLimitedUseAppCheckTokens: true + urlSession: urlSession ) MockURLProtocol .requestHandler = try GenerativeModelTestUtil.httpRequestHandler( diff --git a/FirebaseAI/Tests/Unit/TestUtilities/GenerativeModelTestUtil.swift b/FirebaseAI/Tests/Unit/TestUtilities/GenerativeModelTestUtil.swift index 9b00f0b0c87..ee4f47bc5b0 100644 --- a/FirebaseAI/Tests/Unit/TestUtilities/GenerativeModelTestUtil.swift +++ b/FirebaseAI/Tests/Unit/TestUtilities/GenerativeModelTestUtil.swift @@ -103,7 +103,8 @@ enum GenerativeModelTestUtil { static func testFirebaseInfo(appCheck: AppCheckInterop? = nil, auth: AuthInterop? = nil, - privateAppID: Bool = false) -> FirebaseInfo { + privateAppID: Bool = false, + useLimitedUseAppCheckTokens: Bool = false) -> FirebaseInfo { let app = FirebaseApp(instanceWithName: "testApp", options: FirebaseOptions(googleAppID: "ignore", gcmSenderID: "ignore")) @@ -114,7 +115,8 @@ enum GenerativeModelTestUtil { projectID: "my-project-id", apiKey: "API_KEY", firebaseAppID: "My app ID", - firebaseApp: app + firebaseApp: app, + useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens ) } } From d5e2284825d151725184035392ded4ece4423f73 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Mon, 25 Aug 2025 17:44:20 -0400 Subject: [PATCH 53/76] chore(ci): Remove unused secret (#15247) --- .github/workflows/abtesting.yml | 2 -- .github/workflows/auth.yml | 2 -- .github/workflows/crashlytics.yml | 2 -- .github/workflows/database.yml | 1 - .github/workflows/firestore.yml | 1 - .github/workflows/functions.yml | 2 -- .github/workflows/inappmessaging.yml | 1 - .github/workflows/messaging.yml | 2 -- .github/workflows/performance.yml | 2 -- .github/workflows/prerelease.yml | 11 ----------- .github/workflows/release.yml | 11 ----------- .github/workflows/remoteconfig.yml | 2 -- .github/workflows/storage.yml | 2 -- .github/workflows/zip.yml | 9 --------- 14 files changed, 50 deletions(-) diff --git a/.github/workflows/abtesting.yml b/.github/workflows/abtesting.yml index b4ec5bef578..e7d25366464 100644 --- a/.github/workflows/abtesting.yml +++ b/.github/workflows/abtesting.yml @@ -45,7 +45,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} runs-on: macos-15 steps: - uses: actions/checkout@v4 @@ -70,7 +69,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} runs-on: macos-15 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/auth.yml b/.github/workflows/auth.yml index a8b04befda4..424ea3cada2 100644 --- a/.github/workflows/auth.yml +++ b/.github/workflows/auth.yml @@ -97,7 +97,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} runs-on: macos-15 steps: - uses: actions/checkout@v4 @@ -117,7 +116,6 @@ jobs: # env: # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - # signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} # runs-on: macos-14 # steps: # - uses: actions/checkout@v4 diff --git a/.github/workflows/crashlytics.yml b/.github/workflows/crashlytics.yml index 6d61284351a..60e103c672b 100644 --- a/.github/workflows/crashlytics.yml +++ b/.github/workflows/crashlytics.yml @@ -47,7 +47,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} runs-on: macos-15 steps: - uses: actions/checkout@v4 @@ -77,7 +76,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} runs-on: macos-15 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/database.yml b/.github/workflows/database.yml index 74a5bebe067..318ad0d9df5 100644 --- a/.github/workflows/database.yml +++ b/.github/workflows/database.yml @@ -73,7 +73,6 @@ jobs: if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} runs-on: macos-15 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/firestore.yml b/.github/workflows/firestore.yml index dbb144924d8..05b609aa0f7 100644 --- a/.github/workflows/firestore.yml +++ b/.github/workflows/firestore.yml @@ -605,7 +605,6 @@ jobs: # if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' # env: # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - # signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} # runs-on: macos-14 # needs: check diff --git a/.github/workflows/functions.yml b/.github/workflows/functions.yml index 658a78f1952..4cc466aa26e 100644 --- a/.github/workflows/functions.yml +++ b/.github/workflows/functions.yml @@ -56,7 +56,6 @@ jobs: # if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' # env: # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - # signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} # LEGACY: true # # TODO: Move to macos-14 and Xcode 15. The legacy quickstart uses material which doesn't build on Xcode 15. # runs-on: macos-12 @@ -83,7 +82,6 @@ jobs: # if: github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule' # env: # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - # signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} # LEGACY: true # # TODO: Move to macos-14 and Xcode 15. The legacy quickstart uses material which doesn't build on Xcode 15. # runs-on: macos-12 diff --git a/.github/workflows/inappmessaging.yml b/.github/workflows/inappmessaging.yml index edcf7b25b8d..408fb403960 100644 --- a/.github/workflows/inappmessaging.yml +++ b/.github/workflows/inappmessaging.yml @@ -90,7 +90,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} runs-on: macos-15 steps: diff --git a/.github/workflows/messaging.yml b/.github/workflows/messaging.yml index 2dd09288c22..ce1d6a180e4 100644 --- a/.github/workflows/messaging.yml +++ b/.github/workflows/messaging.yml @@ -84,7 +84,6 @@ jobs: if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} strategy: matrix: include: @@ -113,7 +112,6 @@ jobs: if: github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule' env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} runs-on: macos-15 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index d788c81a968..5b81b71fba4 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -81,7 +81,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} runs-on: macos-15 steps: - uses: actions/checkout@v4 @@ -104,7 +103,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} runs-on: macos-15 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 45cb46e10ab..6f098e2fc43 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -220,7 +220,6 @@ jobs: needs: buildup_SpecsTesting_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} runs-on: macos-15 steps: @@ -256,7 +255,6 @@ jobs: needs: buildup_SpecsTesting_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} runs-on: macos-15 steps: @@ -286,7 +284,6 @@ jobs: needs: buildup_SpecsTesting_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" @@ -329,7 +326,6 @@ jobs: needs: buildup_SpecsTesting_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" @@ -363,7 +359,6 @@ jobs: needs: buildup_SpecsTesting_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" @@ -397,7 +392,6 @@ jobs: # needs: buildup_SpecsTesting_repo # env: # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - # signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} # botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} # testing_repo_dir: "/tmp/test/" # testing_repo: "firebase-ios-sdk" @@ -437,7 +431,6 @@ jobs: needs: buildup_SpecsTesting_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" @@ -473,7 +466,6 @@ jobs: needs: buildup_SpecsTesting_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" @@ -509,7 +501,6 @@ jobs: needs: buildup_SpecsTesting_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} runs-on: macos-15 steps: @@ -539,7 +530,6 @@ jobs: needs: buildup_SpecsTesting_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" @@ -572,7 +562,6 @@ jobs: needs: buildup_SpecsTesting_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d29131a857e..e784215e1ca 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -156,7 +156,6 @@ jobs: needs: buildup_SpecsReleasing_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} runs-on: macos-15 steps: @@ -192,7 +191,6 @@ jobs: needs: buildup_SpecsReleasing_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} runs-on: macos-15 steps: @@ -222,7 +220,6 @@ jobs: needs: buildup_SpecsReleasing_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" @@ -265,7 +262,6 @@ jobs: needs: buildup_SpecsReleasing_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" @@ -299,7 +295,6 @@ jobs: needs: buildup_SpecsReleasing_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" @@ -333,7 +328,6 @@ jobs: # needs: buildup_SpecsReleasing_repo # env: # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - # signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} # botaccess: ${{ secrets.RELEASE_TESTING_PAT }} # testing_repo_dir: "/tmp/test/" # testing_repo: "firebase-ios-sdk" @@ -370,7 +364,6 @@ jobs: needs: buildup_SpecsReleasing_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" @@ -406,7 +399,6 @@ jobs: needs: buildup_SpecsReleasing_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" @@ -442,7 +434,6 @@ jobs: needs: buildup_SpecsReleasing_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} runs-on: macos-15 steps: @@ -472,7 +463,6 @@ jobs: needs: buildup_SpecsReleasing_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" @@ -505,7 +495,6 @@ jobs: needs: buildup_SpecsReleasing_repo env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} testing_repo_dir: "/tmp/test/" testing_repo: "firebase-ios-sdk" diff --git a/.github/workflows/remoteconfig.yml b/.github/workflows/remoteconfig.yml index 6b7ca4d68b3..906d0766aa3 100644 --- a/.github/workflows/remoteconfig.yml +++ b/.github/workflows/remoteconfig.yml @@ -88,7 +88,6 @@ jobs: if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} runs-on: macos-15 steps: - uses: actions/checkout@v4 @@ -109,7 +108,6 @@ jobs: # if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' # env: # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - # signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} # runs-on: macos-14 # steps: # - uses: actions/checkout@v4 diff --git a/.github/workflows/storage.yml b/.github/workflows/storage.yml index 47d19b294c6..910f91f480c 100644 --- a/.github/workflows/storage.yml +++ b/.github/workflows/storage.yml @@ -90,7 +90,6 @@ jobs: xcode: Xcode_16.4 env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} LEGACY: true runs-on: ${{ matrix.os }} steps: @@ -111,7 +110,6 @@ jobs: if: github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule' env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} LEGACY: true runs-on: macos-15 steps: diff --git a/.github/workflows/zip.yml b/.github/workflows/zip.yml index 10a02312ce0..429746ef071 100644 --- a/.github/workflows/zip.yml +++ b/.github/workflows/zip.yml @@ -107,7 +107,6 @@ jobs: needs: package-head env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "ABTesting" strategy: matrix: @@ -166,7 +165,6 @@ jobs: needs: package-head env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Authentication" strategy: matrix: @@ -217,7 +215,6 @@ jobs: needs: package-head env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Config" strategy: matrix: @@ -266,7 +263,6 @@ jobs: needs: package-head env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Crashlytics" strategy: matrix: @@ -338,7 +334,6 @@ jobs: needs: package-head env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Database" strategy: matrix: @@ -390,7 +385,6 @@ jobs: needs: package-head env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Firestore" strategy: matrix: @@ -478,7 +472,6 @@ jobs: needs: package-head env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "InAppMessaging" strategy: matrix: @@ -531,7 +524,6 @@ jobs: needs: package-head env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Messaging" strategy: matrix: @@ -584,7 +576,6 @@ jobs: needs: package-head env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Storage" strategy: matrix: From 788c8d462cca1c91b82b65e58df4902d9d912462 Mon Sep 17 00:00:00 2001 From: Seyed Mojtaba Hosseini Zeidabadi Date: Tue, 26 Aug 2025 16:55:20 +0330 Subject: [PATCH 54/76] docs: fix typos in firebase sessions (#15248) --- FirebaseSessions/Sources/SessionInitiator.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseSessions/Sources/SessionInitiator.swift b/FirebaseSessions/Sources/SessionInitiator.swift index 9524fdbae73..2e3afeaa729 100644 --- a/FirebaseSessions/Sources/SessionInitiator.swift +++ b/FirebaseSessions/Sources/SessionInitiator.swift @@ -51,7 +51,7 @@ class SessionInitiator { let notificationCenter = NotificationCenter.default #if os(iOS) || os(tvOS) || os(visionOS) - // Change background update event listerner for iPadOS 26 multi-windowing supoort + // Change background update event listener for iPadOS 26 multi-windowing support if #available(iOS 26, *), GULAppEnvironmentUtil.appleDevicePlatform().contains("ipados") { notificationCenter.addObserver( self, From a16f21d8605436ff121c161596ab324dd8544ede Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 26 Aug 2025 10:37:07 -0400 Subject: [PATCH 55/76] fix(ci): Update stalling remoteconfig.yml job to use retry action (#15250) --- .github/workflows/remoteconfig.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/remoteconfig.yml b/.github/workflows/remoteconfig.yml index 906d0766aa3..46d071e883a 100644 --- a/.github/workflows/remoteconfig.yml +++ b/.github/workflows/remoteconfig.yml @@ -72,7 +72,12 @@ jobs: - name: Xcode run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Fake Console API Tests - run: scripts/third_party/travis/retry.sh scripts/build.sh RemoteConfig ${{ matrix.target }} fakeconsole + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 + with: + timeout_minutes: 15 + max_attempts: 3 + retry_wait_seconds: 120 + command: scripts/build.sh RemoteConfig ${{ matrix.target }} fakeconsole - name: IntegrationTest if: matrix.target == 'iOS' # No retry to avoid exhausting AccessToken quota. From e1932704b1025c3a338ce15d8eb87a0c95fbf8e9 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 26 Aug 2025 11:42:41 -0400 Subject: [PATCH 56/76] chore(ci): Remove unused env vars in .github/workflows/[pre]release.yml (#15251) --- .github/workflows/prerelease.yml | 16 ---------------- .github/workflows/release.yml | 16 ---------------- 2 files changed, 32 deletions(-) diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 6f098e2fc43..5677aab2e88 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -285,8 +285,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} - testing_repo_dir: "/tmp/test/" - testing_repo: "firebase-ios-sdk" runs-on: macos-15 steps: - uses: actions/checkout@v4 @@ -327,8 +325,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} - testing_repo_dir: "/tmp/test/" - testing_repo: "firebase-ios-sdk" runs-on: macos-15 steps: - uses: actions/checkout@v4 @@ -360,8 +356,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} - testing_repo_dir: "/tmp/test/" - testing_repo: "firebase-ios-sdk" runs-on: macos-15 steps: - uses: actions/checkout@v4 @@ -393,8 +387,6 @@ jobs: # env: # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} # botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} - # testing_repo_dir: "/tmp/test/" - # testing_repo: "firebase-ios-sdk" # LEGACY: true # # TODO: The functions quickstart uses Material which isn't supported by Xcode 15 # runs-on: macos-12 @@ -432,8 +424,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} - testing_repo_dir: "/tmp/test/" - testing_repo: "firebase-ios-sdk" runs-on: macos-15 steps: - uses: actions/checkout@v4 @@ -467,8 +457,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} - testing_repo_dir: "/tmp/test/" - testing_repo: "firebase-ios-sdk" runs-on: macos-15 steps: - uses: actions/checkout@v4 @@ -531,8 +519,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} - testing_repo_dir: "/tmp/test/" - testing_repo: "firebase-ios-sdk" LEGACY: true runs-on: macos-15 steps: @@ -563,8 +549,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} - testing_repo_dir: "/tmp/test/" - testing_repo: "firebase-ios-sdk" runs-on: macos-15 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e784215e1ca..0c45c2b786d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -221,8 +221,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - testing_repo_dir: "/tmp/test/" - testing_repo: "firebase-ios-sdk" runs-on: macos-15 steps: - uses: actions/checkout@v4 @@ -263,8 +261,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - testing_repo_dir: "/tmp/test/" - testing_repo: "firebase-ios-sdk" runs-on: macos-15 steps: - uses: actions/checkout@v4 @@ -296,8 +292,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - testing_repo_dir: "/tmp/test/" - testing_repo: "firebase-ios-sdk" runs-on: macos-15 steps: - uses: actions/checkout@v4 @@ -329,8 +323,6 @@ jobs: # env: # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} # botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - # testing_repo_dir: "/tmp/test/" - # testing_repo: "firebase-ios-sdk" # LEGACY: true # runs-on: macos-12 # steps: @@ -365,8 +357,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - testing_repo_dir: "/tmp/test/" - testing_repo: "firebase-ios-sdk" runs-on: macos-15 steps: - uses: actions/checkout@v4 @@ -400,8 +390,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - testing_repo_dir: "/tmp/test/" - testing_repo: "firebase-ios-sdk" runs-on: macos-15 steps: - uses: actions/checkout@v4 @@ -464,8 +452,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - testing_repo_dir: "/tmp/test/" - testing_repo: "firebase-ios-sdk" LEGACY: true runs-on: macos-15 steps: @@ -496,8 +482,6 @@ jobs: env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - testing_repo_dir: "/tmp/test/" - testing_repo: "firebase-ios-sdk" runs-on: macos-15 steps: - uses: actions/checkout@v4 From 056de5b8889602bfad9a417433ed36a72f4faecd Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 26 Aug 2025 12:22:50 -0400 Subject: [PATCH 57/76] refactor(ci): Introduce common, re-usable quickstart workflow (#15245) --- .github/workflows/abtesting.yml | 30 ++----- .github/workflows/auth.yml | 29 +++--- .github/workflows/common_quickstart.yml | 114 ++++++++++++++++++++++++ .github/workflows/crashlytics.yml | 35 +++----- .github/workflows/database.yml | 32 +++---- .github/workflows/firestore.yml | 29 +++--- .github/workflows/functions.yml | 41 ++++----- .github/workflows/inappmessaging.yml | 36 +++----- .github/workflows/installations.yml | 31 +++---- .github/workflows/messaging.yml | 37 +++----- .github/workflows/performance.yml | 30 +++---- .github/workflows/remoteconfig.yml | 37 ++++---- .github/workflows/storage.yml | 36 +++----- 13 files changed, 267 insertions(+), 250 deletions(-) create mode 100644 .github/workflows/common_quickstart.yml diff --git a/.github/workflows/abtesting.yml b/.github/workflows/abtesting.yml index e7d25366464..6edd5ef83b0 100644 --- a/.github/workflows/abtesting.yml +++ b/.github/workflows/abtesting.yml @@ -13,6 +13,7 @@ on: - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' - '.github/workflows/common_catalyst.yml' + - '.github/workflows/common_quickstart.yml' - 'Gemfile*' schedule: # Run every day at 2am (PDT) / 5am (EDT) - cron uses UTC times @@ -40,28 +41,15 @@ jobs: product: FirebaseABTesting quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - env: + uses: ./.github/workflows/common_quickstart.yml + with: + product: ABTesting + is_legacy: true + setup_command: scripts/setup_quickstart.sh abtesting + plist_src_path: scripts/gha-encrypted/qs-database.plist.gpg + plist_dst_path: quickstart-ios/database/GoogleService-Info.plist + secrets: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Setup quickstart - env: - LEGACY: true - run: scripts/setup_quickstart.sh abtesting - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-abtesting.plist.gpg \ - quickstart-ios/abtesting/GoogleService-Info.plist "$plist_secret" - - name: Test swift quickstart - env: - LEGACY: true - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh ABTesting true) quickstart-ftl-cron-only: # Don't run on private repo. diff --git a/.github/workflows/auth.yml b/.github/workflows/auth.yml index 424ea3cada2..299397fc81e 100644 --- a/.github/workflows/auth.yml +++ b/.github/workflows/auth.yml @@ -13,6 +13,7 @@ on: - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' - '.github/workflows/common_catalyst.yml' + - '.github/workflows/common_quickstart.yml' - 'scripts/gha-encrypted/AuthSample/SwiftApplication.plist.gpg' - 'Gemfile*' schedule: @@ -92,22 +93,16 @@ jobs: command: ([ -z $plist_secret ] || scripts/build.sh Auth iOS ${{ matrix.scheme }}) quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - env: + uses: ./.github/workflows/common_quickstart.yml + with: + product: Authentication + is_legacy: false + setup_command: scripts/setup_quickstart.sh authentication + plist_src_path: scripts/gha-encrypted/qs-auth.plist.gpg + plist_dst_path: quickstart-ios/authentication/GoogleService-Info.plist + run_tests: false + secrets: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup quickstart - run: scripts/setup_quickstart.sh authentication - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-auth.plist.gpg \ - quickstart-ios/authentication/GoogleService-Info.plist "$plist_secret" - - name: Test swift quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Authentication false) # TODO(@sunmou99): currently have issue with this job, will re-enable it once the issue resolved. # quickstart-ftl-cron-only: @@ -116,6 +111,7 @@ jobs: # env: # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} + # signin_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} # runs-on: macos-14 # steps: # - uses: actions/checkout@v4 @@ -150,6 +146,9 @@ jobs: '--use-static-frameworks' ] needs: pod_lib_lint + env: + plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} + runs-on: macos-14 steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 diff --git a/.github/workflows/common_quickstart.yml b/.github/workflows/common_quickstart.yml new file mode 100644 index 00000000000..a3f965796ea --- /dev/null +++ b/.github/workflows/common_quickstart.yml @@ -0,0 +1,114 @@ +name: common_quickstart + +permissions: + contents: read + +on: + workflow_call: + # Re-usable workflows do not automatically inherit the caller's secrets. + # + # This workflow decrypts encrypted files, so the calling workflow needs to + # pass the secret to the re-usable workflow. + # + # Example: + # + # quickstart: + # uses: ./.github/workflows/common_quickstart.yml + # with: + # # ... + # secrets: + # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} + # + secrets: + plist_secret: + required: true + + inputs: + # The product to test be tested (e.g. `ABTesting`). + product: + type: string + required: true + + # Whether to test the legacy version of the quickstart. + is_legacy: + type: boolean + required: true + + # The path to the encrypted `GoogleService-Info.plist` file. + plist_src_path: + type: string + required: true + + # The destination path for the decrypted `GoogleService-Info.plist` file. + plist_dst_path: + type: string + required: true + + # The type of quickstart to test. + # + # Options: [swift, objc] + quickstart_type: + type: string + required: false + default: objc + + # Whether to run tests or just build. Defaults to true. + run_tests: + type: boolean + required: false + default: true + + # A command to execute before testing. + # + # Example: `scripts/setup_quickstart.sh functions` + setup_command: + type: string + required: false + default: "" + +jobs: + quickstart: + # Run on the main repo's scheduled jobs or pull requests and manual workflow invocations. + if: (github.repository == 'firebase/firebase-ios-sdk' && github.event_name == 'schedule') || contains(fromJSON('["pull_request", "workflow_dispatch"]'), github.event_name) + env: + plist_secret: ${{ secrets.plist_secret }} + LEGACY: ${{ inputs.is_legacy && true || '' }} + runs-on: macos-15 + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 + - name: Xcode + run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer + - name: Run setup command. + run: ${{ inputs.setup_command }} + - name: Install Secret GoogleService-Info.plist + run: | + scripts/decrypt_gha_secret.sh \ + ${{ inputs.plist_src_path }} \ + ${{ inputs.plist_dst_path }} \ + "$plist_secret" + - name: Build ${{ inputs.product }} Quickstart (${{ inputs.quickstart_type }} / ${{ inputs.is_legacy && 'Legacy' || 'Non-Legacy' }}) + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 + with: + timeout_minutes: 15 + max_attempts: 3 + retry_wait_seconds: 120 + command: | + scripts/test_quickstart.sh \ + ${{ inputs.product }} \ + ${{ inputs.run_tests }} \ + ${{ inputs.quickstart_type }} + # Failure sequence to upload artifact. + - id: lowercase_product + if: ${{ failure() }} + run: | + lowercase_product=$(echo "${{ inputs.product }}" | tr '[:upper:]' '[:lower:]') + echo "lowercase_product=$lowercase_product" >> $GITHUB_OUTPUT + - name: Remove data before upload. + if: ${{ failure() }} + run: scripts/remove_data.sh ${{ steps.lowercase_product.outputs.lowercase_product }} + - uses: actions/upload-artifact@v4 + if: ${{ failure() }} + with: + name: quickstart_artifacts_${{ steps.lowercase_product.outputs.lowercase_product }} + path: quickstart-ios/ diff --git a/.github/workflows/crashlytics.yml b/.github/workflows/crashlytics.yml index 60e103c672b..e88f692ebc3 100644 --- a/.github/workflows/crashlytics.yml +++ b/.github/workflows/crashlytics.yml @@ -13,6 +13,7 @@ on: - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' - '.github/workflows/common_catalyst.yml' + - '.github/workflows/common_quickstart.yml' - 'Interop/Analytics/Public/*.h' - 'Gemfile*' schedule: @@ -42,33 +43,21 @@ jobs: buildonly_platforms: tvOS, macOS, watchOS quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Setup quickstart - run: scripts/setup_quickstart.sh crashlytics - env: - LEGACY: true - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-crashlytics.plist.gpg \ - quickstart-ios/crashlytics/GoogleService-Info.plist "$plist_secret" - - name: Test swift quickstart - run: | + uses: ./.github/workflows/common_quickstart.yml + with: + product: Crashlytics + is_legacy: true + quickstart_type: swift + setup_command: | + scripts/setup_quickstart.sh crashlytics mkdir quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/Pods/FirebaseCrashlytics # Set the deployed pod location of run and upload-symbols with the development pod version. cp Crashlytics/run quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/Pods/FirebaseCrashlytics/ cp Crashlytics/upload-symbols quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/Pods/FirebaseCrashlytics/ - ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Crashlytics true swift) - env: - LEGACY: true + plist_src_path: scripts/gha-encrypted/qs-crashlytics.plist.gpg + plist_dst_path: quickstart-ios/crashlytics/GoogleService-Info.plist + secrets: + plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} quickstart-ftl-cron-only: # Don't run on private repo. diff --git a/.github/workflows/database.yml b/.github/workflows/database.yml index 318ad0d9df5..a5a297b445f 100644 --- a/.github/workflows/database.yml +++ b/.github/workflows/database.yml @@ -16,6 +16,7 @@ on: - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' - '.github/workflows/common_catalyst.yml' + - '.github/workflows/common_quickstart.yml' - 'Gemfile*' - 'scripts/run_database_emulator.sh' schedule: @@ -69,25 +70,20 @@ jobs: run: scripts/third_party/travis/retry.sh scripts/build.sh Database iOS integration quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - env: + uses: ./.github/workflows/common_quickstart.yml + strategy: + matrix: + quickstart_type: [objc, swift] + with: + product: Database + is_legacy: false + setup_command: scripts/setup_quickstart.sh database + plist_src_path: scripts/gha-encrypted/qs-database.plist.gpg + plist_dst_path: quickstart-ios/database/GoogleService-Info.plist + quickstart_type: ${{ matrix.quickstart_type }} + run_tests: false + secrets: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup quickstart - run: scripts/setup_quickstart.sh database - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-database.plist.gpg \ - quickstart-ios/database/GoogleService-Info.plist "$plist_secret" - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Test objc quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Database false) - - name: Test swift quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Database false swift) database-cron-only: # Don't run on private repo. diff --git a/.github/workflows/firestore.yml b/.github/workflows/firestore.yml index 05b609aa0f7..2a935f81fa0 100644 --- a/.github/workflows/firestore.yml +++ b/.github/workflows/firestore.yml @@ -598,23 +598,16 @@ jobs: if: needs.*.result == 'failure' run: exit 1 - # Disable until FirebaseUI is updated to accept Firebase 9 and quickstart is updated to accept - # Firebase UI 12 + # TODO: Disable until FirebaseUI is updated to accept Firebase 9 and + # quickstart is updated to accept Firebase UI 12 # quickstart: - # # Don't run on private repo unless it is a PR. - # if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - # env: + # uses: ./.github/workflows/common_quickstart.yml + # with: + # product: Firestore + # is_legacy: true + # setup_command: scripts/setup_quickstart.sh firestore + # plist_src_path: scripts/gha-encrypted/qs-firestore.plist.gpg + # plist_dst_path: quickstart-ios/firestore/GoogleService-Info.plist + # run_tests: false + # secrets: # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - # runs-on: macos-14 - # needs: check - - # steps: - # - uses: actions/checkout@v4 - # - name: Setup quickstart - # run: scripts/setup_quickstart.sh firestore - # - name: Install Secret GoogleService-Info.plist - # run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-firestore.plist.gpg \ - # quickstart-ios/firestore/GoogleService-Info.plist "$plist_secret" - # - name: Test swift quickstart - # run: ([ -z $plist_secret ] || - # scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Firestore false) diff --git a/.github/workflows/functions.yml b/.github/workflows/functions.yml index 4cc466aa26e..0563dea4059 100644 --- a/.github/workflows/functions.yml +++ b/.github/workflows/functions.yml @@ -50,32 +50,23 @@ jobs: with: target: FirebaseFunctionsUnit - # TODO: Move to macos-14 and Xcode 15. The legacy quickstart uses material which doesn't build on Xcode 15. + # TODO: The legacy quickstart uses material which doesn't build on Xcode 15. # quickstart: - # # Don't run on private repo unless it is a PR. - # if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - # env: - # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - # LEGACY: true - # # TODO: Move to macos-14 and Xcode 15. The legacy quickstart uses material which doesn't build on Xcode 15. - # runs-on: macos-12 - - # steps: - # - uses: actions/checkout@v4 - # - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - # - name: Setup quickstart - # run: scripts/setup_quickstart.sh functions - # - name: install secret googleservice-info.plist - # run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-functions.plist.gpg \ - # quickstart-ios/functions/GoogleService-Info.plist "$plist_secret" - # - name: Setup custom URL scheme - # run: sed -i '' 's/REVERSED_CLIENT_ID/com.googleusercontent.apps.1025801074639-6p6ebi8amuklcjrto20gvpe295smm8u6/' quickstart-ios/functions/LegacyFunctionsQuickstart/FunctionsExample/Info.plist - # - name: Test objc quickstart - # run: ([ -z $plist_secret ] || - # scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Functions true) - # - name: Test swift quickstart - # run: ([ -z $plist_secret ] || - # scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Functions true swift) + # uses: ./.github/workflows/common_quickstart.yml + # strategy: + # matrix: + # quickstart_type: [objc, swift] + # with: + # product: Functions + # is_legacy: true + # setup_command: | + # scripts/setup_quickstart.sh functions + # sed -i '' 's/REVERSED_CLIENT_ID/com.googleusercontent.apps.1025801074639-6p6ebi8amuklcjrto20gvpe295smm8u6/' quickstart-ios/functions/LegacyFunctionsQuickstart/FunctionsExample/Info.plist + # plist_src_path: scripts/gha-encrypted/qs-functions.plist.gpg + # plist_dst_path: quickstart-ios/functions/GoogleService-Info.plist + # quickstart_type: ${{ matrix.quickstart_type }} + # secrets: + # plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} # quickstart-ftl-cron-only: # # Don't run on private repo diff --git a/.github/workflows/inappmessaging.yml b/.github/workflows/inappmessaging.yml index 408fb403960..61118a10d1f 100644 --- a/.github/workflows/inappmessaging.yml +++ b/.github/workflows/inappmessaging.yml @@ -12,6 +12,7 @@ on: - '.github/workflows/inappmessaging.yml' - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' + - '.github/workflows/common_quickstart.yml' - 'Gemfile*' schedule: # Run every day at 11pm (PDT) / 2am (EDT) - cron uses UTC times @@ -85,27 +86,16 @@ jobs: run: scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseInAppMessaging.podspec --platforms=${{ matrix.platform }} ${{ matrix.flags }} quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - env: + uses: ./.github/workflows/common_quickstart.yml + strategy: + matrix: + quickstart_type: [objc, swift] + with: + product: InAppMessaging + is_legacy: false + quickstart_type: ${{ matrix.quickstart_type }} + setup_command: scripts/setup_quickstart.sh inappmessaging + plist_src_path: scripts/gha-encrypted/qs-inappmessaging.plist.gpg + plist_dst_path: quickstart-ios/inappmessaging/GoogleService-Info.plist + secrets: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - runs-on: macos-15 - - steps: - - uses: actions/checkout@v4 - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Setup quickstart - run: scripts/setup_quickstart.sh inappmessaging - - name: install secret googleservice-info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-inappmessaging.plist.gpg \ - quickstart-ios/inappmessaging/GoogleService-Info.plist "$plist_secret" - - name: Test objc quickstart - run: ([ -z $plist_secret ] || - scripts/third_party/travis/retry.sh scripts/test_quickstart.sh InAppMessaging true) - - name: Test swift quickstart - run: ([ -z $plist_secret ] || - scripts/third_party/travis/retry.sh scripts/test_quickstart.sh InAppMessaging true swift) diff --git a/.github/workflows/installations.yml b/.github/workflows/installations.yml index 8a87c9dd341..54f95f0b67d 100644 --- a/.github/workflows/installations.yml +++ b/.github/workflows/installations.yml @@ -12,6 +12,7 @@ on: - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' - '.github/workflows/common_catalyst.yml' + - '.github/workflows/common_quickstart.yml' - 'Gemfile*' schedule: # Run every day at 11pm (PDT) / 2am (EDT) - cron uses UTC times @@ -48,23 +49,19 @@ jobs: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Setup quickstart - run: scripts/setup_quickstart.sh installations - - name: Copy mock plist - run: cp quickstart-ios/mock-GoogleService-Info.plist quickstart-ios/installations/GoogleService-Info.plist - - name: Test objc quickstart - run: scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Installations true - - name: Test swift quickstart - run: scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Installations true swift + uses: ./.github/workflows/common_quickstart.yml + strategy: + matrix: + quickstart_type: [objc, swift] + with: + product: Installations + is_legacy: false + setup_command: scripts/setup_quickstart.sh installations + plist_src_path: scripts/gha-encrypted/Installations/GoogleService-Info.plist.gpg + plist_dst_path: quickstart-ios/installations/GoogleService-Info.plist + quickstart_type: ${{ matrix.quickstart_type }} + secrets: + plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} quickstart-ftl-cron-only: # Don't run on private repo. diff --git a/.github/workflows/messaging.yml b/.github/workflows/messaging.yml index ce1d6a180e4..b1227c3e9eb 100644 --- a/.github/workflows/messaging.yml +++ b/.github/workflows/messaging.yml @@ -19,6 +19,7 @@ on: - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' - '.github/workflows/common_catalyst.yml' + - '.github/workflows/common_quickstart.yml' # Rebuild on Ruby infrastructure changes - 'Gemfile*' schedule: @@ -80,32 +81,20 @@ jobs: run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/build.sh Messaging all) quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} + uses: ./.github/workflows/common_quickstart.yml strategy: matrix: - include: - - os: macos-15 - xcode: Xcode_16.4 - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup quickstart - run: scripts/setup_quickstart.sh messaging - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-messaging.plist.gpg \ - quickstart-ios/messaging/GoogleService-Info.plist "$plist_secret" - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - - name: Test objc quickstart - run: ([ -z $plist_secret ] || - scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Messaging false) - - name: Test swift quickstart - run: ([ -z $plist_secret ] || - scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Messaging false swift) + quickstart_type: [objc, swift] + with: + product: Messaging + is_legacy: false + quickstart_type: ${{ matrix.quickstart_type }} + setup_command: scripts/setup_quickstart.sh messaging + plist_src_path: scripts/gha-encrypted/qs-messaging.plist.gpg + plist_dst_path: quickstart-ios/messaging/GoogleService-Info.plist + run_tests: false + secrets: + plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} quickstart-ftl-cron-only: # Don't run on private repo. diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 5b81b71fba4..b0d01161259 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -19,6 +19,7 @@ on: - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' - '.github/workflows/common_catalyst.yml' + - '.github/workflows/common_quickstart.yml' # Rebuild on Ruby infrastructure changes - 'Gemfile*' schedule: @@ -76,27 +77,18 @@ jobs: #TODO: tests are not supported with Xcode 15 because the test spec depends on the iOS 8 GDCWebServer buildonly_platforms: iOS, tvOS + # TODO: The legacy ObjC quickstarts don't run with Xcode 15, re-able if we get these working. quickstart: - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - - env: + uses: ./.github/workflows/common_quickstart.yml + with: + product: Performance + is_legacy: false + quickstart_type: swift + setup_command: scripts/setup_quickstart.sh performance + plist_src_path: scripts/gha-encrypted/qs-performance.plist.gpg + plist_dst_path: quickstart-ios/performance/GoogleService-Info.plist + secrets: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Setup quickstart - run: scripts/setup_quickstart.sh performance - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-performance.plist.gpg \ - quickstart-ios/performance/GoogleService-Info.plist "$plist_secret" - - name: Test swift quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Performance true swift) - # TODO: The legacy ObjC quickstarts don't run with Xcode 15, re-able if we get these working. - # - name: Test objc quickstart - # run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Performance true) quickstart-ftl-cron-only: if: github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule' diff --git a/.github/workflows/remoteconfig.yml b/.github/workflows/remoteconfig.yml index 46d071e883a..9b60ed6be19 100644 --- a/.github/workflows/remoteconfig.yml +++ b/.github/workflows/remoteconfig.yml @@ -13,6 +13,7 @@ on: - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' - '.github/workflows/common_catalyst.yml' + - '.github/workflows/common_quickstart.yml' - 'Gemfile*' - 'scripts/generate_access_token.sh' - 'scripts/gha-encrypted/RemoteConfigSwiftAPI/**' @@ -72,12 +73,12 @@ jobs: - name: Xcode run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Fake Console API Tests - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 - with: - timeout_minutes: 15 - max_attempts: 3 - retry_wait_seconds: 120 - command: scripts/build.sh RemoteConfig ${{ matrix.target }} fakeconsole + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 + with: + timeout_minutes: 15 + max_attempts: 3 + retry_wait_seconds: 120 + command: scripts/build.sh RemoteConfig ${{ matrix.target }} fakeconsole - name: IntegrationTest if: matrix.target == 'iOS' # No retry to avoid exhausting AccessToken quota. @@ -89,23 +90,15 @@ jobs: product: FirebaseRemoteConfig quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' - env: + uses: ./.github/workflows/common_quickstart.yml + with: + product: Config + is_legacy: false + setup_command: scripts/setup_quickstart.sh config + plist_src_path: scripts/gha-encrypted/qs-config.plist.gpg + plist_dst_path: quickstart-ios/config/GoogleService-Info.plist + secrets: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Setup quickstart - run: scripts/setup_quickstart.sh config - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-config.plist.gpg \ - quickstart-ios/config/GoogleService-Info.plist "$plist_secret" - - name: Test Swift Quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Config true) # TODO(@sunmou99): currently have issue with this job, will re-enable it once the issue resolved. # quickstart-ftl-cron-only: diff --git a/.github/workflows/storage.yml b/.github/workflows/storage.yml index 910f91f480c..29449d9fe85 100644 --- a/.github/workflows/storage.yml +++ b/.github/workflows/storage.yml @@ -13,6 +13,7 @@ on: - '.github/workflows/common.yml' - '.github/workflows/common_cocoapods.yml' - '.github/workflows/common_catalyst.yml' + - '.github/workflows/common_quickstart.yml' # Rebuild on Ruby infrastructure changes. - 'Gemfile*' schedule: @@ -77,33 +78,18 @@ jobs: command: ([ -z $plist_secret ] || scripts/build.sh Storage${{ matrix.language }} all) quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' # TODO: See #12399 and restore Objective-C testing for Xcode 15 if GHA is fixed. - strategy: - matrix: - include: - #- os: macos-13 - # xcode: Xcode_14.2 # TODO: the legacy ObjC quickstart doesn't build with Xcode 15. - - swift: swift - os: macos-15 - xcode: Xcode_16.4 - env: + uses: ./.github/workflows/common_quickstart.yml + with: + product: Storage + quickstart_type: swift + is_legacy: true + setup_command: scripts/setup_quickstart.sh storage + plist_src_path: scripts/gha-encrypted/qs-storage.plist.gpg + plist_dst_path: quickstart-ios/storage/GoogleService-Info.plist + run_tests: false + secrets: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - LEGACY: true - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup quickstart - run: scripts/setup_quickstart.sh storage - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-storage.plist.gpg \ - quickstart-ios/storage/GoogleService-Info.plist "$plist_secret" - - name: Xcode - run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer - - name: Test quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Storage false ${{ matrix.swift }}) quickstart-ftl-cron-only: # Don't run on private repo. From 8f7f164af1543255bfb1d0f58dae7594146e8fc3 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 26 Aug 2025 13:44:14 -0400 Subject: [PATCH 58/76] chore(ci): Run prerelease.yml when it changes (#15253) --- .github/workflows/prerelease.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 5677aab2e88..c2c1fb96df7 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -7,6 +7,8 @@ on: pull_request: # closed will be triggered when a pull request is merged. This is to keep https://github.com/firebase/SpecsTesting up to date. types: [closed] + paths: + - '.github/workflows/prerelease.yml' workflow_dispatch: schedule: # Run every day at 10pm (PDT) / 1am (EDT) - cron uses UTC times From e40142ecbd150fe48475090f3b6b347b44d11113 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 26 Aug 2025 14:43:39 -0400 Subject: [PATCH 59/76] fix(ci): Remove duplicate `runs-on` use in auth.yml (#15254) --- .github/workflows/auth.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/auth.yml b/.github/workflows/auth.yml index 299397fc81e..b34a5fd9bd0 100644 --- a/.github/workflows/auth.yml +++ b/.github/workflows/auth.yml @@ -148,7 +148,6 @@ jobs: needs: pod_lib_lint env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - runs-on: macos-14 steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 From dabcd3f2dc354b474b0fc6f2862d154b27fe7f0c Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 26 Aug 2025 14:47:36 -0400 Subject: [PATCH 60/76] fix(ci): Fix syntax errors in remoteconfig.yml (#15255) --- .github/workflows/remoteconfig.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/workflows/remoteconfig.yml b/.github/workflows/remoteconfig.yml index 9b60ed6be19..5dc0984c517 100644 --- a/.github/workflows/remoteconfig.yml +++ b/.github/workflows/remoteconfig.yml @@ -73,12 +73,12 @@ jobs: - name: Xcode run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - name: Fake Console API Tests - uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 - with: - timeout_minutes: 15 - max_attempts: 3 - retry_wait_seconds: 120 - command: scripts/build.sh RemoteConfig ${{ matrix.target }} fakeconsole + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 + with: + timeout_minutes: 15 + max_attempts: 3 + retry_wait_seconds: 120 + command: scripts/build.sh RemoteConfig ${{ matrix.target }} fakeconsole - name: IntegrationTest if: matrix.target == 'iOS' # No retry to avoid exhausting AccessToken quota. @@ -153,9 +153,7 @@ jobs: strategy: matrix: target: [ios, tvos, macos] - flags: [ - '--skip-tests --use-static-frameworks' - ] + flags: ['--skip-tests --use-static-frameworks'] needs: pod_lib_lint steps: - uses: actions/checkout@v4 From 176f0839aefadccfe286ee3057f59899e0657975 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 27 Aug 2025 09:29:24 -0400 Subject: [PATCH 61/76] refactor(ci): Consolidate quickstart jobs in prerelease.yml (#15252) --- .github/workflows/prerelease.yml | 379 ++++-------------- ....plist.gpg => qs-authentication.plist.gpg} | Bin 2 files changed, 81 insertions(+), 298 deletions(-) rename scripts/gha-encrypted/{qs-auth.plist.gpg => qs-authentication.plist.gpg} (100%) diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index c2c1fb96df7..ee5cea1113d 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -215,172 +215,6 @@ jobs: pod repo add --silent "${local_repo}" https://"$botaccess"@github.com/Firebase/SpecsTesting.git BOT_TOKEN="${botaccess}" .build/debug/spec-repo-builder --sdk-repo $(pwd) --local-spec-repo-name "${local_repo}" --sdk-repo-name SpecsTesting --github-account Firebase --pod-sources 'https://${BOT_TOKEN}@github.com/Firebase/SpecsTesting' "https://github.com/firebase/SpecsDev.git" "https://github.com/firebase/SpecsStaging.git" "https://cdn.cocoapods.org/" "FirebaseFirestoreTestingSupport" "FirebaseAuthTestingSupport" "FirebaseCombineSwift" --keep-repo --include-pods "${updated_podspecs[@]}" - abtesting_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'workflow_dispatch' - - needs: buildup_SpecsTesting_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Setup testing repo and quickstart - env: - LEGACY: true - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh abtesting prerelease_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-abtesting.plist.gpg \ - quickstart-ios/abtesting/GoogleService-Info.plist "$plist_secret" - - name: Test swift quickstart - env: - LEGACY: true - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh ABTesting true) - - name: Remove data before upload - env: - LEGACY: true - if: ${{ failure() }} - run: scripts/remove_data.sh config - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: quickstart_artifacts_abtesting - path: quickstart-ios/ - - auth_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsTesting_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Setup testing repo and quickstart - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh Authentication prerelease_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-auth.plist.gpg \ - quickstart-ios/authentication/GoogleService-Info.plist "$plist_secret" - - name: Test swift quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Authentication false) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh authentication - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: quickstart_artifacts_auth - path: quickstart-ios/ - - crashlytics_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsTesting_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Setup testing repo and quickstart - env: - LEGACY: true - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh Crashlytics prerelease_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-crashlytics.plist.gpg \ - quickstart-ios/crashlytics/GoogleService-Info.plist "$plist_secret" - - name: Test swift quickstart - env: - LEGACY: true - run: | - mkdir -p quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/Pods/FirebaseCrashlytics - # Set the deployed pod location of run and upload-symbols with the development pod version. - cp Crashlytics/run quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/Pods/FirebaseCrashlytics/ - cp Crashlytics/upload-symbols quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/Pods/FirebaseCrashlytics/ - ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Crashlytics true swift) - - name: Remove data before upload - env: - LEGACY: true - if: ${{ failure() }} - run: scripts/remove_data.sh crashlytics - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: quickstart_artifacts_crashlytics - path: quickstart-ios/ - - database_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsTesting_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Setup testing repo and quickstart - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh database prerelease_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-database.plist.gpg \ - quickstart-ios/database/GoogleService-Info.plist "$plist_secret" - - name: Test objc quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Database false) - - name: Test swift quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Database false swift) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh database - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: quickstart_artifacts_database - path: quickstart-ios/ - - firestore_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsTesting_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Setup testing repo and quickstart - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh firestore prerelease_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-firestore.plist.gpg \ - quickstart-ios/firestore/GoogleService-Info.plist "$plist_secret" - - name: Test swift quickstart - run: ([ -z $plist_secret ] || - scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Firestore false) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh firestore - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: quickstart_artifacts_firestore - path: quickstart-ios/ - # TODO: The functions quickstart uses Material which isn't supported by Xcode 15 #functions_quickstart: # Don't run on private repo unless it is a PR. @@ -419,156 +253,105 @@ jobs: # name: quickstart_artifacts_functions # path: quickstart-ios/ - inappmessaging_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsTesting_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Setup testing repo and quickstart - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh inappmessaging prerelease_testing - - name: install secret googleservice-info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-inappmessaging.plist.gpg \ - quickstart-ios/inappmessaging/GoogleService-Info.plist "$plist_secret" - - name: Test objc quickstart - run: ([ -z $plist_secret ] || - scripts/third_party/travis/retry.sh scripts/test_quickstart.sh InAppMessaging true) - - name: Test swift quickstart - run: ([ -z $plist_secret ] || - scripts/third_party/travis/retry.sh scripts/test_quickstart.sh InAppMessaging true swift) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh inappmessaging - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: quickstart_artifacts_inappmessaging - path: quickstart-ios/ - - messaging_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsTesting_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Setup testing repo and quickstart - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh messaging prerelease_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-messaging.plist.gpg \ - quickstart-ios/messaging/GoogleService-Info.plist "$plist_secret" - - name: Test objc quickstart - run: ([ -z $plist_secret ] || - scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Messaging false) - - name: Test swift quickstart - run: ([ -z $plist_secret ] || - scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Messaging false swift) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh messaging - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: quickstart_artifacts_messaging - path: quickstart-ios/ - - remoteconfig_quickstart: + quickstart: # Don't run on private repo unless it is a PR. if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'workflow_dispatch' needs: buildup_SpecsTesting_repo + strategy: + matrix: + include: + - product: Performance + run_tests: true + swift: true + - product: Storage + is_legacy: true + run_tests: true + swift: true + - product: Config + run_tests: true + objc: true + - product: Messaging + run_tests: false + swift: true + objc: true + - product: InAppMessaging + run_tests: true + swift: true + objc: true + - product: Firestore + run_tests: false + - product: Database + run_tests: false + swift: true + objc: true + - product: Authentication + run_tests: false + objc: true + - product: Crashlytics + is_legacy: true + run_tests: true + objc: false + swift: true + setup_command: | + mkdir -p quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/Pods/FirebaseCrashlytics + # Set the deployed pod location of run and upload-symbols with the development pod version. + cp Crashlytics/run quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/Pods/FirebaseCrashlytics/ + cp Crashlytics/upload-symbols quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/Pods/FirebaseCrashlytics/ + - product: ABTesting + is_legacy: true + run_tests: true + objc: true env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} + LEGACY: ${{ matrix.is_legacy && true || '' }} runs-on: macos-15 steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer + - name: Get lowercase product name. + id: lowercase_product + run: | + lowercase_product=$(echo "${{ matrix.product }}" | tr '[:upper:]' '[:lower:]') + echo "lowercase_product=$lowercase_product" >> $GITHUB_OUTPUT - name: Setup testing repo and quickstart - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh config prerelease_testing + run: | + lowercase_product=${{ steps.lowercase_product.outputs.lowercase_product }} + BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh $lowercase_product prerelease_testing - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-config.plist.gpg \ - quickstart-ios/config/GoogleService-Info.plist "$plist_secret" - - name: Test Swift Quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Config true) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh config - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} + run: | + lowercase_product = ${{ steps.lowercase_product.outputs.lowercase_product }} + scripts/decrypt_gha_secret.sh \ + scripts/gha-encrypted/qs-$lowercase_product.plist.gpg \ + quickstart-ios/$lowercase_product/GoogleService-Info.plist \ + "$plist_secret" + - name: Run setup command, if needed. + if: matrix.setup_command != '' + run: ${{ matrix.setup_command }} + - name: Build Swift quickstart + if: matrix.swift == true + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: - name: quickstart_artifacts_config - path: quickstart-ios/ - - storage_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsTesting_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} - LEGACY: true - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Setup testing repo and quickstart - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh storage prerelease_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-storage.plist.gpg \ - quickstart-ios/storage/GoogleService-Info.plist "$plist_secret" - - name: Test swift quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Storage true swift) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh storage - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} + timeout_minutes: 15 + max_attempts: 3 + retry_wait_seconds: 120 + command: scripts/test_quickstart.sh ${{ matrix.product }} ${{ matrix.run_tests }} swift + - name: Build Obj-C quickstart + if: matrix.objc == true + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: - name: quickstart_artifacts_storage - path: quickstart-ios/ - - performance_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsTesting_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.PRERELEASE_TESTING_PAT }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Xcode - run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Setup testing repo and quickstart - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh Performance prerelease_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-performance.plist.gpg \ - quickstart-ios/performance/GoogleService-Info.plist "$plist_secret" - - name: Test swift quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Performance true swift) - - name: Remove data before upload + timeout_minutes: 15 + max_attempts: 3 + retry_wait_seconds: 120 + command: scripts/test_quickstart.sh ${{ matrix.product }} ${{ matrix.run_tests }} + # Failure sequence to upload artifact. + - name: Remove data before upload. if: ${{ failure() }} - run: scripts/remove_data.sh performance + run: scripts/remove_data.sh ${{ steps.lowercase_product.outputs.lowercase_product }} - uses: actions/upload-artifact@v4 if: ${{ failure() }} with: - name: quickstart_artifacts_performance + name: quickstart_artifacts_${{ steps.lowercase_product.outputs.lowercase_product }} path: quickstart-ios/ diff --git a/scripts/gha-encrypted/qs-auth.plist.gpg b/scripts/gha-encrypted/qs-authentication.plist.gpg similarity index 100% rename from scripts/gha-encrypted/qs-auth.plist.gpg rename to scripts/gha-encrypted/qs-authentication.plist.gpg From b70b4112f2d6eb97609c234adf626722cd58e642 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Wed, 27 Aug 2025 14:53:59 -0400 Subject: [PATCH 62/76] fix(ci): Update to clang-format@21 (#15260) --- CONTRIBUTING.md | 2 +- README.md | 2 +- scripts/setup_check.sh | 2 +- scripts/style.sh | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0a460cbdd87..2679fbd217e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -132,7 +132,7 @@ To develop Firebase software, **install**: To install [clang-format] and [mint] using [Homebrew]: ```console - brew install clang-format@20 + brew install clang-format@21 brew install mint ``` diff --git a/README.md b/README.md index 6c5168f8bbe..15a560d92f7 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,7 @@ GitHub Actions will verify that any code changes are done in a style-compliant way. Install `clang-format` and `mint`: ```console -brew install clang-format@20 +brew install clang-format@21 brew install mint ``` diff --git a/scripts/setup_check.sh b/scripts/setup_check.sh index 805596a9ae6..faf4715c688 100755 --- a/scripts/setup_check.sh +++ b/scripts/setup_check.sh @@ -35,7 +35,7 @@ fi # install clang-format brew update -brew install clang-format@20 +brew install clang-format@21 # mint installs tools from Mintfile on demand. brew install mint diff --git a/scripts/style.sh b/scripts/style.sh index 72a31312d72..c8c15f5155a 100755 --- a/scripts/style.sh +++ b/scripts/style.sh @@ -56,7 +56,7 @@ version="${version/ (*)/}" version="${version/.*/}" case "$version" in - 20) + 21) ;; google3-trunk) echo "Please use a publicly released clang-format; a recent LLVM release" @@ -65,7 +65,7 @@ case "$version" in exit 1 ;; *) - echo "Please upgrade to clang-format version 20." + echo "Please upgrade to clang-format version 21." echo "If it's installed via homebrew you can run:" echo "brew upgrade clang-format" exit 1 From c54b0de4ef49e84d21d374b5750743bfab2abbf8 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Wed, 27 Aug 2025 15:54:35 -0400 Subject: [PATCH 63/76] [Release] Update Carthage artifacts for 12.2.0 (#15263) --- ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAIBinary.json | 3 ++- ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json | 1 + .../CarthageJSON/FirebaseMLModelDownloaderBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json | 1 + ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json | 1 + 17 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json index 46bcfece798..4dc290fc4b4 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseABTestingBinary.json @@ -46,6 +46,7 @@ "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseABTesting-5436773ba2b9326e.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseABTesting-bd721c84362383a6.zip", "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseABTesting-bb0e44f97fd81c31.zip", + "12.2.0": "https://dl.google.com/dl/firebase/ios/carthage/12.2.0/FirebaseABTesting-328b9123860fa215.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/ABTesting-d0fdf10c43e985b1.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/ABTesting-d0fdf10c43e985b1.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/ABTesting-a71d17cadc209af9.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json index ba7d7cb3685..493bacd3a80 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAIBinary.json @@ -3,5 +3,6 @@ "11.14.0": "https://dl.google.com/dl/firebase/ios/carthage/11.14.0/FirebaseAI-0991ef5c3a83833a.zip", "11.15.0": "https://dl.google.com/dl/firebase/ios/carthage/11.15.0/FirebaseAI-ba1237ee5b7a5baa.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseAI-05a4568076093001.zip", - "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseAI-1fa7d016c66b2331.zip" + "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseAI-1fa7d016c66b2331.zip", + "12.2.0": "https://dl.google.com/dl/firebase/ios/carthage/12.2.0/FirebaseAI-8fac222fb35cd84e.zip" } diff --git a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json index 6628fc3fdda..054ce256713 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAnalyticsBinary.json @@ -46,6 +46,7 @@ "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseAnalytics-fe649e5740ef72e9.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseAnalytics-70ead21957efa870.zip", "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseAnalytics-88dad74aa8ab040a.zip", + "12.2.0": "https://dl.google.com/dl/firebase/ios/carthage/12.2.0/FirebaseAnalytics-b37787f72cdbb950.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Analytics-2468c231ebeb7922.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Analytics-bc8101d420b896c5.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Analytics-d2b6a6b0242db786.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json index 209eee8f4d4..d6682a9e7f3 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAppCheckBinary.json @@ -46,6 +46,7 @@ "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseAppCheck-366c926c105319b0.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseAppCheck-b9f47f169bb6249c.zip", "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseAppCheck-072a1be1f8eb1177.zip", + "12.2.0": "https://dl.google.com/dl/firebase/ios/carthage/12.2.0/FirebaseAppCheck-dac2380c7e1b9898.zip", "8.0.0": "https://dl.google.com/dl/firebase/ios/carthage/8.0.0/FirebaseAppCheck-9ef1d217cf057203.zip", "8.1.0": "https://dl.google.com/dl/firebase/ios/carthage/8.1.0/FirebaseAppCheck-fc03215d9fe45d3a.zip", "8.10.0": "https://dl.google.com/dl/firebase/ios/carthage/8.10.0/FirebaseAppCheck-6ebe9e9539f06003.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json index 252385766d7..da411015d0a 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAppDistributionBinary.json @@ -46,6 +46,7 @@ "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseAppDistribution-32e12df219d91736.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseAppDistribution-076c2c6efb7eb8dc.zip", "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseAppDistribution-370884f5f825f098.zip", + "12.2.0": "https://dl.google.com/dl/firebase/ios/carthage/12.2.0/FirebaseAppDistribution-042b04483c9241b6.zip", "6.31.0": "https://dl.google.com/dl/firebase/ios/carthage/6.31.0/FirebaseAppDistribution-07f6a2cf7f576a8a.zip", "6.32.0": "https://dl.google.com/dl/firebase/ios/carthage/6.32.0/FirebaseAppDistribution-a9c4f5db794508ca.zip", "6.33.0": "https://dl.google.com/dl/firebase/ios/carthage/6.33.0/FirebaseAppDistribution-448a96d2ade54581.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json b/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json index 65ac8b39fec..087bb03cb96 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseAuthBinary.json @@ -46,6 +46,7 @@ "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseAuth-ab131b2e07abc902.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseAuth-e58b2b5f430bfbfe.zip", "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseAuth-2c17100b302eb080.zip", + "12.2.0": "https://dl.google.com/dl/firebase/ios/carthage/12.2.0/FirebaseAuth-9f0a14da6c12ea6d.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Auth-0fa76ba0f7956220.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Auth-5ddd2b4351012c7a.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Auth-5e248984d78d7284.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json index cc05921dcfd..a2af858e249 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseCrashlyticsBinary.json @@ -46,6 +46,7 @@ "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseCrashlytics-81aa29d9a106acb0.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseCrashlytics-d9a9be2a4e220017.zip", "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseCrashlytics-fbf241b0c59f3821.zip", + "12.2.0": "https://dl.google.com/dl/firebase/ios/carthage/12.2.0/FirebaseCrashlytics-623ce628d0404f39.zip", "6.15.0": "https://dl.google.com/dl/firebase/ios/carthage/6.15.0/FirebaseCrashlytics-1c6d22d5b73c84fd.zip", "6.16.0": "https://dl.google.com/dl/firebase/ios/carthage/6.16.0/FirebaseCrashlytics-938e5fd0e2eab3b3.zip", "6.17.0": "https://dl.google.com/dl/firebase/ios/carthage/6.17.0/FirebaseCrashlytics-fa09f0c8f31ed5d9.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json b/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json index 0959ea0af13..8e9f4fa6ea5 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseDatabaseBinary.json @@ -46,6 +46,7 @@ "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseDatabase-8b970d6e0f67a415.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseDatabase-18b95ef28b89f3db.zip", "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseDatabase-d6c24e13e4b05437.zip", + "12.2.0": "https://dl.google.com/dl/firebase/ios/carthage/12.2.0/FirebaseDatabase-a87ae96a7eeb2535.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Database-1f7a820452722c7d.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Database-1f7a820452722c7d.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Database-59a12d87456b3e1c.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json b/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json index b724c13a0de..2e5d344364e 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseFirestoreBinary.json @@ -46,6 +46,7 @@ "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseFirestore-30a2451150d46015.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseFirestore-635c7c2864cdd1a9.zip", "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseFirestore-6098779ef7b7b151.zip", + "12.2.0": "https://dl.google.com/dl/firebase/ios/carthage/12.2.0/FirebaseFirestore-8d65b82dc9d53ddf.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Firestore-68fc02c229d0cc69.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Firestore-87a804ab561d91db.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Firestore-ecb3eea7bde7e8e8.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json b/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json index cce3563815c..f3cf5077781 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseFunctionsBinary.json @@ -46,6 +46,7 @@ "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseFunctions-1681244d37d89040.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseFunctions-2ac7bbbaf94c52e1.zip", "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseFunctions-f4a1c660d9a2ea75.zip", + "12.2.0": "https://dl.google.com/dl/firebase/ios/carthage/12.2.0/FirebaseFunctions-f3aa95160827b0af.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Functions-f4c426016dd41e38.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Functions-c6c44427c3034736.zip", "5.0.0": "https://dl.google.com/dl/firebase/ios/carthage/5.0.0/Functions-146f34c401bd459b.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json b/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json index 87f96dd518f..44bb103f3ac 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseGoogleSignInBinary.json @@ -46,6 +46,7 @@ "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/GoogleSignIn-d4359fb699843869.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/GoogleSignIn-b924d38d37bc920a.zip", "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/GoogleSignIn-01f98c11db934294.zip", + "12.2.0": "https://dl.google.com/dl/firebase/ios/carthage/12.2.0/GoogleSignIn-31b2e32d1dadbaa8.zip", "6.0.0": "https://dl.google.com/dl/firebase/ios/carthage/6.0.0/GoogleSignIn-de9c5d5e8eb6d6ea.zip", "6.1.0": "https://dl.google.com/dl/firebase/ios/carthage/6.1.0/GoogleSignIn-8c82f2870573a793.zip", "6.10.0": "https://dl.google.com/dl/firebase/ios/carthage/6.10.0/GoogleSignIn-ff3aef61c4a55b05.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json index d83b9ffff48..cb089894be6 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseInAppMessagingBinary.json @@ -46,6 +46,7 @@ "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseInAppMessaging-67bccdf31b1dc458.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseInAppMessaging-59f9fc54fc4eecb5.zip", "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseInAppMessaging-78a0d591fb574512.zip", + "12.2.0": "https://dl.google.com/dl/firebase/ios/carthage/12.2.0/FirebaseInAppMessaging-0ec7907b67ce2888.zip", "5.10.0": "https://dl.google.com/dl/firebase/ios/carthage/5.10.0/InAppMessaging-a7a3f933362f6e95.zip", "5.11.0": "https://dl.google.com/dl/firebase/ios/carthage/5.11.0/InAppMessaging-fa28ce1b88fbca93.zip", "5.12.0": "https://dl.google.com/dl/firebase/ios/carthage/5.12.0/InAppMessaging-fa28ce1b88fbca93.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json b/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json index 1f8860d484f..3d2e26797bd 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseMLModelDownloaderBinary.json @@ -46,6 +46,7 @@ "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseMLModelDownloader-2d08410294abf160.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseMLModelDownloader-1f183c6e3be7cab3.zip", "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseMLModelDownloader-3864d35f4429bc08.zip", + "12.2.0": "https://dl.google.com/dl/firebase/ios/carthage/12.2.0/FirebaseMLModelDownloader-6bfb3459ae557ef3.zip", "8.0.0": "https://dl.google.com/dl/firebase/ios/carthage/8.0.0/FirebaseMLModelDownloader-8f972757fb181320.zip", "8.1.0": "https://dl.google.com/dl/firebase/ios/carthage/8.1.0/FirebaseMLModelDownloader-058ad59fa6dc0111.zip", "8.10.0": "https://dl.google.com/dl/firebase/ios/carthage/8.10.0/FirebaseMLModelDownloader-286479a966d2fb37.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json b/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json index 4fc0c68b1ca..ba4b4663e5d 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseMessagingBinary.json @@ -46,6 +46,7 @@ "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseMessaging-379bf3738f94ef44.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseMessaging-0f018ab3d7701839.zip", "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseMessaging-252cac88c87e9c55.zip", + "12.2.0": "https://dl.google.com/dl/firebase/ios/carthage/12.2.0/FirebaseMessaging-d1ab6eaf596d9b7d.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Messaging-a22ef2b5f2f30f82.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Messaging-94fa4e090c7e9185.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Messaging-2a00a1c64a19d176.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json b/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json index 0237b8ed2c3..5c16479a908 100644 --- a/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebasePerformanceBinary.json @@ -46,6 +46,7 @@ "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebasePerformance-9a2f8d3983650cea.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebasePerformance-0df8c67ab3cb665c.zip", "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebasePerformance-dec4dc5c3edadd9a.zip", + "12.2.0": "https://dl.google.com/dl/firebase/ios/carthage/12.2.0/FirebasePerformance-1913383f1952dce6.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Performance-d8693eb892bfa05b.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Performance-0a400f9460f7a71d.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Performance-f5b4002ab96523e4.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json b/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json index 9027616f5d0..ecc201dff62 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseRemoteConfigBinary.json @@ -46,6 +46,7 @@ "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseRemoteConfig-7455afe6f2231467.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseRemoteConfig-5894aa4820a265ae.zip", "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseRemoteConfig-bb5ba29a5f73cd24.zip", + "12.2.0": "https://dl.google.com/dl/firebase/ios/carthage/12.2.0/FirebaseRemoteConfig-3e803b148769baed.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/RemoteConfig-7e9635365ccd4a17.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/RemoteConfig-e7928fcb6311c439.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/RemoteConfig-9ab1ca5f360a1780.zip", diff --git a/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json b/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json index b753e8be256..836e19050a3 100644 --- a/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json +++ b/ReleaseTooling/CarthageJSON/FirebaseStorageBinary.json @@ -46,6 +46,7 @@ "11.9.0": "https://dl.google.com/dl/firebase/ios/carthage/11.9.0/FirebaseStorage-5a28ee1b2244be55.zip", "12.0.0": "https://dl.google.com/dl/firebase/ios/carthage/12.0.0/FirebaseStorage-21ed034a4fa51f2a.zip", "12.1.0": "https://dl.google.com/dl/firebase/ios/carthage/12.1.0/FirebaseStorage-faeffdccd0d44a7c.zip", + "12.2.0": "https://dl.google.com/dl/firebase/ios/carthage/12.2.0/FirebaseStorage-20489713b94790a0.zip", "4.11.0": "https://dl.google.com/dl/firebase/ios/carthage/4.11.0/Storage-6b3e77e1a7fdbc61.zip", "4.12.0": "https://dl.google.com/dl/firebase/ios/carthage/4.12.0/Storage-4721c35d2b90a569.zip", "4.9.0": "https://dl.google.com/dl/firebase/ios/carthage/4.9.0/Storage-821299369b9d0fb2.zip", From 71937eb1a423f0f194d508a7b362639e98667f42 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Wed, 27 Aug 2025 13:43:46 -0700 Subject: [PATCH 64/76] Fix whitespace causing docs to not generate (#15264) --- FirebaseAI/Sources/FirebaseAI.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseAI/Sources/FirebaseAI.swift b/FirebaseAI/Sources/FirebaseAI.swift index 7cb33e30a33..7f05d8a0d7b 100644 --- a/FirebaseAI/Sources/FirebaseAI.swift +++ b/FirebaseAI/Sources/FirebaseAI.swift @@ -27,7 +27,7 @@ public final class FirebaseAI: Sendable { /// Creates an instance of `FirebaseAI`. /// - /// - Parameters: + /// - Parameters: /// - app: A custom `FirebaseApp` used for initialization; if not specified, uses the default /// ``FirebaseApp``. /// - backend: The backend API for the Firebase AI SDK; if not specified, uses the default From 5727a7b794e64b0be7ce2279bed7dcf4c6004491 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Wed, 27 Aug 2025 23:14:54 -0400 Subject: [PATCH 65/76] [Release] Update versions for 12.3.0 (#15265) --- Firebase.podspec | 44 +++++++++---------- FirebaseABTesting.podspec | 4 +- FirebaseAI.podspec | 10 ++--- FirebaseAnalytics.podspec | 12 ++--- FirebaseAppCheck.podspec | 6 +-- FirebaseAppCheckInterop.podspec | 2 +- FirebaseAppDistribution.podspec | 6 +-- FirebaseAuth.podspec | 10 ++--- FirebaseAuthInterop.podspec | 2 +- FirebaseCombineSwift.podspec | 14 +++--- FirebaseCore.podspec | 4 +- FirebaseCoreExtension.podspec | 4 +- FirebaseCoreInternal.podspec | 2 +- FirebaseCrashlytics.podspec | 10 ++--- FirebaseDatabase.podspec | 10 ++--- FirebaseFirestore.podspec | 10 ++--- FirebaseFirestoreInternal.podspec | 6 +-- FirebaseFunctions.podspec | 14 +++--- FirebaseInAppMessaging.podspec | 8 ++-- FirebaseInstallations.podspec | 4 +- FirebaseMLModelDownloader.podspec | 8 ++-- FirebaseMessaging.podspec | 6 +-- FirebaseMessagingInterop.podspec | 2 +- FirebasePerformance.podspec | 10 ++--- FirebaseRemoteConfig.podspec | 12 ++--- FirebaseRemoteConfigInterop.podspec | 2 +- FirebaseSessions.podspec | 8 ++-- FirebaseSharedSwift.podspec | 2 +- FirebaseStorage.podspec | 14 +++--- GoogleAppMeasurement.podspec | 8 ++-- Package.swift | 2 +- .../FirebaseManifest/FirebaseManifest.swift | 2 +- 32 files changed, 129 insertions(+), 129 deletions(-) diff --git a/Firebase.podspec b/Firebase.podspec index 415d933d8e0..1a9364b4ad7 100644 --- a/Firebase.podspec +++ b/Firebase.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Firebase' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Firebase' s.description = <<-DESC @@ -36,14 +36,14 @@ Simplify your app development, grow your user base, and monetize more effectivel ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '15.0' - ss.ios.dependency 'FirebaseAnalytics', '~> 12.2.0' - ss.osx.dependency 'FirebaseAnalytics', '~> 12.2.0' - ss.tvos.dependency 'FirebaseAnalytics', '~> 12.2.0' + ss.ios.dependency 'FirebaseAnalytics', '~> 12.3.0' + ss.osx.dependency 'FirebaseAnalytics', '~> 12.3.0' + ss.tvos.dependency 'FirebaseAnalytics', '~> 12.3.0' ss.dependency 'Firebase/CoreOnly' end s.subspec 'CoreOnly' do |ss| - ss.dependency 'FirebaseCore', '~> 12.2.0' + ss.dependency 'FirebaseCore', '~> 12.3.0' ss.source_files = 'CoreOnly/Sources/Firebase.h' ss.preserve_paths = 'CoreOnly/Sources/module.modulemap' if ENV['FIREBASE_POD_REPO_FOR_DEV_POD'] then @@ -70,7 +70,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'ABTesting' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseABTesting', '~> 12.2.0' + ss.dependency 'FirebaseABTesting', '~> 12.3.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -80,13 +80,13 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'AppDistribution' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseAppDistribution', '~> 12.2.0-beta' + ss.ios.dependency 'FirebaseAppDistribution', '~> 12.3.0-beta' ss.ios.deployment_target = '15.0' end s.subspec 'AppCheck' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseAppCheck', '~> 12.2.0' + ss.dependency 'FirebaseAppCheck', '~> 12.3.0' ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '15.0' @@ -95,7 +95,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Auth' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseAuth', '~> 12.2.0' + ss.dependency 'FirebaseAuth', '~> 12.3.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -105,7 +105,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Crashlytics' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseCrashlytics', '~> 12.2.0' + ss.dependency 'FirebaseCrashlytics', '~> 12.3.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -115,7 +115,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Database' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseDatabase', '~> 12.2.0' + ss.dependency 'FirebaseDatabase', '~> 12.3.0' # Standard platforms PLUS watchOS 7. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -125,7 +125,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Firestore' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseFirestore', '~> 12.2.0' + ss.dependency 'FirebaseFirestore', '~> 12.3.0' ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' ss.tvos.deployment_target = '15.0' @@ -133,7 +133,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Functions' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseFunctions', '~> 12.2.0' + ss.dependency 'FirebaseFunctions', '~> 12.3.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -143,20 +143,20 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'InAppMessaging' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebaseInAppMessaging', '~> 12.2.0-beta' - ss.tvos.dependency 'FirebaseInAppMessaging', '~> 12.2.0-beta' + ss.ios.dependency 'FirebaseInAppMessaging', '~> 12.3.0-beta' + ss.tvos.dependency 'FirebaseInAppMessaging', '~> 12.3.0-beta' ss.ios.deployment_target = '15.0' ss.tvos.deployment_target = '15.0' end s.subspec 'Installations' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseInstallations', '~> 12.2.0' + ss.dependency 'FirebaseInstallations', '~> 12.3.0' end s.subspec 'Messaging' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseMessaging', '~> 12.2.0' + ss.dependency 'FirebaseMessaging', '~> 12.3.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -166,7 +166,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'MLModelDownloader' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseMLModelDownloader', '~> 12.2.0-beta' + ss.dependency 'FirebaseMLModelDownloader', '~> 12.3.0-beta' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -176,15 +176,15 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Performance' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.ios.dependency 'FirebasePerformance', '~> 12.2.0' - ss.tvos.dependency 'FirebasePerformance', '~> 12.2.0' + ss.ios.dependency 'FirebasePerformance', '~> 12.3.0' + ss.tvos.dependency 'FirebasePerformance', '~> 12.3.0' ss.ios.deployment_target = '15.0' ss.tvos.deployment_target = '15.0' end s.subspec 'RemoteConfig' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseRemoteConfig', '~> 12.2.0' + ss.dependency 'FirebaseRemoteConfig', '~> 12.3.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' @@ -194,7 +194,7 @@ Simplify your app development, grow your user base, and monetize more effectivel s.subspec 'Storage' do |ss| ss.dependency 'Firebase/CoreOnly' - ss.dependency 'FirebaseStorage', '~> 12.2.0' + ss.dependency 'FirebaseStorage', '~> 12.3.0' # Standard platforms PLUS watchOS. ss.ios.deployment_target = '15.0' ss.osx.deployment_target = '10.15' diff --git a/FirebaseABTesting.podspec b/FirebaseABTesting.podspec index d6cfb519ae4..403e11741f8 100644 --- a/FirebaseABTesting.podspec +++ b/FirebaseABTesting.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseABTesting' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Firebase ABTesting' s.description = <<-DESC @@ -51,7 +51,7 @@ Firebase Cloud Messaging and Firebase Remote Config in your app. s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } - s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.3.0' s.test_spec 'unit' do |unit_tests| unit_tests.scheme = { :code_coverage => true } diff --git a/FirebaseAI.podspec b/FirebaseAI.podspec index 9b5787bf038..25a9e71dec5 100644 --- a/FirebaseAI.podspec +++ b/FirebaseAI.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAI' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Firebase AI SDK' s.description = <<-DESC @@ -43,10 +43,10 @@ Build AI-powered apps and features with the Gemini API using the Firebase AI SDK s.tvos.framework = 'UIKit' s.watchos.framework = 'WatchKit' - s.dependency 'FirebaseAppCheckInterop', '~> 12.2.0' - s.dependency 'FirebaseAuthInterop', '~> 12.2.0' - s.dependency 'FirebaseCore', '~> 12.2.0' - s.dependency 'FirebaseCoreExtension', '~> 12.2.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.3.0' + s.dependency 'FirebaseAuthInterop', '~> 12.3.0' + s.dependency 'FirebaseCore', '~> 12.3.0' + s.dependency 'FirebaseCoreExtension', '~> 12.3.0' s.test_spec 'unit' do |unit_tests| unit_tests_dir = 'FirebaseAI/Tests/Unit/' diff --git a/FirebaseAnalytics.podspec b/FirebaseAnalytics.podspec index 67515303300..bba40f73c84 100644 --- a/FirebaseAnalytics.podspec +++ b/FirebaseAnalytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAnalytics' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Firebase Analytics for iOS' s.description = <<-DESC @@ -26,8 +26,8 @@ Pod::Spec.new do |s| s.libraries = 'c++', 'sqlite3', 'z' s.frameworks = 'StoreKit' - s.dependency 'FirebaseCore', '~> 12.2.0' - s.dependency 'FirebaseInstallations', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.3.0' + s.dependency 'FirebaseInstallations', '~> 12.3.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/MethodSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/NSData+zlib', '~> 8.1' @@ -37,17 +37,17 @@ Pod::Spec.new do |s| s.default_subspecs = 'Default' s.subspec 'Default' do |ss| - ss.dependency 'GoogleAppMeasurement/Default', '12.2.0' + ss.dependency 'GoogleAppMeasurement/Default', '12.3.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end s.subspec 'Core' do |ss| - ss.dependency 'GoogleAppMeasurement/Core', '12.2.0' + ss.dependency 'GoogleAppMeasurement/Core', '12.3.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end s.subspec 'IdentitySupport' do |ss| - ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.2.0' + ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.3.0' ss.vendored_frameworks = 'Frameworks/FirebaseAnalytics.xcframework' end diff --git a/FirebaseAppCheck.podspec b/FirebaseAppCheck.podspec index 86d023c4c3d..90d7c768ef9 100644 --- a/FirebaseAppCheck.podspec +++ b/FirebaseAppCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppCheck' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Firebase App Check SDK.' s.description = <<-DESC @@ -45,8 +45,8 @@ Pod::Spec.new do |s| s.tvos.weak_framework = 'DeviceCheck' s.dependency 'AppCheckCore', '~> 11.0' - s.dependency 'FirebaseAppCheckInterop', '~> 12.2.0' - s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.3.0' + s.dependency 'FirebaseCore', '~> 12.3.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseAppCheckInterop.podspec b/FirebaseAppCheckInterop.podspec index 5b2a61f6134..e1869c3ba33 100644 --- a/FirebaseAppCheckInterop.podspec +++ b/FirebaseAppCheckInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppCheckInterop' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Interfaces that allow other Firebase SDKs to use AppCheck functionality.' s.description = <<-DESC diff --git a/FirebaseAppDistribution.podspec b/FirebaseAppDistribution.podspec index 853a66272b6..32c29999e8a 100644 --- a/FirebaseAppDistribution.podspec +++ b/FirebaseAppDistribution.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAppDistribution' - s.version = '12.2.0-beta' + s.version = '12.3.0-beta' s.summary = 'App Distribution for Firebase iOS SDK.' s.description = <<-DESC @@ -30,10 +30,10 @@ iOS SDK for App Distribution for Firebase. ] s.public_header_files = base_dir + 'Public/FirebaseAppDistribution/*.h' - s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.3.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' - s.dependency 'FirebaseInstallations', '~> 12.2.0' + s.dependency 'FirebaseInstallations', '~> 12.3.0' s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' diff --git a/FirebaseAuth.podspec b/FirebaseAuth.podspec index e192db98da9..5e47dc61b87 100644 --- a/FirebaseAuth.podspec +++ b/FirebaseAuth.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAuth' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Apple platform client for Firebase Authentication' s.description = <<-DESC @@ -55,10 +55,10 @@ supports email and password accounts, as well as several 3rd party authenticatio } s.framework = 'Security' s.ios.framework = 'SafariServices' - s.dependency 'FirebaseAuthInterop', '~> 12.2.0' - s.dependency 'FirebaseAppCheckInterop', '~> 12.2.0' - s.dependency 'FirebaseCore', '~> 12.2.0' - s.dependency 'FirebaseCoreExtension', '~> 12.2.0' + s.dependency 'FirebaseAuthInterop', '~> 12.3.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.3.0' + s.dependency 'FirebaseCore', '~> 12.3.0' + s.dependency 'FirebaseCoreExtension', '~> 12.3.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 6.0' diff --git a/FirebaseAuthInterop.podspec b/FirebaseAuthInterop.podspec index c5c5877c8d1..305fb25050d 100644 --- a/FirebaseAuthInterop.podspec +++ b/FirebaseAuthInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseAuthInterop' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Auth functionality.' s.description = <<-DESC diff --git a/FirebaseCombineSwift.podspec b/FirebaseCombineSwift.podspec index e25c93a9bdf..c427399b7c6 100644 --- a/FirebaseCombineSwift.podspec +++ b/FirebaseCombineSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCombineSwift' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Swift extensions with Combine support for Firebase' s.description = <<-DESC @@ -51,11 +51,11 @@ for internal testing only. It should not be published. s.osx.framework = 'AppKit' s.tvos.framework = 'UIKit' - s.dependency 'FirebaseCore', '~> 12.2.0' - s.dependency 'FirebaseAuth', '~> 12.2.0' - s.dependency 'FirebaseFunctions', '~> 12.2.0' - s.dependency 'FirebaseFirestore', '~> 12.2.0' - s.dependency 'FirebaseStorage', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.3.0' + s.dependency 'FirebaseAuth', '~> 12.3.0' + s.dependency 'FirebaseFunctions', '~> 12.3.0' + s.dependency 'FirebaseFirestore', '~> 12.3.0' + s.dependency 'FirebaseStorage', '~> 12.3.0' s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"', @@ -104,6 +104,6 @@ for internal testing only. It should not be published. int_tests.resources = 'FirebaseStorage/Tests/Integration/Resources/1mb.dat', 'FirebaseStorage/Tests/Integration/Resources/GoogleService-Info.plist', 'FirebaseStorage/Tests/Integration/Resources/HomeImprovement.numbers' - int_tests.dependency 'FirebaseAuth', '~> 12.2.0' + int_tests.dependency 'FirebaseAuth', '~> 12.3.0' end end diff --git a/FirebaseCore.podspec b/FirebaseCore.podspec index 77c336ba8c4..1cfd124c6f4 100644 --- a/FirebaseCore.podspec +++ b/FirebaseCore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCore' - s.version = '12.2.0' + s.version = '12.3.0' 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.1' s.dependency 'GoogleUtilities/Logger', '~> 8.1' - s.dependency 'FirebaseCoreInternal', '~> 12.2.0' + s.dependency 'FirebaseCoreInternal', '~> 12.3.0' s.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'Firebase_VERSION=' + s.version.to_s, diff --git a/FirebaseCoreExtension.podspec b/FirebaseCoreExtension.podspec index b7c893d25c1..21ee3852697 100644 --- a/FirebaseCoreExtension.podspec +++ b/FirebaseCoreExtension.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCoreExtension' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Extended FirebaseCore APIs for Firebase product SDKs' s.description = <<-DESC @@ -34,5 +34,5 @@ Pod::Spec.new do |s| "#{s.module_name}_Privacy" => 'FirebaseCore/Extension/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.3.0' end diff --git a/FirebaseCoreInternal.podspec b/FirebaseCoreInternal.podspec index a5832bb6e8e..d07d9a7f190 100644 --- a/FirebaseCoreInternal.podspec +++ b/FirebaseCoreInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCoreInternal' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'APIs for internal FirebaseCore usage.' s.description = <<-DESC diff --git a/FirebaseCrashlytics.podspec b/FirebaseCrashlytics.podspec index 8675001983c..3cbc3825050 100644 --- a/FirebaseCrashlytics.podspec +++ b/FirebaseCrashlytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseCrashlytics' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Best and lightest-weight crash reporting for mobile, desktop and tvOS.' s.description = 'Firebase Crashlytics helps you track, prioritize, and fix stability issues that erode app quality.' s.homepage = 'https://firebase.google.com/' @@ -59,10 +59,10 @@ Pod::Spec.new do |s| cp -f ./Crashlytics/CrashlyticsInputFiles.xcfilelist ./CrashlyticsInputFiles.xcfilelist PREPARE_COMMAND_END - s.dependency 'FirebaseCore', '~> 12.2.0' - s.dependency 'FirebaseInstallations', '~> 12.2.0' - s.dependency 'FirebaseSessions', '~> 12.2.0' - s.dependency 'FirebaseRemoteConfigInterop', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.3.0' + s.dependency 'FirebaseInstallations', '~> 12.3.0' + s.dependency 'FirebaseSessions', '~> 12.3.0' + s.dependency 'FirebaseRemoteConfigInterop', '~> 12.3.0' s.dependency 'PromisesObjC', '~> 2.4' s.dependency 'GoogleDataTransport', '~> 10.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' diff --git a/FirebaseDatabase.podspec b/FirebaseDatabase.podspec index 86931787c3b..c323f144338 100644 --- a/FirebaseDatabase.podspec +++ b/FirebaseDatabase.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseDatabase' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Firebase Realtime Database' s.description = <<-DESC @@ -48,9 +48,9 @@ Simplify your iOS development, grow your user base, and monetize more effectivel s.macos.frameworks = 'CFNetwork', 'Security', 'SystemConfiguration' s.watchos.frameworks = 'CFNetwork', 'Security', 'WatchKit' s.dependency 'leveldb-library', '~> 1.22' - s.dependency 'FirebaseCore', '~> 12.2.0' - s.dependency 'FirebaseAppCheckInterop', '~> 12.2.0' - s.dependency 'FirebaseSharedSwift', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.3.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.3.0' + s.dependency 'FirebaseSharedSwift', '~> 12.3.0' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' @@ -72,7 +72,7 @@ Simplify your iOS development, grow your user base, and monetize more effectivel 'SharedTestUtilities/FIRComponentTestUtilities.[mh]', 'SharedTestUtilities/FIROptionsMock.[mh]', ] - unit_tests.dependency 'FirebaseAppCheckInterop', '~> 12.2.0' + unit_tests.dependency 'FirebaseAppCheckInterop', '~> 12.3.0' unit_tests.dependency 'OCMock' unit_tests.resources = 'FirebaseDatabase/Tests/Resources/syncPointSpec.json', 'FirebaseDatabase/Tests/Resources/GoogleService-Info.plist' diff --git a/FirebaseFirestore.podspec b/FirebaseFirestore.podspec index df500387412..0e73ea1f60d 100644 --- a/FirebaseFirestore.podspec +++ b/FirebaseFirestore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFirestore' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Google Cloud Firestore' s.description = <<-DESC Google Cloud Firestore is a NoSQL document database built for automatic scaling, high performance, and ease of application development. @@ -35,9 +35,9 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, "#{s.module_name}_Privacy" => 'Firestore/Swift/Source/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseCore', '~> 12.2.0' - s.dependency 'FirebaseCoreExtension', '~> 12.2.0' - s.dependency 'FirebaseFirestoreInternal', '~> 12.2.0' - s.dependency 'FirebaseSharedSwift', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.3.0' + s.dependency 'FirebaseCoreExtension', '~> 12.3.0' + s.dependency 'FirebaseFirestoreInternal', '~> 12.3.0' + s.dependency 'FirebaseSharedSwift', '~> 12.3.0' end diff --git a/FirebaseFirestoreInternal.podspec b/FirebaseFirestoreInternal.podspec index b2881725ecb..9dfd6e30ac2 100644 --- a/FirebaseFirestoreInternal.podspec +++ b/FirebaseFirestoreInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFirestoreInternal' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Google Cloud Firestore' s.description = <<-DESC @@ -91,8 +91,8 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, "#{s.module_name}_Privacy" => 'Firestore/Source/Resources/PrivacyInfo.xcprivacy' } - s.dependency 'FirebaseAppCheckInterop', '~> 12.2.0' - s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.3.0' + s.dependency 'FirebaseCore', '~> 12.3.0' abseil_version = '~> 1.20240722.0' s.dependency 'abseil/algorithm', abseil_version diff --git a/FirebaseFunctions.podspec b/FirebaseFunctions.podspec index 52bbf0f26c1..c6e04fbdfc1 100644 --- a/FirebaseFunctions.podspec +++ b/FirebaseFunctions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseFunctions' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Cloud Functions for Firebase' s.description = <<-DESC @@ -35,12 +35,12 @@ Cloud Functions for Firebase. 'FirebaseFunctions/Sources/**/*.swift', ] - s.dependency 'FirebaseCore', '~> 12.2.0' - s.dependency 'FirebaseCoreExtension', '~> 12.2.0' - s.dependency 'FirebaseAppCheckInterop', '~> 12.2.0' - s.dependency 'FirebaseAuthInterop', '~> 12.2.0' - s.dependency 'FirebaseMessagingInterop', '~> 12.2.0' - s.dependency 'FirebaseSharedSwift', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.3.0' + s.dependency 'FirebaseCoreExtension', '~> 12.3.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.3.0' + s.dependency 'FirebaseAuthInterop', '~> 12.3.0' + s.dependency 'FirebaseMessagingInterop', '~> 12.3.0' + s.dependency 'FirebaseSharedSwift', '~> 12.3.0' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 6.0' s.test_spec 'objc' do |objc_tests| diff --git a/FirebaseInAppMessaging.podspec b/FirebaseInAppMessaging.podspec index ed309155b99..3921a9d7c59 100644 --- a/FirebaseInAppMessaging.podspec +++ b/FirebaseInAppMessaging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseInAppMessaging' - s.version = '12.2.0-beta' + s.version = '12.3.0-beta' s.summary = 'Firebase In-App Messaging for iOS' s.description = <<-DESC @@ -80,9 +80,9 @@ See more product details at https://firebase.google.com/products/in-app-messagin s.framework = 'UIKit' - s.dependency 'FirebaseCore', '~> 12.2.0' - s.dependency 'FirebaseInstallations', '~> 12.2.0' - s.dependency 'FirebaseABTesting', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.3.0' + s.dependency 'FirebaseInstallations', '~> 12.3.0' + s.dependency 'FirebaseABTesting', '~> 12.3.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' s.dependency 'nanopb', '~> 3.30910.0' diff --git a/FirebaseInstallations.podspec b/FirebaseInstallations.podspec index 217fe097416..be91f3a0c72 100644 --- a/FirebaseInstallations.podspec +++ b/FirebaseInstallations.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseInstallations' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Firebase Installations' s.description = <<-DESC @@ -45,7 +45,7 @@ Pod::Spec.new do |s| } s.framework = 'Security' - s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.3.0' s.dependency 'PromisesObjC', '~> 2.4' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseMLModelDownloader.podspec b/FirebaseMLModelDownloader.podspec index 1c19d2e8746..7d8e926cbcf 100644 --- a/FirebaseMLModelDownloader.podspec +++ b/FirebaseMLModelDownloader.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMLModelDownloader' - s.version = '12.2.0-beta' + s.version = '12.3.0-beta' s.summary = 'Firebase ML Model Downloader' s.description = <<-DESC @@ -36,9 +36,9 @@ Pod::Spec.new do |s| ] s.framework = 'Foundation' - s.dependency 'FirebaseCore', '~> 12.2.0' - s.dependency 'FirebaseCoreExtension', '~> 12.2.0' - s.dependency 'FirebaseInstallations', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.3.0' + s.dependency 'FirebaseCoreExtension', '~> 12.3.0' + s.dependency 'FirebaseInstallations', '~> 12.3.0' s.dependency 'GoogleDataTransport', '~> 10.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' s.dependency 'SwiftProtobuf', '~> 1.19' diff --git a/FirebaseMessaging.podspec b/FirebaseMessaging.podspec index 06f138db888..de61f8e8549 100644 --- a/FirebaseMessaging.podspec +++ b/FirebaseMessaging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMessaging' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Firebase Messaging' s.description = <<-DESC @@ -60,8 +60,8 @@ device, and it is completely free. s.tvos.framework = 'SystemConfiguration' s.osx.framework = 'SystemConfiguration' s.weak_framework = 'UserNotifications' - s.dependency 'FirebaseInstallations', '~> 12.2.0' - s.dependency 'FirebaseCore', '~> 12.2.0' + s.dependency 'FirebaseInstallations', '~> 12.3.0' + s.dependency 'FirebaseCore', '~> 12.3.0' s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.1' s.dependency 'GoogleUtilities/Reachability', '~> 8.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' diff --git a/FirebaseMessagingInterop.podspec b/FirebaseMessagingInterop.podspec index cedd5c82a8b..4aa8021895b 100644 --- a/FirebaseMessagingInterop.podspec +++ b/FirebaseMessagingInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseMessagingInterop' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Messaging functionality.' s.description = <<-DESC diff --git a/FirebasePerformance.podspec b/FirebasePerformance.podspec index 78cefbdaede..ba627a2370b 100644 --- a/FirebasePerformance.podspec +++ b/FirebasePerformance.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebasePerformance' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Firebase Performance' s.description = <<-DESC @@ -58,10 +58,10 @@ Firebase Performance library to measure performance of Mobile and Web Apps. s.ios.framework = 'CoreTelephony' s.framework = 'QuartzCore' s.framework = 'SystemConfiguration' - s.dependency 'FirebaseCore', '~> 12.2.0' - s.dependency 'FirebaseInstallations', '~> 12.2.0' - s.dependency 'FirebaseRemoteConfig', '~> 12.2.0' - s.dependency 'FirebaseSessions', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.3.0' + s.dependency 'FirebaseInstallations', '~> 12.3.0' + s.dependency 'FirebaseRemoteConfig', '~> 12.3.0' + s.dependency 'FirebaseSessions', '~> 12.3.0' s.dependency 'GoogleDataTransport', '~> 10.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/MethodSwizzler', '~> 8.1' diff --git a/FirebaseRemoteConfig.podspec b/FirebaseRemoteConfig.podspec index 06fde8ddcb4..d12f5f65acb 100644 --- a/FirebaseRemoteConfig.podspec +++ b/FirebaseRemoteConfig.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseRemoteConfig' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Firebase Remote Config' s.description = <<-DESC @@ -49,13 +49,13 @@ app update. s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } - s.dependency 'FirebaseABTesting', '~> 12.2.0' - s.dependency 'FirebaseSharedSwift', '~> 12.2.0' - s.dependency 'FirebaseCore', '~> 12.2.0' - s.dependency 'FirebaseInstallations', '~> 12.2.0' + s.dependency 'FirebaseABTesting', '~> 12.3.0' + s.dependency 'FirebaseSharedSwift', '~> 12.3.0' + s.dependency 'FirebaseCore', '~> 12.3.0' + s.dependency 'FirebaseInstallations', '~> 12.3.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/NSData+zlib', '~> 8.1' - s.dependency 'FirebaseRemoteConfigInterop', '~> 12.2.0' + s.dependency 'FirebaseRemoteConfigInterop', '~> 12.3.0' s.test_spec 'unit' do |unit_tests| unit_tests.scheme = { :code_coverage => true } diff --git a/FirebaseRemoteConfigInterop.podspec b/FirebaseRemoteConfigInterop.podspec index 3266634c9fa..b1121de1930 100644 --- a/FirebaseRemoteConfigInterop.podspec +++ b/FirebaseRemoteConfigInterop.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseRemoteConfigInterop' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Interfaces that allow other Firebase SDKs to use Remote Config functionality.' s.description = <<-DESC diff --git a/FirebaseSessions.podspec b/FirebaseSessions.podspec index 88406da2eb6..f003161ea12 100644 --- a/FirebaseSessions.podspec +++ b/FirebaseSessions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseSessions' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Firebase Sessions' s.description = <<-DESC @@ -39,9 +39,9 @@ Pod::Spec.new do |s| base_dir + 'SourcesObjC/**/*.{c,h,m,mm}', ] - s.dependency 'FirebaseCore', '~> 12.2.0' - s.dependency 'FirebaseCoreExtension', '~> 12.2.0' - s.dependency 'FirebaseInstallations', '~> 12.2.0' + s.dependency 'FirebaseCore', '~> 12.3.0' + s.dependency 'FirebaseCoreExtension', '~> 12.3.0' + s.dependency 'FirebaseInstallations', '~> 12.3.0' s.dependency 'GoogleDataTransport', '~> 10.1' s.dependency 'GoogleUtilities/Environment', '~> 8.1' s.dependency 'GoogleUtilities/UserDefaults', '~> 8.1' diff --git a/FirebaseSharedSwift.podspec b/FirebaseSharedSwift.podspec index b52cf86f973..500846b7f4c 100644 --- a/FirebaseSharedSwift.podspec +++ b/FirebaseSharedSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseSharedSwift' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Shared Swift Extensions for Firebase' s.description = <<-DESC diff --git a/FirebaseStorage.podspec b/FirebaseStorage.podspec index ac4caed6655..130fabcb31b 100644 --- a/FirebaseStorage.podspec +++ b/FirebaseStorage.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FirebaseStorage' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Firebase Storage' s.description = <<-DESC @@ -37,10 +37,10 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas 'FirebaseStorage/Typedefs/*.h', ] - s.dependency 'FirebaseAppCheckInterop', '~> 12.2.0' - s.dependency 'FirebaseAuthInterop', '~> 12.2.0' - s.dependency 'FirebaseCore', '~> 12.2.0' - s.dependency 'FirebaseCoreExtension', '~> 12.2.0' + s.dependency 'FirebaseAppCheckInterop', '~> 12.3.0' + s.dependency 'FirebaseAuthInterop', '~> 12.3.0' + s.dependency 'FirebaseCore', '~> 12.3.0' + s.dependency 'FirebaseCoreExtension', '~> 12.3.0' s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 6.0' s.dependency 'GoogleUtilities/Environment', '~> 8.1' @@ -57,7 +57,7 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas objc_tests.requires_app_host = true objc_tests.resources = 'FirebaseStorage/Tests/Integration/Resources/1mb.dat', 'FirebaseStorage/Tests/Integration/Resources/GoogleService-Info.plist' - objc_tests.dependency 'FirebaseAuth', '~> 12.2.0' + objc_tests.dependency 'FirebaseAuth', '~> 12.3.0' objc_tests.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"' } @@ -86,6 +86,6 @@ Firebase Storage provides robust, secure file uploads and downloads from Firebas int_tests.resources = 'FirebaseStorage/Tests/Integration/Resources/1mb.dat', 'FirebaseStorage/Tests/Integration/Resources/GoogleService-Info.plist', 'FirebaseStorage/Tests/Integration/Resources/HomeImprovement.numbers' - int_tests.dependency 'FirebaseAuth', '~> 12.2.0' + int_tests.dependency 'FirebaseAuth', '~> 12.3.0' end end diff --git a/GoogleAppMeasurement.podspec b/GoogleAppMeasurement.podspec index 244898bbd48..076e2641595 100644 --- a/GoogleAppMeasurement.podspec +++ b/GoogleAppMeasurement.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'GoogleAppMeasurement' - s.version = '12.2.0' + s.version = '12.3.0' s.summary = 'Shared measurement methods for Google libraries. Not intended for direct use.' s.description = <<-DESC @@ -37,8 +37,8 @@ Pod::Spec.new do |s| s.default_subspecs = 'Default' s.subspec 'Default' do |ss| - ss.dependency 'GoogleAppMeasurement/Core', '12.2.0' - ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.2.0' + ss.dependency 'GoogleAppMeasurement/Core', '12.3.0' + ss.dependency 'GoogleAppMeasurement/IdentitySupport', '12.3.0' ss.ios.dependency 'GoogleAdsOnDeviceConversion', '2.3.0' end @@ -47,7 +47,7 @@ Pod::Spec.new do |s| end s.subspec 'IdentitySupport' do |ss| - ss.dependency 'GoogleAppMeasurement/Core', '12.2.0' + ss.dependency 'GoogleAppMeasurement/Core', '12.3.0' ss.vendored_frameworks = 'Frameworks/GoogleAppMeasurementIdentitySupport.xcframework' end end diff --git a/Package.swift b/Package.swift index f1f118874fb..67247393177 100644 --- a/Package.swift +++ b/Package.swift @@ -18,7 +18,7 @@ import PackageDescription -let firebaseVersion = "12.2.0" +let firebaseVersion = "12.3.0" let package = Package( name: "Firebase", diff --git a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift index 9e5a6aebb35..4b2b361b069 100755 --- a/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift +++ b/ReleaseTooling/Sources/FirebaseManifest/FirebaseManifest.swift @@ -21,7 +21,7 @@ import Foundation /// The version and releasing fields of the non-Firebase pods should be reviewed every release. /// The array should be ordered so that any pod's dependencies precede it in the list. public let shared = Manifest( - version: "12.2.0", + version: "12.3.0", pods: [ Pod("FirebaseSharedSwift"), Pod("FirebaseCoreInternal"), From 2b141b9f5d1e945d08416264e3eec75fae46344c Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Thu, 28 Aug 2025 10:50:46 -0400 Subject: [PATCH 66/76] chore(ci): Upload failing build log in firebasepod.yml (#15261) --- .github/workflows/firebasepod.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/firebasepod.yml b/.github/workflows/firebasepod.yml index ac61d4735a6..de92ee23206 100644 --- a/.github/workflows/firebasepod.yml +++ b/.github/workflows/firebasepod.yml @@ -39,3 +39,8 @@ jobs: run: scripts/install_prereqs.sh FirebasePod iOS - name: Build run: scripts/build.sh FirebasePod iOS + - uses: actions/upload-artifact@v4 + if: ${{ failure() }} + with: + name: firebasepod-xcodebuild-build.log + path: xcodebuild-build.log From c080b30599b070b3d5cf06296498dbb155384a63 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Thu, 28 Aug 2025 11:55:04 -0400 Subject: [PATCH 67/76] Revert "[Infra] Attempt to reduce Crashlytics testing flake" (#15203) --- Crashlytics/UnitTests/Mocks/FIRCLSMockFileManager.m | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Crashlytics/UnitTests/Mocks/FIRCLSMockFileManager.m b/Crashlytics/UnitTests/Mocks/FIRCLSMockFileManager.m index 955e701d065..b89d05bbff8 100644 --- a/Crashlytics/UnitTests/Mocks/FIRCLSMockFileManager.m +++ b/Crashlytics/UnitTests/Mocks/FIRCLSMockFileManager.m @@ -41,9 +41,7 @@ - (BOOL)removeItemAtPath:(NSString *)path { // If we set up the expectation, and we went over the expected count or removes, fulfill the // expectation if (self.removeExpectation && self.removeCount >= self.expectedRemoveCount) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self.removeExpectation fulfill]; - }); + [self.removeExpectation fulfill]; } return YES; From 85d91a89bd3fc882ed5458716fd5ff7772a6885a Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 28 Aug 2025 14:24:02 -0400 Subject: [PATCH 68/76] [CI] Replace refs to `qs-auth.plist.gpg` with updated name (#15268) --- .github/workflows/auth.yml | 4 ++-- .github/workflows/release.yml | 2 +- .github/workflows/zip.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/auth.yml b/.github/workflows/auth.yml index b34a5fd9bd0..3f1d3142fe0 100644 --- a/.github/workflows/auth.yml +++ b/.github/workflows/auth.yml @@ -98,7 +98,7 @@ jobs: product: Authentication is_legacy: false setup_command: scripts/setup_quickstart.sh authentication - plist_src_path: scripts/gha-encrypted/qs-auth.plist.gpg + plist_src_path: scripts/gha-encrypted/qs-authentication.plist.gpg plist_dst_path: quickstart-ios/authentication/GoogleService-Info.plist run_tests: false secrets: @@ -122,7 +122,7 @@ jobs: # - name: Setup quickstart # run: scripts/setup_quickstart.sh authentication # - name: Install Secret GoogleService-Info.plist - # run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-auth.plist.gpg \ + # run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-authentication.plist.gpg \ # quickstart-ios/authentication/GoogleService-Info.plist "$plist_secret" # - name: Build swift quickstart # run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_ftl.sh Authentication) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0c45c2b786d..aad7f591868 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -201,7 +201,7 @@ jobs: - name: Setup testing repo and quickstart run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh Authentication nightly_release_testing - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-auth.plist.gpg \ + run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-authentication.plist.gpg \ quickstart-ios/authentication/GoogleService-Info.plist "$plist_secret" - name: Test swift quickstart run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Authentication false) diff --git a/.github/workflows/zip.yml b/.github/workflows/zip.yml index 429746ef071..3d797af2e75 100644 --- a/.github/workflows/zip.yml +++ b/.github/workflows/zip.yml @@ -196,7 +196,7 @@ jobs: "${HOME}"/ios_frameworks/Firebase/FirebaseAuth/* \ "${HOME}"/ios_frameworks/Firebase/FirebaseAnalytics/* - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-auth.plist.gpg \ + run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-authentication.plist.gpg \ quickstart-ios/authentication/GoogleService-Info.plist "$plist_secret" - name: Test Swift Quickstart run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart_framework.sh "${SDK}") From 1ec81a94e492306818905b01a8aa2ba61c953cf0 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Thu, 28 Aug 2025 17:03:20 -0400 Subject: [PATCH 69/76] fix(ci): Fix prerelease.yml by removing unneeded lowercasing (#15271) --- .github/workflows/prerelease.yml | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index ee5cea1113d..b87499a0fc4 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -311,21 +311,13 @@ jobs: - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer - - name: Get lowercase product name. - id: lowercase_product - run: | - lowercase_product=$(echo "${{ matrix.product }}" | tr '[:upper:]' '[:lower:]') - echo "lowercase_product=$lowercase_product" >> $GITHUB_OUTPUT - name: Setup testing repo and quickstart - run: | - lowercase_product=${{ steps.lowercase_product.outputs.lowercase_product }} - BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh $lowercase_product prerelease_testing + run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh ${{ matrix.product }} prerelease_testing - name: Install Secret GoogleService-Info.plist run: | - lowercase_product = ${{ steps.lowercase_product.outputs.lowercase_product }} scripts/decrypt_gha_secret.sh \ - scripts/gha-encrypted/qs-$lowercase_product.plist.gpg \ - quickstart-ios/$lowercase_product/GoogleService-Info.plist \ + scripts/gha-encrypted/qs-${{ matrix.product }}.plist.gpg \ + quickstart-ios/${{ matrix.product }}/GoogleService-Info.plist \ "$plist_secret" - name: Run setup command, if needed. if: matrix.setup_command != '' @@ -349,9 +341,9 @@ jobs: # Failure sequence to upload artifact. - name: Remove data before upload. if: ${{ failure() }} - run: scripts/remove_data.sh ${{ steps.lowercase_product.outputs.lowercase_product }} + run: scripts/remove_data.sh ${{ matrix.product }} - uses: actions/upload-artifact@v4 if: ${{ failure() }} with: - name: quickstart_artifacts_${{ steps.lowercase_product.outputs.lowercase_product }} + name: quickstart_artifacts_${{ matrix.product }} path: quickstart-ios/ From a623ed1a977730ae90f1f17b476f6fbb214a9c6f Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 29 Aug 2025 11:05:03 -0400 Subject: [PATCH 70/76] refactor(ci): Consolidate quickstart jobs in release.yml (#15269) --- .github/workflows/release.yml | 368 +++++++--------------------------- 1 file changed, 72 insertions(+), 296 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index aad7f591868..32c40274ecc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,5 +1,8 @@ name: release +permissions: + contents: read + on: pull_request: paths: @@ -150,77 +153,58 @@ jobs: if: ${{ always() }} run: pod repo remove "${local_repo}" - abtesting_quickstart: + quickstart: # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsReleasing_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - name: Set Xcode version - run: sudo xcode-select -s /Applications/Xcode_16.4.app - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup testing repo and quickstart - env: - LEGACY: true - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh abtesting nightly_release_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-abtesting.plist.gpg \ - quickstart-ios/abtesting/GoogleService-Info.plist "$plist_secret" - - name: Test swift quickstart - env: - LEGACY: true - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh ABTesting true) - - name: Remove data before upload - env: - LEGACY: true - if: ${{ failure() }} - run: scripts/remove_data.sh config - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: quickstart_artifacts_abtesting - path: quickstart-ios/ - - auth_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsReleasing_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - name: Set Xcode version - run: sudo xcode-select -s /Applications/Xcode_16.4.app - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup testing repo and quickstart - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh Authentication nightly_release_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-authentication.plist.gpg \ - quickstart-ios/authentication/GoogleService-Info.plist "$plist_secret" - - name: Test swift quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Authentication false) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh authentication - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: quickstart_artifacts_auth - path: quickstart-ios/ - - crashlytics_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' + if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'workflow_dispatch' needs: buildup_SpecsReleasing_repo + strategy: + matrix: + include: + - product: Performance + run_tests: true + swift: true + - product: Storage + run_tests: true + swift: true + is_legacy: true + - product: Config + run_tests: true + objc: true + - product: Messaging + run_tests: false + objc: true + swift: true + - product: InAppMessaging + run_tests: true + objc: true + swift: true + - product: Firestore + run_tests: false + objc: true + - product: Database + run_tests: false + objc: true + swift: true + - product: Authentication + run_tests: false + objc: true + - product: Crashlytics + run_tests: true + swift: true + is_legacy: true + setup_command: | + mkdir -p quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/Pods/FirebaseCrashlytics + # Set the deployed pod location of run and upload-symbols with the development pod version. + cp Crashlytics/run quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/Pods/FirebaseCrashlytics/ + cp Crashlytics/upload-symbols quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/Pods/FirebaseCrashlytics/ + - product: ABTesting + run_tests: true + objc: true + is_legacy: true env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} botaccess: ${{ secrets.RELEASE_TESTING_PAT }} + LEGACY: ${{ matrix.is_legacy && true || '' }} runs-on: macos-15 steps: - uses: actions/checkout@v4 @@ -228,91 +212,37 @@ jobs: run: sudo xcode-select -s /Applications/Xcode_16.4.app - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Setup testing repo and quickstart - env: - LEGACY: true - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh Crashlytics nightly_release_testing + run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh ${{ matrix.product }} nightly_release_testing - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-crashlytics.plist.gpg \ - quickstart-ios/crashlytics/GoogleService-Info.plist "$plist_secret" - - name: Test swift quickstart - env: - LEGACY: true run: | - mkdir -p quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/Pods/FirebaseCrashlytics - # Set the deployed pod location of run and upload-symbols with the development pod version. - cp Crashlytics/run quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/Pods/FirebaseCrashlytics/ - cp Crashlytics/upload-symbols quickstart-ios/crashlytics/LegacyCrashlyticsQuickstart/Pods/FirebaseCrashlytics/ - ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Crashlytics true swift) - - name: Remove data before upload - env: - LEGACY: true - if: ${{ failure() }} - run: scripts/remove_data.sh crashlytics - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} + scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-${{ matrix.product }}.plist.gpg \ + quickstart-ios/${{ matrix.product }}/GoogleService-Info.plist "$plist_secret" + - name: Run setup command, if needed. + if: matrix.setup_command != '' + run: ${{ matrix.setup_command }} + - name: Build Obj-C quickstart + if: matrix.objc == true + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: - name: quickstart_artifacts_crashlytics - path: quickstart-ios/ - - database_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsReleasing_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - name: Set Xcode version - run: sudo xcode-select -s /Applications/Xcode_16.4.app - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup testing repo and quickstart - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh database nightly_release_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-database.plist.gpg \ - quickstart-ios/database/GoogleService-Info.plist "$plist_secret" - - name: Test objc quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Database false) - - name: Test swift quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Database false swift) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh database - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} + timeout_minutes: 15 + max_attempts: 3 + retry_wait_seconds: 120 + command: scripts/test_quickstart.sh ${{ matrix.product }} ${{ matrix.run_tests }} + - name: Build Swift quickstart + if: matrix.swift == true + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 with: - name: quickstart_artifacts_database - path: quickstart-ios/ - - firestore_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsReleasing_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - name: Set Xcode version - run: sudo xcode-select -s /Applications/Xcode_16.4.app - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup testing repo and quickstart - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh firestore nightly_release_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-firestore.plist.gpg \ - quickstart-ios/firestore/GoogleService-Info.plist "$plist_secret" - - name: Test swift quickstart - run: ([ -z $plist_secret ] || - scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Firestore false) + timeout_minutes: 15 + max_attempts: 3 + retry_wait_seconds: 120 + command: scripts/test_quickstart.sh ${{ matrix.product }} ${{ matrix.run_tests }} swift - name: Remove data before upload if: ${{ failure() }} - run: scripts/remove_data.sh firestore + run: scripts/remove_data.sh ${{ matrix.product }} - uses: actions/upload-artifact@v4 if: ${{ failure() }} with: - name: quickstart_artifacts_firestore + name: quickstart_artifacts_${{ matrix.product }} path: quickstart-ios/ # TODO: The functions quickstart uses Material which isn't supported by Xcode 15 @@ -349,157 +279,3 @@ jobs: # with: # name: quickstart_artifacts_functions # path: quickstart-ios/ - - inappmessaging_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsReleasing_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - name: Set Xcode version - run: sudo xcode-select -s /Applications/Xcode_16.4.app - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup testing repo and quickstart - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh inappmessaging nightly_release_testing - - name: install secret googleservice-info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-inappmessaging.plist.gpg \ - quickstart-ios/inappmessaging/GoogleService-Info.plist "$plist_secret" - - name: Test objc quickstart - run: ([ -z $plist_secret ] || - scripts/third_party/travis/retry.sh scripts/test_quickstart.sh InAppMessaging true) - - name: Test swift quickstart - run: ([ -z $plist_secret ] || - scripts/third_party/travis/retry.sh scripts/test_quickstart.sh InAppMessaging true swift) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh inappmessaging - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: quickstart_artifacts_inappmessaging - path: quickstart-ios/ - - messaging_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsReleasing_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - name: Set Xcode version - run: sudo xcode-select -s /Applications/Xcode_16.4.app - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup testing repo and quickstart - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh messaging nightly_release_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-messaging.plist.gpg \ - quickstart-ios/messaging/GoogleService-Info.plist "$plist_secret" - - name: Test objc quickstart - run: ([ -z $plist_secret ] || - scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Messaging false) - - name: Test swift quickstart - run: ([ -z $plist_secret ] || - scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Messaging false swift) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh messaging - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: quickstart_artifacts_messaging - path: quickstart-ios/ - - remoteconfig_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsReleasing_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - name: Set Xcode version - run: sudo xcode-select -s /Applications/Xcode_16.4.app - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup testing repo and quickstart - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh config nightly_release_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-config.plist.gpg \ - quickstart-ios/config/GoogleService-Info.plist "$plist_secret" - - name: Test Swift Quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Config true) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh config - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: quickstart_artifacts_config - path: quickstart-ios/ - - storage_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsReleasing_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - LEGACY: true - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - name: Set Xcode version - run: sudo xcode-select -s /Applications/Xcode_16.4.app - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup testing repo and quickstart - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh storage nightly_release_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-storage.plist.gpg \ - quickstart-ios/storage/GoogleService-Info.plist "$plist_secret" - - name: Test swift quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Storage true swift) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh storage - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: quickstart_artifacts_storage - path: quickstart-ios/ - - performance_quickstart: - # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' - needs: buildup_SpecsReleasing_repo - env: - plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} - botaccess: ${{ secrets.RELEASE_TESTING_PAT }} - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - name: Set Xcode version - run: sudo xcode-select -s /Applications/Xcode_16.4.app - - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - - name: Setup testing repo and quickstart - run: BOT_TOKEN="${botaccess}" scripts/setup_quickstart.sh Performance nightly_release_testing - - name: Install Secret GoogleService-Info.plist - run: scripts/decrypt_gha_secret.sh scripts/gha-encrypted/qs-performance.plist.gpg \ - quickstart-ios/performance/GoogleService-Info.plist "$plist_secret" - - name: Test swift quickstart - run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/test_quickstart.sh Performance true swift) - - name: Remove data before upload - if: ${{ failure() }} - run: scripts/remove_data.sh performance - - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: quickstart_artifacts_performance - path: quickstart-ios/ From d05c15916966070f8f2053a143ca9e1c3f6cf043 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Fri, 29 Aug 2025 23:12:46 -0400 Subject: [PATCH 71/76] feat(ci): Add support for using previous zip run artifact (#15274) --- .github/workflows/zip.yml | 74 ++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/.github/workflows/zip.yml b/.github/workflows/zip.yml index 3d797af2e75..1ebbc3dffe1 100644 --- a/.github/workflows/zip.yml +++ b/.github/workflows/zip.yml @@ -1,5 +1,9 @@ name: zip +permissions: + actions: read + contents: read + on: pull_request: paths: @@ -21,6 +25,12 @@ on: description: 'Custom Podspec repos' required: true default: 'https://github.com/firebase/SpecsStaging.git' + zip_run_id: + # For example, in the below URL, `17335533279` is the run ID: + # - https://github.com/firebase/firebase-ios-sdk/actions/runs/17335533279 + description: 'Run ID of a previous successful zip workflow to use for quickstart testing' + required: false + default: '' concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} @@ -29,7 +39,10 @@ concurrency: jobs: package-release: # Don't run on private repo. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' + if: | + github.repository == 'firebase/firebase-ios-sdk' && + contains(fromJSON('["schedule", "pull_request", "workflow_dispatch"]'), github.event_name) && + github.event.inputs.zip_run_id == '' runs-on: macos-14 steps: - uses: actions/checkout@v4 @@ -57,7 +70,10 @@ jobs: build: # Don't run on private repo unless it is a PR. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' + if: | + github.repository == 'firebase/firebase-ios-sdk' && + contains(fromJSON('["schedule", "pull_request", "workflow_dispatch"]'), github.event_name) && + github.event.inputs.zip_run_id == '' runs-on: macos-14 steps: - uses: actions/checkout@v4 @@ -66,11 +82,9 @@ jobs: - name: Build run: | cd ReleaseTooling - swift build -v +# swift build -v package-head: - # Don't run on private repo. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' needs: build strategy: matrix: @@ -102,9 +116,8 @@ jobs: path: zip_output_dir quickstart_framework_abtesting: - # Don't run on private repo. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' needs: package-head + if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "ABTesting" @@ -121,6 +134,8 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} + run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer @@ -160,9 +175,8 @@ jobs: path: quickstart-ios/ quickstart_framework_auth: - # Don't run on private repo. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' needs: package-head + if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Authentication" @@ -180,6 +194,8 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} + run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer @@ -210,9 +226,8 @@ jobs: path: quickstart-ios/ quickstart_framework_config: - # Don't run on private repo. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' needs: package-head + if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Config" @@ -229,6 +244,8 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} + run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer @@ -258,9 +275,8 @@ jobs: path: quickstart-ios/ quickstart_framework_crashlytics: - # Don't run on private repo. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' needs: package-head + if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Crashlytics" @@ -277,6 +293,8 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} + run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer @@ -329,9 +347,8 @@ jobs: path: quickstart-ios/ quickstart_framework_database: - # Don't run on private repo. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' needs: package-head + if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Database" @@ -347,6 +364,8 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} + run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer @@ -380,9 +399,8 @@ jobs: path: quickstart-ios/ quickstart_framework_firestore: - # Don't run on private repo. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' needs: package-head + if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Firestore" @@ -399,6 +417,8 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} + run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer @@ -436,9 +456,8 @@ jobs: path: quickstart_artifacts_firestore.zip check_framework_firestore_symbols: - # Don't run on private repo. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' needs: package-head + if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} env: FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1 runs-on: macos-14 @@ -450,6 +469,8 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: Firebase-actions-dir + run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Setup Bundler run: ./scripts/setup_bundler.sh @@ -467,9 +488,8 @@ jobs: "${HOME}"/ios_frameworks/Firebase/FirebaseFirestore/FirebaseFirestoreInternal.xcframework quickstart_framework_inappmessaging: - # Don't run on private repo. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' needs: package-head + if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "InAppMessaging" @@ -486,6 +506,8 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} + run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer @@ -519,9 +541,8 @@ jobs: path: quickstart-ios/ quickstart_framework_messaging: - # Don't run on private repo. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' needs: package-head + if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Messaging" @@ -538,6 +559,8 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} + run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer @@ -571,9 +594,8 @@ jobs: path: quickstart-ios/ quickstart_framework_storage: - # Don't run on private repo. - if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' needs: package-head + if: ${{ !cancelled() && (success() || github.event.inputs.zip_run_id != '') }} env: plist_secret: ${{ secrets.GHASecretsGPGPassphrase1 }} SDK: "Storage" @@ -590,6 +612,8 @@ jobs: uses: actions/download-artifact@v4.1.7 with: name: ${{ matrix.artifact }} + run-id: ${{ github.event.inputs.zip_run_id || github.run_id }} + github-token: ${{ secrets.GITHUB_TOKEN }} - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 # v1 - name: Xcode run: sudo xcode-select -s /Applications/${{ matrix.build-env.xcode }}.app/Contents/Developer From 9bc71e35b4250816412a5772cf2c730c81eddf6c Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 2 Sep 2025 11:01:02 -0400 Subject: [PATCH 72/76] fix(ci): Revert unintended change in zip.yml (#15278) --- .github/workflows/zip.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/zip.yml b/.github/workflows/zip.yml index 1ebbc3dffe1..eba3c5b61b5 100644 --- a/.github/workflows/zip.yml +++ b/.github/workflows/zip.yml @@ -82,7 +82,7 @@ jobs: - name: Build run: | cd ReleaseTooling -# swift build -v + swift build -v package-head: needs: build From 0b46d74f71334f3e04d18a2e1ef201d7cdcf9004 Mon Sep 17 00:00:00 2001 From: Daymon <17409137+daymxn@users.noreply.github.com> Date: Wed, 3 Sep 2025 11:21:36 -0500 Subject: [PATCH 73/76] chore(firebaseai): Update changelog per release (#15285) --- FirebaseAI/CHANGELOG.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/FirebaseAI/CHANGELOG.md b/FirebaseAI/CHANGELOG.md index 1cc90f6028e..fcd35a32e43 100644 --- a/FirebaseAI/CHANGELOG.md +++ b/FirebaseAI/CHANGELOG.md @@ -1,9 +1,12 @@ # 12.2.0 - [feature] Added support for returning thought summaries, which are synthesized versions of a model's internal reasoning process. (#15096) -- [feature] Added support for limited-use tokens with Firebase App Check. These short-lived tokens - provide greater protection for the APIs that give you access to Gemini and Imagen models. Learn - how to [enable usage of limited-use tokens](https://firebase.google.com/docs/ai-logic/app-check). +- [feature] Added support for limited-use tokens with Firebase App Check. + These limited-use tokens are required for an upcoming optional feature called + _replay protection_. We recommend + [enabling the usage of limited-use tokens](https://firebase.google.com/docs/ai-logic/app-check) + now so that when replay protection becomes available, you can enable it sooner + because more of your users will be on versions of your app that send limited-use tokens. (#15099) # 12.0.0 From 9f4c34bbdbd3e3918d31fc276ab0ba48fb3aac6b Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Wed, 3 Sep 2025 19:30:02 -0400 Subject: [PATCH 74/76] [Firebase AI] Handle empty or unknown `Part` data (#15262) --- FirebaseAI/CHANGELOG.md | 5 ++ FirebaseAI/Sources/AILog.swift | 2 + .../Sources/GenerateContentResponse.swift | 15 ++-- FirebaseAI/Sources/GenerativeModel.swift | 33 ++++++- FirebaseAI/Sources/ModelContent.swift | 32 +++++-- .../Internal/Errors/EmptyContentError.swift | 20 +++++ .../Tests/TestApp/Sources/Constants.swift | 1 + .../GenerateContentIntegrationTests.swift | 87 +++++++++++++++++-- .../Unit/GenerativeModelGoogleAITests.swift | 17 ++++ .../Unit/GenerativeModelVertexAITests.swift | 49 ++++++++--- 10 files changed, 223 insertions(+), 38 deletions(-) create mode 100644 FirebaseAI/Sources/Types/Internal/Errors/EmptyContentError.swift diff --git a/FirebaseAI/CHANGELOG.md b/FirebaseAI/CHANGELOG.md index fcd35a32e43..4c2d482f8d5 100644 --- a/FirebaseAI/CHANGELOG.md +++ b/FirebaseAI/CHANGELOG.md @@ -1,3 +1,8 @@ +# 12.3.0 +- [fixed] Fixed a decoding error when generating images with the + `gemini-2.5-flash-image-preview` model using `generateContentStream` or + `sendMessageStream` with the Gemini Developer API. (#15262) + # 12.2.0 - [feature] Added support for returning thought summaries, which are synthesized versions of a model's internal reasoning process. (#15096) diff --git a/FirebaseAI/Sources/AILog.swift b/FirebaseAI/Sources/AILog.swift index 4019c2cd0ff..cae85a0ff0a 100644 --- a/FirebaseAI/Sources/AILog.swift +++ b/FirebaseAI/Sources/AILog.swift @@ -62,11 +62,13 @@ enum AILog { case decodedInvalidCitationPublicationDate = 3011 case generateContentResponseUnrecognizedContentModality = 3012 case decodedUnsupportedImagenPredictionType = 3013 + case decodedUnsupportedPartData = 3014 // SDK State Errors case generateContentResponseNoCandidates = 4000 case generateContentResponseNoText = 4001 case appCheckTokenFetchFailed = 4002 + case generateContentResponseEmptyCandidates = 4003 // SDK Debugging case loadRequestStreamResponseLine = 5000 diff --git a/FirebaseAI/Sources/GenerateContentResponse.swift b/FirebaseAI/Sources/GenerateContentResponse.swift index 0756d2afd9a..015d5dae56c 100644 --- a/FirebaseAI/Sources/GenerateContentResponse.swift +++ b/FirebaseAI/Sources/GenerateContentResponse.swift @@ -163,6 +163,12 @@ public struct Candidate: Sendable { self.citationMetadata = citationMetadata self.groundingMetadata = groundingMetadata } + + // Returns `true` if the candidate contains no information that a developer could use. + var isEmpty: Bool { + content.parts + .isEmpty && finishReason == nil && citationMetadata == nil && groundingMetadata == nil + } } /// A collection of source attributions for a piece of content. @@ -525,15 +531,6 @@ extension Candidate: Decodable { finishReason = try container.decodeIfPresent(FinishReason.self, forKey: .finishReason) - // The `content` may only be empty if a `finishReason` is included; if neither are included in - // the response then this is likely the `"content": {}` bug. - guard !content.parts.isEmpty || finishReason != nil else { - throw InvalidCandidateError.emptyContent(underlyingError: DecodingError.dataCorrupted(.init( - codingPath: [CodingKeys.content, CodingKeys.finishReason], - debugDescription: "Invalid Candidate: empty content and no finish reason" - ))) - } - citationMetadata = try container.decodeIfPresent( CitationMetadata.self, forKey: .citationMetadata diff --git a/FirebaseAI/Sources/GenerativeModel.swift b/FirebaseAI/Sources/GenerativeModel.swift index 8d3f5e043a7..428e1fe6f26 100644 --- a/FirebaseAI/Sources/GenerativeModel.swift +++ b/FirebaseAI/Sources/GenerativeModel.swift @@ -174,6 +174,13 @@ public final class GenerativeModel: Sendable { throw GenerateContentError.responseStoppedEarly(reason: reason, response: response) } + // If all candidates are empty (contain no information that a developer could act on) then throw + if response.candidates.allSatisfy({ $0.isEmpty }) { + throw GenerateContentError.internalError(underlying: InvalidCandidateError.emptyContent( + underlyingError: Candidate.EmptyContentError() + )) + } + return response } @@ -223,6 +230,7 @@ public final class GenerativeModel: Sendable { let responseStream = generativeAIService.loadRequestStream(request: generateContentRequest) Task { do { + var didYieldResponse = false for try await response in responseStream { // Check the prompt feedback to see if the prompt was blocked. if response.promptFeedback?.blockReason != nil { @@ -237,9 +245,30 @@ public final class GenerativeModel: Sendable { ) } - continuation.yield(response) + // Skip returning the response if all candidates are empty (i.e., they contain no + // information that a developer could act on). + if response.candidates.allSatisfy({ $0.isEmpty }) { + AILog.log( + level: .debug, + code: .generateContentResponseEmptyCandidates, + "Skipped response with all empty candidates: \(response)" + ) + } else { + continuation.yield(response) + didYieldResponse = true + } + } + + // Throw an error if all responses were skipped due to empty content. + if didYieldResponse { + continuation.finish() + } else { + continuation.finish(throwing: GenerativeModel.generateContentError( + from: InvalidCandidateError.emptyContent( + underlyingError: Candidate.EmptyContentError() + ) + )) } - continuation.finish() } catch { continuation.finish(throwing: GenerativeModel.generateContentError(from: error)) return diff --git a/FirebaseAI/Sources/ModelContent.swift b/FirebaseAI/Sources/ModelContent.swift index 1a0aa6f5f09..a0dfe6eb937 100644 --- a/FirebaseAI/Sources/ModelContent.swift +++ b/FirebaseAI/Sources/ModelContent.swift @@ -39,9 +39,17 @@ struct InternalPart: Equatable, Sendable { case fileData(FileData) case functionCall(FunctionCall) case functionResponse(FunctionResponse) + + struct UnsupportedDataError: Error { + let decodingError: DecodingError + + var localizedDescription: String { + decodingError.localizedDescription + } + } } - let data: OneOfData + let data: OneOfData? let isThought: Bool? @@ -65,7 +73,7 @@ public struct ModelContent: Equatable, Sendable { /// The data parts comprising this ``ModelContent`` value. public var parts: [any Part] { - return internalParts.map { part -> any Part in + return internalParts.compactMap { part -> (any Part)? in switch part.data { case let .text(text): return TextPart(text, isThought: part.isThought, thoughtSignature: part.thoughtSignature) @@ -85,6 +93,9 @@ public struct ModelContent: Equatable, Sendable { return FunctionResponsePart( functionResponse, isThought: part.isThought, thoughtSignature: part.thoughtSignature ) + case .none: + // Filter out parts that contain missing or unrecognized data + return nil } } } @@ -179,7 +190,14 @@ extension InternalPart: Codable { } public init(from decoder: Decoder) throws { - data = try OneOfData(from: decoder) + do { + data = try OneOfData(from: decoder) + } catch let error as OneOfData.UnsupportedDataError { + AILog.error(code: .decodedUnsupportedPartData, error.localizedDescription) + data = nil + } catch { // Re-throw any other error types + throw error + } let container = try decoder.container(keyedBy: CodingKeys.self) isThought = try container.decodeIfPresent(Bool.self, forKey: .isThought) thoughtSignature = try container.decodeIfPresent(String.self, forKey: .thoughtSignature) @@ -226,9 +244,11 @@ extension InternalPart.OneOfData: Codable { self = try .functionResponse(values.decode(FunctionResponse.self, forKey: .functionResponse)) } else { let unexpectedKeys = values.allKeys.map { $0.stringValue } - throw DecodingError.dataCorrupted(DecodingError.Context( - codingPath: values.codingPath, - debugDescription: "Unexpected Part type(s): \(unexpectedKeys)" + throw UnsupportedDataError(decodingError: DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: values.codingPath, + debugDescription: "Unexpected Part type(s): \(unexpectedKeys)" + ) )) } } diff --git a/FirebaseAI/Sources/Types/Internal/Errors/EmptyContentError.swift b/FirebaseAI/Sources/Types/Internal/Errors/EmptyContentError.swift new file mode 100644 index 00000000000..7c33a975c18 --- /dev/null +++ b/FirebaseAI/Sources/Types/Internal/Errors/EmptyContentError.swift @@ -0,0 +1,20 @@ +// 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. + +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +extension Candidate { + struct EmptyContentError: Error { + let localizedDescription = "Invalid Candidate: empty content and no finish reason" + } +} diff --git a/FirebaseAI/Tests/TestApp/Sources/Constants.swift b/FirebaseAI/Tests/TestApp/Sources/Constants.swift index ef7d9e7c061..be5c0c06891 100644 --- a/FirebaseAI/Tests/TestApp/Sources/Constants.swift +++ b/FirebaseAI/Tests/TestApp/Sources/Constants.swift @@ -24,6 +24,7 @@ public enum ModelNames { public static let gemini2Flash = "gemini-2.0-flash-001" public static let gemini2FlashLite = "gemini-2.0-flash-lite-001" public static let gemini2FlashPreviewImageGeneration = "gemini-2.0-flash-preview-image-generation" + public static let gemini2_5_FlashImagePreview = "gemini-2.5-flash-image-preview" public static let gemini2_5_Flash = "gemini-2.5-flash" public static let gemini2_5_Pro = "gemini-2.5-pro" public static let gemma3_4B = "gemma-3-4b-it" diff --git a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift index ef0f19be217..5b70223ece4 100644 --- a/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift +++ b/FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift @@ -322,14 +322,20 @@ struct GenerateContentIntegrationTests { } @Test(arguments: [ - InstanceConfig.vertexAI_v1beta, - InstanceConfig.vertexAI_v1beta_global, - InstanceConfig.googleAI_v1beta, + (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2FlashPreviewImageGeneration), + (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2FlashPreviewImageGeneration), + (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2_5_FlashImagePreview), + (InstanceConfig.googleAI_v1beta, ModelNames.gemini2FlashPreviewImageGeneration), + (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_FlashImagePreview), // Note: The following configs are commented out for easy one-off manual testing. - // InstanceConfig.googleAI_v1beta_staging, - // InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, + // (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemini2FlashPreviewImageGeneration) + // (InstanceConfig.googleAI_v1beta_freeTier, ModelNames.gemini2FlashPreviewImageGeneration), + // ( + // InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, + // ModelNames.gemini2FlashPreviewImageGeneration + // ), ]) - func generateImage(_ config: InstanceConfig) async throws { + func generateImage(_ config: InstanceConfig, modelName: String) async throws { let generationConfig = GenerationConfig( temperature: 0.0, topP: 0.0, @@ -342,7 +348,7 @@ struct GenerateContentIntegrationTests { $0.harmCategory != .civicIntegrity } let model = FirebaseAI.componentInstance(config).generativeModel( - modelName: ModelNames.gemini2FlashPreviewImageGeneration, + modelName: modelName, generationConfig: generationConfig, safetySettings: safetySettings ) @@ -483,6 +489,73 @@ struct GenerateContentIntegrationTests { #expect(response == expectedResponse) } + @Test(arguments: [ + (InstanceConfig.vertexAI_v1beta, ModelNames.gemini2FlashPreviewImageGeneration), + (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2FlashPreviewImageGeneration), + (InstanceConfig.vertexAI_v1beta_global, ModelNames.gemini2_5_FlashImagePreview), + (InstanceConfig.googleAI_v1beta, ModelNames.gemini2FlashPreviewImageGeneration), + (InstanceConfig.googleAI_v1beta, ModelNames.gemini2_5_FlashImagePreview), + // Note: The following configs are commented out for easy one-off manual testing. + // (InstanceConfig.googleAI_v1beta_staging, ModelNames.gemini2FlashPreviewImageGeneration) + // (InstanceConfig.googleAI_v1beta_freeTier, ModelNames.gemini2FlashPreviewImageGeneration), + // ( + // InstanceConfig.googleAI_v1beta_freeTier_bypassProxy, + // ModelNames.gemini2FlashPreviewImageGeneration + // ), + ]) + func generateImageStreaming(_ config: InstanceConfig, modelName: String) async throws { + let generationConfig = GenerationConfig( + temperature: 0.0, + topP: 0.0, + topK: 1, + responseModalities: [.text, .image] + ) + let safetySettings = safetySettings.filter { + // HARM_CATEGORY_CIVIC_INTEGRITY is deprecated in Vertex AI but only rejected when using the + // 'gemini-2.0-flash-preview-image-generation' model. + $0.harmCategory != .civicIntegrity + } + let model = FirebaseAI.componentInstance(config).generativeModel( + modelName: modelName, + generationConfig: generationConfig, + safetySettings: safetySettings + ) + let prompt = "Generate an image of a cute cartoon kitten playing with a ball of yarn" + + let stream = try model.generateContentStream(prompt) + + var inlineDataParts = [InlineDataPart]() + for try await response in stream { + let candidate = try #require(response.candidates.first) + let inlineDataPart = candidate.content.parts.first { $0 is InlineDataPart } as? InlineDataPart + if let inlineDataPart { + inlineDataParts.append(inlineDataPart) + let inlineDataPartsViaAccessor = response.inlineDataParts + #expect(inlineDataPartsViaAccessor.count == 1) + #expect(inlineDataPartsViaAccessor == response.inlineDataParts) + } + let textPart = candidate.content.parts.first { $0 is TextPart } as? TextPart + #expect( + inlineDataPart != nil || textPart != nil || candidate.finishReason == .stop, + "No text or image found in the candidate" + ) + } + + #expect(inlineDataParts.count == 1) + let inlineDataPart = try #require(inlineDataParts.first) + #expect(inlineDataPart.mimeType == "image/png") + #expect(inlineDataPart.data.count > 0) + #if canImport(UIKit) + let uiImage = try #require(UIImage(data: inlineDataPart.data)) + // Gemini 2.0 Flash Experimental returns images sized to fit within a 1024x1024 pixel box but + // dimensions may vary depending on the aspect ratio. + #expect(uiImage.size.width <= 1024) + #expect(uiImage.size.width >= 500) + #expect(uiImage.size.height <= 1024) + #expect(uiImage.size.height >= 500) + #endif // canImport(UIKit) + } + // MARK: - App Check Tests @Test(arguments: InstanceConfig.appCheckNotConfiguredConfigs) diff --git a/FirebaseAI/Tests/Unit/GenerativeModelGoogleAITests.swift b/FirebaseAI/Tests/Unit/GenerativeModelGoogleAITests.swift index 00e0d398855..b1ee49da6a1 100644 --- a/FirebaseAI/Tests/Unit/GenerativeModelGoogleAITests.swift +++ b/FirebaseAI/Tests/Unit/GenerativeModelGoogleAITests.swift @@ -509,6 +509,23 @@ final class GenerativeModelGoogleAITests: XCTestCase { XCTAssertTrue(thoughtSignature.hasPrefix("CiIBVKhc7vB+vaaq6rA")) } + func testGenerateContentStream_success_ignoresEmptyParts() async throws { + MockURLProtocol.requestHandler = try GenerativeModelTestUtil.httpRequestHandler( + forResource: "streaming-success-empty-parts", + withExtension: "txt", + subdirectory: googleAISubdirectory + ) + + let stream = try model.generateContentStream("Hi") + for try await response in stream { + let candidate = try XCTUnwrap(response.candidates.first) + XCTAssertGreaterThan(candidate.content.parts.count, 0) + let text = response.text + let inlineData = response.inlineDataParts.first + XCTAssertTrue(text != nil || inlineData != nil, "Response did not contain text or data") + } + } + func testGenerateContentStream_failureInvalidAPIKey() async throws { MockURLProtocol.requestHandler = try GenerativeModelTestUtil.httpRequestHandler( forResource: "unary-failure-api-key", diff --git a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift index 0e33ba557e6..2b7a60ec0a8 100644 --- a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift +++ b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift @@ -477,6 +477,27 @@ final class GenerativeModelVertexAITests: XCTestCase { XCTAssertGreaterThan(imagePart.data.count, 0) } + func testGenerateContent_success_image_emptyPartIgnored() async throws { + MockURLProtocol.requestHandler = try GenerativeModelTestUtil.httpRequestHandler( + forResource: "unary-success-empty-part", + withExtension: "json", + subdirectory: vertexSubdirectory + ) + + let response = try await model.generateContent(testPrompt) + + XCTAssertEqual(response.candidates.count, 1) + let candidate = try XCTUnwrap(response.candidates.first) + XCTAssertEqual(candidate.content.parts.count, 2) + let inlineDataParts = response.inlineDataParts + XCTAssertEqual(inlineDataParts.count, 1) + let imagePart = try XCTUnwrap(inlineDataParts.first) + XCTAssertEqual(imagePart.mimeType, "image/png") + XCTAssertGreaterThan(imagePart.data.count, 0) + let text = try XCTUnwrap(response.text) + XCTAssertTrue(text.starts(with: "I can certainly help you with that")) + } + func testGenerateContent_appCheck_validToken() async throws { let appCheckToken = "test-valid-token" model = GenerativeModel( @@ -786,12 +807,12 @@ final class GenerativeModelVertexAITests: XCTestCase { XCTFail("Should throw GenerateContentError.internalError; no error thrown.") } catch let GenerateContentError .internalError(underlying: invalidCandidateError as InvalidCandidateError) { - guard case let .emptyContent(decodingError) = invalidCandidateError else { - XCTFail("Not an InvalidCandidateError.emptyContent error: \(invalidCandidateError)") + guard case let .emptyContent(underlyingError) = invalidCandidateError else { + XCTFail("Should be an InvalidCandidateError.emptyContent error: \(invalidCandidateError)") return } - _ = try XCTUnwrap(decodingError as? DecodingError, - "Not a DecodingError: \(decodingError)") + _ = try XCTUnwrap(underlyingError as? Candidate.EmptyContentError, + "Should be an empty content error: \(underlyingError)") } catch { XCTFail("Should throw GenerateContentError.internalError; error thrown: \(error)") } @@ -976,7 +997,7 @@ final class GenerativeModelVertexAITests: XCTestCase { XCTAssertNotNil(responseError) let generateContentError = try XCTUnwrap(responseError as? GenerateContentError) guard case let .internalError(underlyingError) = generateContentError else { - XCTFail("Not an internal error: \(generateContentError)") + XCTFail("Should be an internal error: \(generateContentError)") return } XCTAssertEqual(underlyingError.localizedDescription, "Response was not an HTTP response.") @@ -1004,12 +1025,12 @@ final class GenerativeModelVertexAITests: XCTestCase { XCTAssertNotNil(responseError) let generateContentError = try XCTUnwrap(responseError as? GenerateContentError) guard case let .internalError(underlyingError) = generateContentError else { - XCTFail("Not an internal error: \(generateContentError)") + XCTFail("Should be an internal error: \(generateContentError)") return } let decodingError = try XCTUnwrap(underlyingError as? DecodingError) guard case let .dataCorrupted(context) = decodingError else { - XCTFail("Not a data corrupted error: \(decodingError)") + XCTFail("Should be a data corrupted error: \(decodingError)") return } XCTAssert(context.debugDescription.hasPrefix("Failed to decode GenerateContentResponse")) @@ -1038,17 +1059,17 @@ final class GenerativeModelVertexAITests: XCTestCase { XCTAssertNotNil(responseError) let generateContentError = try XCTUnwrap(responseError as? GenerateContentError) guard case let .internalError(underlyingError) = generateContentError else { - XCTFail("Not an internal error: \(generateContentError)") + XCTFail("Should be an internal error: \(generateContentError)") return } let invalidCandidateError = try XCTUnwrap(underlyingError as? InvalidCandidateError) guard case let .emptyContent(emptyContentUnderlyingError) = invalidCandidateError else { - XCTFail("Not an empty content error: \(invalidCandidateError)") + XCTFail("Should be an empty content error: \(invalidCandidateError)") return } _ = try XCTUnwrap( - emptyContentUnderlyingError as? DecodingError, - "Not a decoding error: \(emptyContentUnderlyingError)" + emptyContentUnderlyingError as? Candidate.EmptyContentError, + "Should be an empty content error: \(emptyContentUnderlyingError)" ) } @@ -1563,7 +1584,7 @@ final class GenerativeModelVertexAITests: XCTestCase { } } catch let GenerateContentError.internalError(underlying as DecodingError) { guard case let .dataCorrupted(context) = underlying else { - XCTFail("Not a data corrupted error: \(underlying)") + XCTFail("Should be a data corrupted error: \(underlying)") return } XCTAssert(context.debugDescription.hasPrefix("Failed to decode GenerateContentResponse")) @@ -1591,11 +1612,11 @@ final class GenerativeModelVertexAITests: XCTestCase { } } catch let GenerateContentError.internalError(underlyingError as InvalidCandidateError) { guard case let .emptyContent(contentError) = underlyingError else { - XCTFail("Not an empty content error: \(underlyingError)") + XCTFail("Should be an empty content error: \(underlyingError)") return } - XCTAssert(contentError is DecodingError) + XCTAssert(contentError is Candidate.EmptyContentError) return } From dba582f2061e2df65c1e303c82b344962c0b6cfe Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Thu, 4 Sep 2025 13:15:21 -0400 Subject: [PATCH 75/76] fix(spm): Add explicit SwiftPM dependencies to avoid undefined symbols (#15287) --- Crashlytics/CHANGELOG.md | 4 ++++ FirebasePerformance/CHANGELOG.md | 4 ++++ FirebaseRemoteConfig/CHANGELOG.md | 4 ++++ Package.swift | 8 ++++++++ 4 files changed, 20 insertions(+) diff --git a/Crashlytics/CHANGELOG.md b/Crashlytics/CHANGELOG.md index 777e07cd8b1..b4d4bbf8c5e 100644 --- a/Crashlytics/CHANGELOG.md +++ b/Crashlytics/CHANGELOG.md @@ -1,3 +1,7 @@ +# Unreleased +- [fixed] Add missing nanopb dependency to fix SwiftPM builds when building + dynamically linked libraries. (#15276) + # 12.1.0 - [fixed] Do not log using raw print in an internal class. (#15138) diff --git a/FirebasePerformance/CHANGELOG.md b/FirebasePerformance/CHANGELOG.md index 6ac0cee960b..14dbbbb3a16 100644 --- a/FirebasePerformance/CHANGELOG.md +++ b/FirebasePerformance/CHANGELOG.md @@ -1,3 +1,7 @@ +# Unreleased +- [fixed] Add missing nanopb dependency to fix SwiftPM builds when building + dynamically linked libraries. (#15276) + # 11.6.0 - [fixed] Fix a crash related to registering for notifications when the app is between foreground or background states. (#13174) diff --git a/FirebaseRemoteConfig/CHANGELOG.md b/FirebaseRemoteConfig/CHANGELOG.md index 36ced2c9a19..f5db5a0a572 100644 --- a/FirebaseRemoteConfig/CHANGELOG.md +++ b/FirebaseRemoteConfig/CHANGELOG.md @@ -1,3 +1,7 @@ +# Unreleased +- [fixed] Add missing GoogleUtilities dependency to fix SwiftPM builds when + building dynamically linked libraries. (#15276) + # 12.2.0 - [fixed] Fixed a race condition that could lead to a crash during network session recreation. (#15087) diff --git a/Package.swift b/Package.swift index 67247393177..8336778a177 100644 --- a/Package.swift +++ b/Package.swift @@ -1003,6 +1003,7 @@ let package = Package( "FirebaseABTesting", "FirebaseInstallations", "FirebaseRemoteConfigInterop", + .product(name: "GULEnvironment", package: "GoogleUtilities"), .product(name: "GULNSData", package: "GoogleUtilities"), ], path: "FirebaseRemoteConfig/Sources", @@ -1100,6 +1101,13 @@ let package = Package( "FirebaseInstallations", "FirebaseCoreExtension", "FirebaseSessionsObjC", + // The `FirebaseSessions` target transitively depends on nanopb via the internal + // `FirebaseSessionsObjC` target. Not explicitly depending on nanopb leads to + // undefined symbol errors in Tuist based SPM builds. + // See the conversations in + // - https://github.com/firebase/firebase-ios-sdk/issues/15276 + // - https://github.com/firebase/firebase-ios-sdk/pull/15287 + .product(name: "nanopb", package: "nanopb"), .product(name: "Promises", package: "Promises"), .product(name: "GoogleDataTransport", package: "GoogleDataTransport"), .product(name: "GULEnvironment", package: "GoogleUtilities"), From 35bb1b8b145635d798e03da4663a02fe54784fe9 Mon Sep 17 00:00:00 2001 From: Srushti Vaidya Date: Tue, 9 Sep 2025 14:22:45 +0530 Subject: [PATCH 76/76] IdP-Initiated Saml Sign In Implementation (#15291) --- FirebaseAuth/Sources/Swift/Auth/Auth.swift | 23 +++ .../RPC/SignInWithSamlIdpRequest.swift | 55 +++++++ .../RPC/SignInWithSamlIdpResponse.swift | 46 ++++++ .../AuthenticationExample/SceneDelegate.swift | 54 +++++++ .../SignInWithSamlIdpTests.swift | 81 ++++++++++ FirebaseAuth/Tests/Unit/AuthTests.swift | 146 ++++++++++++++++++ .../Unit/SignInWithSamlIdpRequestTests.swift | 113 ++++++++++++++ .../Unit/SignInWithSamlIdpResponseTests.swift | 85 ++++++++++ 8 files changed, 603 insertions(+) create mode 100644 FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithSamlIdpRequest.swift create mode 100644 FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithSamlIdpResponse.swift create mode 100644 FirebaseAuth/Tests/SampleSwift/SwiftApiTests/SignInWithSamlIdpTests.swift create mode 100644 FirebaseAuth/Tests/Unit/SignInWithSamlIdpRequestTests.swift create mode 100644 FirebaseAuth/Tests/Unit/SignInWithSamlIdpResponseTests.swift diff --git a/FirebaseAuth/Sources/Swift/Auth/Auth.swift b/FirebaseAuth/Sources/Swift/Auth/Auth.swift index d198f5418f5..fcb4bc33636 100644 --- a/FirebaseAuth/Sources/Swift/Auth/Auth.swift +++ b/FirebaseAuth/Sources/Swift/Auth/Auth.swift @@ -2341,6 +2341,29 @@ extension Auth: AuthInterop { } #endif + // MARK: IDP Initiated SAML Sign In + + public func signInWithSamlIdp(ProviderId providerId: String, + SpAcsUrl spAcsUrl: String, + SamlResp samlResp: String) async throws -> AuthDataResult { + let samlRespBody = "SAMLResponse=\(samlResp)&providerId=\(providerId)" + let request = SignInWithSamlIdpRequest( + requestUri: spAcsUrl, + postBody: samlRespBody, + returnSecureToken: true, + requestConfiguration: requestConfiguration + ) + let response = try await backend.call(with: request) + let user = try await completeSignIn( + withAccessToken: response.idToken, + accessTokenExpirationDate: response.expirationDate, + refreshToken: response.refreshToken, + anonymous: false + ) + try await updateCurrentUser(user) + return AuthDataResult(withUser: user, additionalUserInfo: nil) + } + // MARK: Internal properties /// Allow tests to swap in an alternate mainBundle, including ObjC unit tests via CocoaPods. diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithSamlIdpRequest.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithSamlIdpRequest.swift new file mode 100644 index 00000000000..c85044cbc2b --- /dev/null +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithSamlIdpRequest.swift @@ -0,0 +1,55 @@ +// 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. + +import Foundation + +final class SignInWithSamlIdpRequest: AuthRPCRequest { + typealias Response = SignInWithSamlIdpResponse + private let config: AuthRequestConfiguration + private let requestUri: String + private let postBody: String + private let returnSecureToken: Bool + + init(requestUri: String, + postBody: String, + returnSecureToken: Bool, + requestConfiguration: AuthRequestConfiguration) { + self.requestUri = requestUri + self.postBody = postBody + self.returnSecureToken = returnSecureToken + config = requestConfiguration + } + + func requestConfiguration() -> AuthRequestConfiguration { + return config + } + + func requestURL() -> URL { + var comps = URLComponents() + comps.scheme = "https" + comps.host = "identitytoolkit.googleapis.com" + comps.path = "/v1/accounts:signInWithIdp" + comps.queryItems = [URLQueryItem(name: "key", value: config.apiKey)] + return comps.url! + } + + var unencodedHTTPRequestBody: [String: AnyHashable]? { + let body: [String: AnyHashable] = [ + "requestUri": requestUri, + "postBody": postBody, + "returnSecureToken": returnSecureToken, + ] + return body + } +} diff --git a/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithSamlIdpResponse.swift b/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithSamlIdpResponse.swift new file mode 100644 index 00000000000..72ca328ba21 --- /dev/null +++ b/FirebaseAuth/Sources/Swift/Backend/RPC/SignInWithSamlIdpResponse.swift @@ -0,0 +1,46 @@ +// 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. + +import Foundation + +struct SignInWithSamlIdpResponse: AuthRPCResponse { + /// The user raw access token. + let idToken: String + /// Refresh token for the authenticated user. + let refreshToken: String + /// The provider Identifier + let providerId: String + /// The email id of user + let email: String + /// The calculated date and time when the token expires. + let expirationDate: Date + + init(dictionary: [String: AnyHashable]) throws { + guard + let email = dictionary["email"] as? String, + let expiration = dictionary["expiresIn"] as? String, + let idToken = dictionary["idToken"] as? String, + let providerId = dictionary["providerId"] as? String, + let refreshToken = dictionary["refreshToken"] as? String + else { + throw AuthErrorUtils.unexpectedResponse(deserializedResponse: dictionary) + } + self.idToken = idToken + self.refreshToken = refreshToken + self.providerId = providerId + self.email = email + let expiresInSec = TimeInterval(expiration) + expirationDate = Date().addingTimeInterval(expiresInSec ?? 3600) + } +} diff --git a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/SceneDelegate.swift b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/SceneDelegate.swift index e7965767a8a..ed5a0cea2d3 100644 --- a/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/SceneDelegate.swift +++ b/FirebaseAuth/Tests/SampleSwift/AuthenticationExample/SceneDelegate.swift @@ -50,10 +50,64 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { // Implementing this delegate method is needed when swizzling is disabled. // Without it, reCAPTCHA's login view controller will not dismiss. + // Without it, IdP Initiated SAML Sign In will not work. func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { for urlContext in URLContexts { let url = urlContext.url _ = Auth.auth().canHandle(url) + /// Handle IdP Initiated SAML deep link myapp://saml?resp= + if url.scheme?.lowercased() == "myapp", /// replace with your custom scheme + url.host?.lowercased() == "saml" { /// replace with your host + let spAcsUrl = + "https://iostemp-8a944.web.app/googleidp-saml/acs" /// replace with your SP ACS URL + if let rawQuery = url.query { + var respValue: String? + for pair in rawQuery.split(separator: "&", omittingEmptySubsequences: false) { + let parts = pair.split(separator: "=", maxSplits: 1, omittingEmptySubsequences: false) + if parts.count == 2, parts[0] == "resp" { + respValue = String(parts[1]) + break + } + } + if let resp = respValue { + let alert = UIAlertController( + title: "SAML Sign In", + message: "Enter Provider ID", + preferredStyle: .alert + ) + alert.addTextField { tf in + tf.placeholder = "Provider ID" + tf.text = "saml.provider" + tf.autocapitalizationType = .none + tf.autocorrectionType = .no + } + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) + alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in + let providerId = alert.textFields?.first?.text? + .trimmingCharacters(in: .whitespacesAndNewlines) ?? "" + let requestUri = alert.textFields?.last?.text? + .trimmingCharacters(in: .whitespacesAndNewlines) ?? "" + guard !providerId.isEmpty, !requestUri.isEmpty else { return } + Task { + do { + _ = try await AppManager.shared.auth().signInWithSamlIdp( + ProviderId: providerId, + SpAcsUrl: requestUri, + SamlResp: resp + ) + } catch { + print("IdP-initiated SAML sign-in failed with error:", error) + } + } + }) + var top = window?.rootViewController + while let presented = top?.presentedViewController { + top = presented + } + top?.present(alert, animated: true) + } + } + } } // URL not auth related; it should be handled separately. diff --git a/FirebaseAuth/Tests/SampleSwift/SwiftApiTests/SignInWithSamlIdpTests.swift b/FirebaseAuth/Tests/SampleSwift/SwiftApiTests/SignInWithSamlIdpTests.swift new file mode 100644 index 00000000000..5e8dc2c127c --- /dev/null +++ b/FirebaseAuth/Tests/SampleSwift/SwiftApiTests/SignInWithSamlIdpTests.swift @@ -0,0 +1,81 @@ +// 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. + +#if os(iOS) + + @testable import FirebaseAuth + import XCTest + + @available(iOS 15.0, macOS 12.0, tvOS 16.0, *) + class SignInWithSamlIdpTests: TestsBase { + func testSignInWithSamlFailureInvalidProvider() async throws { + try? await deleteCurrentUserAsync() + let invalidProvider = "saml.invalid" + let spAcsUrl = "https://example.com/saml-acs" + let samlResp = "samlResp" + do { + _ = try await Auth.auth().signInWithSamlIdp( + ProviderId: invalidProvider, + SpAcsUrl: spAcsUrl, + SamlResp: samlResp + ) + XCTFail("Expected failure for invalid provider ID") + } catch { + let ns = error as NSError + if let code = AuthErrorCode(rawValue: ns.code) { + XCTAssert([.operationNotAllowed].contains(code), + "Unexpected code: \(code)") + } else { + XCTFail("Unexpected error: \(error)") + } + let desc = (ns.userInfo[NSLocalizedDescriptionKey] as? String ?? "").uppercased() + XCTAssert( + desc.contains("THE IDENTITY PROVIDER CONFIGURATION IS NOT FOUND."), + "Expected backend invalid provider message, got: \(desc)" + ) + } + XCTAssertNil(Auth.auth().currentUser) + } + + func testSignInWithSamlFailureInvalidResponse() async throws { + try? await deleteCurrentUserAsync() + let providerId = "saml.googleidp" + let spAcsUrl = "https://example.com/saml-acs" + let invalidSamlResp = "invalid%25" + do { + _ = try await Auth.auth().signInWithSamlIdp( + ProviderId: providerId, + SpAcsUrl: spAcsUrl, + SamlResp: invalidSamlResp + ) + XCTFail("Expected failure for invalid SAMLResponse") + } catch { + let ns = error as NSError + if let code = AuthErrorCode(rawValue: ns.code) { + XCTAssert([.invalidCredential, .internalError].contains(code), + "Unexpected code: \(code)") + } else { + XCTFail("Unexpected error: \(error)") + } + let desc = (ns.userInfo[NSLocalizedDescriptionKey] as? String ?? "").uppercased() + XCTAssert( + desc.contains("UNABLE TO PARSE THE SAML TOKEN."), + "Expected backend invalid credential message, got: \(desc)" + ) + } + XCTAssertNil(Auth.auth().currentUser) + } + } + +#endif diff --git a/FirebaseAuth/Tests/Unit/AuthTests.swift b/FirebaseAuth/Tests/Unit/AuthTests.swift index 5ae1d522108..8e8fc2474f4 100644 --- a/FirebaseAuth/Tests/Unit/AuthTests.swift +++ b/FirebaseAuth/Tests/Unit/AuthTests.swift @@ -2287,6 +2287,152 @@ class AuthTests: RPCBaseTests { } #endif + // MARK: SAML IdP sign-in + + #if os(iOS) + + static let kSamlProviderId = "saml.idp" + static let kSamlAcsUrl = "https://example.com/saml-acs-url" + static let kSamlResponse = "BASE64_SAML_ASSERTION" + static let kBadSamlResponse = "MALFORMED_OR_TAMPERED_SAML" + + func testSignInWithSamlIdpSuccess() throws { + let expectation = self.expectation(description: #function) + setFakeGetAccountProvider() + setFakeSecureTokenService() + rpcIssuer.respondBlock = { + let req = try XCTUnwrap(self.rpcIssuer.request as? SignInWithSamlIdpRequest) + XCTAssertEqual(req.requestConfiguration().apiKey, AuthTests.kFakeAPIKey) + XCTAssertEqual( + req.unencodedHTTPRequestBody?["requestUri"] as? String, + AuthTests.kSamlAcsUrl + ) + XCTAssertTrue( + (req.unencodedHTTPRequestBody?["postBody"] as? String)?.contains( + AuthTests.kSamlProviderId + ) ?? false + ) + XCTAssertTrue(req.unencodedHTTPRequestBody?["returnSecureToken"] as? Bool ?? false) + return try self.rpcIssuer.respond(withJSON: [ + "idToken": RPCBaseTests.kFakeAccessToken, + "refreshToken": self.kRefreshToken, + "email": self.kEmail, + "providerId": AuthTests.kSamlProviderId, + "expiresIn": "3600", + ]) + } + try auth.signOut() + Task { + do { + let result = try await self.auth.signInWithSamlIdp( + ProviderId: AuthTests.kSamlProviderId, + SpAcsUrl: AuthTests.kSamlAcsUrl, + SamlResp: AuthTests.kSamlResponse + ) + XCTAssertEqual(result.user.email, self.kEmail) + XCTAssertEqual(result.user.refreshToken, self.kRefreshToken) + XCTAssertFalse(result.user.isAnonymous) + expectation.fulfill() + } catch { + XCTFail("Unexpected error: \(error)") + } + } + waitForExpectations(timeout: 5) + } + + func testSignInWithSamlIdpWithIncorrectUrl() throws { + let expectation = self.expectation(description: #function) + let kBadSamlAcsUrl = "https://example.com/saml-acs-incorrect-url" + rpcIssuer.respondBlock = { + let req = try XCTUnwrap(self.rpcIssuer.request as? SignInWithSamlIdpRequest) + XCTAssertEqual(req.requestConfiguration().apiKey, AuthTests.kFakeAPIKey) + let body = try XCTUnwrap(req.unencodedHTTPRequestBody) + XCTAssertEqual(body["requestUri"] as? String, kBadSamlAcsUrl) + return try self.rpcIssuer.respond(serverErrorMessage: "OPERATION_NOT_ALLOWED") + } + try auth.signOut() + Task { + do { + _ = try await self.auth.signInWithSamlIdp( + ProviderId: AuthTests.kSamlProviderId, + SpAcsUrl: kBadSamlAcsUrl, + SamlResp: AuthTests.kSamlResponse + ) + XCTFail("Expected OPERATION_NOT_ALLOWED") + } catch { + let ns = error as NSError + XCTAssertEqual(ns.code, AuthErrorCode.operationNotAllowed.rawValue) + expectation.fulfill() + } + } + waitForExpectations(timeout: 5) + XCTAssertNil(auth.currentUser) + } + + func testSignInWithSamlIdpFailureInvalidProviderId() throws { + let expectation = self.expectation(description: #function) + let badProvider = "saml.non-existent-idp" + rpcIssuer.respondBlock = { + let req = try XCTUnwrap(self.rpcIssuer.request as? SignInWithSamlIdpRequest) + XCTAssertEqual(req.requestConfiguration().apiKey, AuthTests.kFakeAPIKey) + let body = try XCTUnwrap(req.unencodedHTTPRequestBody) + let postBody = try XCTUnwrap(body["postBody"] as? String) + XCTAssertTrue(postBody.contains("providerId=\(badProvider)")) + return try self.rpcIssuer.respond(serverErrorMessage: "OPERATION_NOT_ALLOWED") + } + try auth.signOut() + Task { + do { + _ = try await self.auth.signInWithSamlIdp( + ProviderId: badProvider, // wrong providerId + SpAcsUrl: AuthTests.kSamlAcsUrl, + SamlResp: AuthTests.kSamlResponse + ) + XCTFail("Expected OPERATION_NOT_ALLOWED") + } catch { + let ns = error as NSError + XCTAssertEqual(ns.code, AuthErrorCode.operationNotAllowed.rawValue) + expectation.fulfill() + } + } + waitForExpectations(timeout: 5) + XCTAssertNil(auth.currentUser) + } + + func testSignInWithSamlIdpFailureInvalidPostBody() throws { + let expectation = self.expectation(description: #function) + rpcIssuer.respondBlock = { + let req = try XCTUnwrap(self.rpcIssuer.request as? SignInWithSamlIdpRequest) + XCTAssertEqual(req.requestConfiguration().apiKey, AuthTests.kFakeAPIKey) + let body = try XCTUnwrap(req.unencodedHTTPRequestBody) + XCTAssertEqual(body["requestUri"] as? String, AuthTests.kSamlAcsUrl) + let postBody = try XCTUnwrap(body["postBody"] as? String) + XCTAssertTrue(postBody.contains("SAMLResponse=\(AuthTests.kBadSamlResponse)")) + XCTAssertTrue(postBody.contains("providerId=\(AuthTests.kSamlProviderId)")) + XCTAssertTrue(body["returnSecureToken"] as? Bool ?? false) + return try self.rpcIssuer + .respond(underlyingErrorMessage: "INVALID_CREDENTIAL_OR_PROVIDER_ID") + } + try auth.signOut() + Task { + do { + _ = try await self.auth.signInWithSamlIdp( + ProviderId: AuthTests.kSamlProviderId, + SpAcsUrl: AuthTests.kSamlAcsUrl, + SamlResp: AuthTests.kBadSamlResponse + ) + XCTFail("Expected internalError but got success") + } catch { + let ns = error as NSError + XCTAssertEqual(ns.code, AuthErrorCode.internalError.rawValue) + expectation.fulfill() + } + } + waitForExpectations(timeout: 5) + XCTAssertNil(auth.currentUser) + } + #endif + // MARK: Application Delegate tests. #if os(iOS) diff --git a/FirebaseAuth/Tests/Unit/SignInWithSamlIdpRequestTests.swift b/FirebaseAuth/Tests/Unit/SignInWithSamlIdpRequestTests.swift new file mode 100644 index 00000000000..501dbf3a594 --- /dev/null +++ b/FirebaseAuth/Tests/Unit/SignInWithSamlIdpRequestTests.swift @@ -0,0 +1,113 @@ +// 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. + +@testable import FirebaseAuth +import FirebaseCore +import XCTest + +final class SignInWithSamlIdpRequestTests: XCTestCase { + let kAPIKey = "TEST_API_KEY" + let kAppID = "FAKE_APP_ID" + let kRequestUri = "https://example.web.app/sp-acs-url" + let kPostBody = "SAMLResponse=BASE64%2BSAFE&providerId=saml.provider" + let kComplexUri = "https://host/acs;param?p1=v1&p2=v2#frag" + let kRawPostBody = + "SAMLResponse=someResponse&providerId=saml.provider" + + var configuration: AuthRequestConfiguration! + + override func setUp() { + super.setUp() + configuration = AuthRequestConfiguration(apiKey: kAPIKey, appID: kAppID) + } + + override func tearDown() { + configuration = nil + super.tearDown() + } + + func testRequestURL() { + let request = SignInWithSamlIdpRequest( + requestUri: kRequestUri, + postBody: kPostBody, + returnSecureToken: true, + requestConfiguration: configuration + ) + + let url = request.requestURL() + XCTAssertEqual(url.scheme, "https") + XCTAssertEqual(url.host, "identitytoolkit.googleapis.com") + XCTAssertEqual(url.path, "/v1/accounts:signInWithIdp") + + let components = URLComponents(url: url, resolvingAgainstBaseURL: false) + XCTAssertEqual(components?.queryItems?.count, 1) + XCTAssertEqual(components?.queryItems?.first?.name, "key") + XCTAssertEqual(components?.queryItems?.first?.value, kAPIKey) + } + + func testRequestConfigurationPassed() { + let request = SignInWithSamlIdpRequest( + requestUri: kRequestUri, + postBody: kPostBody, + returnSecureToken: false, + requestConfiguration: configuration + ) + + let returned = request.requestConfiguration() + XCTAssertEqual(returned.apiKey, kAPIKey) + XCTAssertIdentical(returned.auth, configuration.auth) + } + + func testUnencodedHTTPRequestBody() { + let request = SignInWithSamlIdpRequest( + requestUri: kRequestUri, + postBody: kPostBody, + returnSecureToken: true, + requestConfiguration: configuration + ) + + guard let body = request.unencodedHTTPRequestBody else { + XCTFail("Body must not be nil") + return + } + + XCTAssertEqual(body.count, 3) + XCTAssertEqual(body["requestUri"] as? String, kRequestUri) + XCTAssertEqual(body["postBody"] as? String, kPostBody) + XCTAssertEqual(body["returnSecureToken"] as? Bool, true) + } + + func testUnencodedHTTPRequestPostBody() { + let request = SignInWithSamlIdpRequest( + requestUri: kRequestUri, + postBody: kRawPostBody, + returnSecureToken: true, + requestConfiguration: configuration + ) + + let body = request.unencodedHTTPRequestBody + XCTAssertEqual(body?["postBody"] as? String, kRawPostBody) + } + + func testUnencodedHTTPRequestBody_AllowsComplexRequestUri() throws { + let request = SignInWithSamlIdpRequest( + requestUri: kComplexUri, + postBody: kPostBody, + returnSecureToken: true, + requestConfiguration: configuration + ) + let body = try XCTUnwrap(request.unencodedHTTPRequestBody) + XCTAssertEqual(body["requestUri"] as? String, kComplexUri) + } +} diff --git a/FirebaseAuth/Tests/Unit/SignInWithSamlIdpResponseTests.swift b/FirebaseAuth/Tests/Unit/SignInWithSamlIdpResponseTests.swift new file mode 100644 index 00000000000..d3c6e2bb6d9 --- /dev/null +++ b/FirebaseAuth/Tests/Unit/SignInWithSamlIdpResponseTests.swift @@ -0,0 +1,85 @@ +// 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. + +@testable import FirebaseAuth +import XCTest + +final class SignInWithSamlIdpResponseTests: XCTestCase { + private func makeValidDictionary() -> [String: AnyHashable] { + return [ + "email": "user@example.com", + "expiresIn": "3600", + "idToken": "FAKE_ID_TOKEN", + "providerId": "saml.provider", + "refreshToken": "FAKE_REFRESH_TOKEN", + ] + } + + func testInitWithValidDictionaryAllRequiredFields() throws { + var dict = makeValidDictionary() + dict["email"] = "user1@example.com" + dict["idToken"] = "ID.TOKEN" + dict["providerId"] = "saml.myidp" + dict["refreshToken"] = "REFRESH.TOKEN" + let response = try SignInWithSamlIdpResponse(dictionary: dict) + XCTAssertEqual(response.email, "user1@example.com") + XCTAssertEqual(response.idToken, "ID.TOKEN") + XCTAssertEqual(response.providerId, "saml.myidp") + XCTAssertEqual(response.refreshToken, "REFRESH.TOKEN") + } + + func testInitMissingRequiredFields() { + struct Case { let name: String; let keyToRemove: String } + let cases: [Case] = [ + .init(name: "Missing email", keyToRemove: "email"), + .init(name: "Missing expiresIn", keyToRemove: "expiresIn"), + .init(name: "Missing idToken", keyToRemove: "idToken"), + .init(name: "Missing providerId", keyToRemove: "providerId"), + .init(name: "Missing refreshToken", keyToRemove: "refreshToken"), + ] + for c in cases { + var dict = makeValidDictionary() + dict.removeValue(forKey: c.keyToRemove) + XCTAssertThrowsError(try SignInWithSamlIdpResponse(dictionary: dict), c.name) { error in + let nsError = error as NSError + XCTAssertEqual(nsError.domain, AuthErrorDomain) + XCTAssertEqual(nsError.code, AuthErrorCode.internalError.rawValue) + } + } + } + + func testInitIncorrectFieldTypes() { + var dict = makeValidDictionary() + dict["expiresIn"] = 3600 + XCTAssertThrowsError(try SignInWithSamlIdpResponse(dictionary: dict)) { error in + let nsError = error as NSError + XCTAssertEqual(nsError.domain, AuthErrorDomain) + XCTAssertEqual(nsError.code, AuthErrorCode.internalError.rawValue) + } + dict = makeValidDictionary() + dict["idToken"] = 123 + XCTAssertThrowsError(try SignInWithSamlIdpResponse(dictionary: dict)) { error in + let nsError = error as NSError + XCTAssertEqual(nsError.domain, AuthErrorDomain) + XCTAssertEqual(nsError.code, AuthErrorCode.internalError.rawValue) + } + dict = makeValidDictionary() + dict["email"] = NSNull() + XCTAssertThrowsError(try SignInWithSamlIdpResponse(dictionary: dict)) { error in + let nsError = error as NSError + XCTAssertEqual(nsError.domain, AuthErrorDomain) + XCTAssertEqual(nsError.code, AuthErrorCode.internalError.rawValue) + } + } +}