From 87bba4db5edfbf80155c83cc0a3f1788df9b2431 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Fri, 19 Apr 2024 16:31:38 -0400 Subject: [PATCH 01/12] [Release Tooling] Handle all resources the same when building on Xcode 15 --- .../Sources/ZipBuilder/FrameworkBuilder.swift | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift b/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift index 1dd183e0c75..60ae7f70612 100755 --- a/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift +++ b/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift @@ -674,20 +674,6 @@ struct FrameworkBuilder { includingPropertiesForKeys: nil ) .filter { $0.pathExtension == "bundle" } - // TODO(ncooke3): Once the zip is built with Xcode 15, the following - // `filter` can be removed. The following block exists to preserve - // how resources (e.g. like FIAM's) are packaged for use in Xcode 14. - .filter { bundleURL in - let dirEnum = fileManager.enumerator(atPath: bundleURL.path) - var containsPrivacyManifest = false - while let relativeFilePath = dirEnum?.nextObject() as? String { - if relativeFilePath.hasSuffix("PrivacyInfo.xcprivacy") { - containsPrivacyManifest = true - break - } - } - return containsPrivacyManifest - } // Bundles are moved rather than copied to prevent them from being // packaged in a `Resources` directory at the root of the xcframework. .forEach { try! fileManager.moveItem( From c441f62661ca638a2e8cec6ee0adc2aa99b6e9a2 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Fri, 19 Apr 2024 16:33:15 -0400 Subject: [PATCH 02/12] Refactor out of method --- .../Sources/ZipBuilder/FrameworkBuilder.swift | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift b/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift index 60ae7f70612..0aa50f026ef 100755 --- a/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift +++ b/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift @@ -651,7 +651,20 @@ struct FrameworkBuilder { platform == .catalyst || platform == .macOS ? "Resources" : "" ) .resolvingSymlinksInPath() - processPrivacyManifests(fileManager, frameworkPath, resourceDir) + + // Move resource bundles into the platform framework. + try? fileManager.contentsOfDirectory( + at: frameworkPath.deletingLastPathComponent(), + includingPropertiesForKeys: nil + ) + .filter { $0.pathExtension == "bundle" } + // Bundles are moved rather than copied to prevent them from being + // packaged in a `Resources` directory at the root of the xcframework. + .forEach { try! fileManager.moveItem( + at: $0, + to: platformFrameworkDir.appendingPathComponent($0.lastPathComponent) + ) } + // Use the appropriate moduleMaps packageModuleMaps(inFrameworks: [frameworkPath], @@ -663,25 +676,6 @@ struct FrameworkBuilder { } } - /// Process privacy manifests. - /// - /// Move any privacy manifest-containing resource bundles into the platform framework. - func processPrivacyManifests(_ fileManager: FileManager, - _ frameworkPath: URL, - _ platformFrameworkDir: URL) { - try? fileManager.contentsOfDirectory( - at: frameworkPath.deletingLastPathComponent(), - includingPropertiesForKeys: nil - ) - .filter { $0.pathExtension == "bundle" } - // Bundles are moved rather than copied to prevent them from being - // packaged in a `Resources` directory at the root of the xcframework. - .forEach { try! fileManager.moveItem( - at: $0, - to: platformFrameworkDir.appendingPathComponent($0.lastPathComponent) - ) } - } - /// Package the built frameworks into an XCFramework. /// - Parameter withName: The framework name. /// - Parameter frameworks: The grouped frameworks. From 6df82082f84cae85f582becdd439e64e38150b7a Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Fri, 19 Apr 2024 16:33:28 -0400 Subject: [PATCH 03/12] style --- ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift b/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift index 0aa50f026ef..63c020a51b1 100755 --- a/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift +++ b/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift @@ -665,7 +665,6 @@ struct FrameworkBuilder { to: platformFrameworkDir.appendingPathComponent($0.lastPathComponent) ) } - // Use the appropriate moduleMaps packageModuleMaps(inFrameworks: [frameworkPath], frameworkName: framework, From c8cd11c9c5e6dfd8c4a31e0a93c000a27da216f7 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Fri, 19 Apr 2024 16:40:09 -0400 Subject: [PATCH 04/12] Stop including gRPC-Certificates.bundle --- ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift b/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift index 63c020a51b1..9ab77c0674d 100755 --- a/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift +++ b/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift @@ -658,6 +658,8 @@ struct FrameworkBuilder { includingPropertiesForKeys: nil ) .filter { $0.pathExtension == "bundle" } + // Filter out `gRPCCertificates-Cpp.bundle` since it is unused. + .filter { $0.lastPathComponent == "gRPCCertificates-Cpp.bundle" } // Bundles are moved rather than copied to prevent them from being // packaged in a `Resources` directory at the root of the xcframework. .forEach { try! fileManager.moveItem( From 570900232c12fd1c1751b2c9c818075de1a2de98 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Fri, 19 Apr 2024 17:03:40 -0400 Subject: [PATCH 05/12] Add search path for FIAM resource bundle since it will be embedded --- .../Sources/DefaultUI/FIRIAMDefaultDisplayImpl.m | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/FirebaseInAppMessaging/Sources/DefaultUI/FIRIAMDefaultDisplayImpl.m b/FirebaseInAppMessaging/Sources/DefaultUI/FIRIAMDefaultDisplayImpl.m index dc7bc917dda..138634b9d63 100644 --- a/FirebaseInAppMessaging/Sources/DefaultUI/FIRIAMDefaultDisplayImpl.m +++ b/FirebaseInAppMessaging/Sources/DefaultUI/FIRIAMDefaultDisplayImpl.m @@ -67,7 +67,15 @@ + (NSBundle *)getViewResourceBundle { NSBundle *containingBundle; NSURL *bundleURL; // The containing bundle is different whether FIAM is statically or dynamically linked. - for (containingBundle in @[ [NSBundle mainBundle], [NSBundle bundleForClass:myClass] ]) { + for (containingBundle in @[ + // Statically linked. + [NSBundle mainBundle], + // Dynamically linked. + [NSBundle bundleForClass:myClass], + // Embedded static framework (zip distribution). + [[NSBundle.mainBundle.bundleURL URLByAppendingPathComponent:@"Frameworks"] + URLByAppendingPathComponent:@"FirebaseInAppMessaging.framework"] + ]) { bundleURL = [containingBundle URLForResource:bundledResource withExtension:@"bundle"]; if (bundleURL != nil) break; } From b7ce806fba2f2b8c230f15d5a22a1cb23f479cf1 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Fri, 19 Apr 2024 17:07:30 -0400 Subject: [PATCH 06/12] Update README.md --- ReleaseTooling/Template/README.md | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/ReleaseTooling/Template/README.md b/ReleaseTooling/Template/README.md index 4073b74c289..2e71b138136 100644 --- a/ReleaseTooling/Template/README.md +++ b/ReleaseTooling/Template/README.md @@ -24,11 +24,11 @@ Xcode 15.2 or newer is required. To integrate a Firebase SDK with your app: 1. Find the desired SDK from the list within `METADATA.md`. -2. Make sure you have an Xcode project open in Xcode. -3. In Xcode, hit `⌘-1` to open the Project Navigator pane. It will open on +1. Make sure you have an Xcode project open in Xcode. +1. In Xcode, hit `⌘-1` to open the Project Navigator pane. It will open on left side of the Xcode window if it wasn't already open. -4. Remove any existing Firebase xcframeworks from your project. -5. Drag each xcframework from the "FirebaseAnalytics" directory into the Project +1. Remove any existing Firebase xcframeworks from your project. +1. Drag each xcframework from the "FirebaseAnalytics" directory into the Project Navigator pane. In the dialog box that appears, make sure the target you want the framework to be added to has a checkmark next to it, and that you've selected "Copy items if needed". @@ -36,25 +36,20 @@ To integrate a Firebase SDK with your app: > ⚠ To disable AdId support, do not copy > `GoogleAppMeasurementIdentitySupport.xcframework`. -6. Drag each framework from the directory named after the SDK into the Project +1. Drag each framework from the directory named after the SDK into the Project Navigator pane. Note that there may be no additional frameworks, in which case this directory will be empty. For instance, if you want the Database SDK, look in the Database folder for the required frameworks. In the dialog box that appears, make sure the target you want this framework to be added to has a checkmark next to it, and that you've selected "Copy items if needed." -7. If using Xcode 15, embed each framework that was dragged in. Navigate to the +1. If using Xcode 15, embed each framework that was dragged in. Navigate to the target's _General_ settings and find _Frameworks, Libraries, & Embedded Content_. For each framework dragged in from the `Firebase.zip`, select **Embed & Sign**. This step will enable privacy manifests to be picked up by Xcode's tooling. -8. If the SDK has resources, go into the Resources folders, which will be in - the SDK folder. Drag all of those resources into the Project Navigator, just - like the frameworks, again making sure that the target you want to add these - resources to has a checkmark next to it, and that you've selected "Copy items - if needed". -9. Add the `-ObjC` flag to **Other Linker Settings**: +1. Add the `-ObjC` flag to **Other Linker Settings**: a. In your project settings, open the **Settings** panel for your target. @@ -63,7 +58,7 @@ To integrate a Firebase SDK with your app: c. Double-click the setting, click the '+' button, and add `-ObjC` -10. Add the `-lc++` flag to **Other Linker Settings**: +1. Add the `-lc++` flag to **Other Linker Settings**: a. In your project settings, open the **Settings** panel for your target. @@ -72,13 +67,13 @@ To integrate a Firebase SDK with your app: c. Double-click the setting, click the '+' button, and add `-lc++` -11. Drag the `Firebase.h` header in this directory into your project. This will +1. 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. -12. Drag `module.modulemap` into your project and update the +1. 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. -13. If your app does not include any Swift implementation, you may need to add +1. 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. @@ -86,7 +81,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**. -14. You're done! Build your target and start using Firebase. +1. 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 ee9878634f68913f16318841d246eb026990f37b Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Fri, 19 Apr 2024 22:44:59 -0400 Subject: [PATCH 07/12] [Debug] Add hash to resource directory to avoid collisions --- ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift b/ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift index 2b0b1de7720..0168ce8e9a2 100644 --- a/ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift +++ b/ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift @@ -485,7 +485,7 @@ struct ZipBuilder { if packageKind == "Firebase" { // Move all the bundles in the frameworks out to a common "Resources" directory to // match the existing Zip structure. - let resourcesDir = productPath.appendingPathComponent("Resources") + let resourcesDir = productPath.appendingPathComponent("Resources-\(UUID().uuidString)") try fileManager.moveItem(at: xcResourceDir, to: resourcesDir) } else { From 14dead6f98f92d8622bfc10ec53cb34c2d440469 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Sat, 20 Apr 2024 19:53:36 -0400 Subject: [PATCH 08/12] Fix gRPC bundle handling --- .../Sources/ZipBuilder/FrameworkBuilder.swift | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift b/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift index 9ab77c0674d..8a618e0fe3c 100755 --- a/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift +++ b/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift @@ -653,19 +653,31 @@ struct FrameworkBuilder { .resolvingSymlinksInPath() // Move resource bundles into the platform framework. - try? fileManager.contentsOfDirectory( - at: frameworkPath.deletingLastPathComponent(), - includingPropertiesForKeys: nil - ) - .filter { $0.pathExtension == "bundle" } - // Filter out `gRPCCertificates-Cpp.bundle` since it is unused. - .filter { $0.lastPathComponent == "gRPCCertificates-Cpp.bundle" } - // Bundles are moved rather than copied to prevent them from being - // packaged in a `Resources` directory at the root of the xcframework. - .forEach { try! fileManager.moveItem( - at: $0, - to: platformFrameworkDir.appendingPathComponent($0.lastPathComponent) - ) } + do { + try fileManager.contentsOfDirectory( + at: frameworkPath.deletingLastPathComponent(), + includingPropertiesForKeys: nil + ) + .filter { $0.pathExtension == "bundle" } + // Bundles are moved rather than copied to prevent them from being + // packaged in a `Resources` directory at the root of the xcframework. + .forEach { + // Delete `gRPCCertificates-Cpp.bundle` since it is not needed (#9184). + guard $0.lastPathComponent != "gRPCCertificates-Cpp.bundle" else { + try fileManager.removeItem(at: $0) + return + } + + try fileManager.moveItem( + at: $0, + to: platformFrameworkDir.appendingPathComponent($0.lastPathComponent) + ) + } + } catch { + fatalError( + "Could not move resources for framework \(frameworkPath), platform \(platform). Error: \(error)" + ) + } // Use the appropriate moduleMaps packageModuleMaps(inFrameworks: [frameworkPath], From 49d6cabbf3bf44a453cf86407a0f86097cfed390 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Sat, 20 Apr 2024 23:45:19 -0400 Subject: [PATCH 09/12] Remove workaround --- ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift b/ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift index 0168ce8e9a2..2b0b1de7720 100644 --- a/ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift +++ b/ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift @@ -485,7 +485,7 @@ struct ZipBuilder { if packageKind == "Firebase" { // Move all the bundles in the frameworks out to a common "Resources" directory to // match the existing Zip structure. - let resourcesDir = productPath.appendingPathComponent("Resources-\(UUID().uuidString)") + let resourcesDir = productPath.appendingPathComponent("Resources") try fileManager.moveItem(at: xcResourceDir, to: resourcesDir) } else { From e0d46cca0517f7efa0f12bbd7d8c0e64871b08de Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Sun, 21 Apr 2024 17:09:34 -0400 Subject: [PATCH 10/12] Update path --- ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift b/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift index 8a618e0fe3c..318c03ac065 100755 --- a/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift +++ b/ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift @@ -670,7 +670,7 @@ struct FrameworkBuilder { try fileManager.moveItem( at: $0, - to: platformFrameworkDir.appendingPathComponent($0.lastPathComponent) + to: resourceDir.appendingPathComponent($0.lastPathComponent) ) } } catch { From 09efe724f7f6b5bc8874f2ff0bd316a574270e2f Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Mon, 22 Apr 2024 11:53:50 -0400 Subject: [PATCH 11/12] Fix FIAM bundle --- .../Sources/DefaultUI/FIRIAMDefaultDisplayImpl.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/FirebaseInAppMessaging/Sources/DefaultUI/FIRIAMDefaultDisplayImpl.m b/FirebaseInAppMessaging/Sources/DefaultUI/FIRIAMDefaultDisplayImpl.m index 138634b9d63..ed724bfcfe3 100644 --- a/FirebaseInAppMessaging/Sources/DefaultUI/FIRIAMDefaultDisplayImpl.m +++ b/FirebaseInAppMessaging/Sources/DefaultUI/FIRIAMDefaultDisplayImpl.m @@ -73,8 +73,9 @@ + (NSBundle *)getViewResourceBundle { // Dynamically linked. [NSBundle bundleForClass:myClass], // Embedded static framework (zip distribution). - [[NSBundle.mainBundle.bundleURL URLByAppendingPathComponent:@"Frameworks"] - URLByAppendingPathComponent:@"FirebaseInAppMessaging.framework"] + [NSBundle bundleWithURL:[NSBundle.mainBundle.bundleURL + URLByAppendingPathComponent: + @"Frameworks/FirebaseInAppMessaging.framework"]] ]) { bundleURL = [containingBundle URLForResource:bundledResource withExtension:@"bundle"]; if (bundleURL != nil) break; From 65a0837e78065bae4f326216af1579c748e1f587 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 23 Apr 2024 10:35:57 -0400 Subject: [PATCH 12/12] [skip ci] Fix numbering --- ReleaseTooling/Template/README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ReleaseTooling/Template/README.md b/ReleaseTooling/Template/README.md index 2e71b138136..55c97b9b536 100644 --- a/ReleaseTooling/Template/README.md +++ b/ReleaseTooling/Template/README.md @@ -24,11 +24,11 @@ Xcode 15.2 or newer is required. To integrate a Firebase SDK with your app: 1. Find the desired SDK from the list within `METADATA.md`. -1. Make sure you have an Xcode project open in Xcode. -1. In Xcode, hit `⌘-1` to open the Project Navigator pane. It will open on +2. Make sure you have an Xcode project open in Xcode. +3. In Xcode, hit `⌘-1` to open the Project Navigator pane. It will open on left side of the Xcode window if it wasn't already open. -1. Remove any existing Firebase xcframeworks from your project. -1. Drag each xcframework from the "FirebaseAnalytics" directory into the Project +4. Remove any existing Firebase xcframeworks from your project. +5. Drag each xcframework from the "FirebaseAnalytics" directory into the Project Navigator pane. In the dialog box that appears, make sure the target you want the framework to be added to has a checkmark next to it, and that you've selected "Copy items if needed". @@ -36,20 +36,20 @@ To integrate a Firebase SDK with your app: > ⚠ To disable AdId support, do not copy > `GoogleAppMeasurementIdentitySupport.xcframework`. -1. Drag each framework from the directory named after the SDK into the Project +6. Drag each framework from the directory named after the SDK into the Project Navigator pane. Note that there may be no additional frameworks, in which case this directory will be empty. For instance, if you want the Database SDK, look in the Database folder for the required frameworks. In the dialog box that appears, make sure the target you want this framework to be added to has a checkmark next to it, and that you've selected "Copy items if needed." -1. If using Xcode 15, embed each framework that was dragged in. Navigate to the +7. If using Xcode 15, embed each framework that was dragged in. Navigate to the target's _General_ settings and find _Frameworks, Libraries, & Embedded Content_. For each framework dragged in from the `Firebase.zip`, select **Embed & Sign**. This step will enable privacy manifests to be picked up by Xcode's tooling. -1. Add the `-ObjC` flag to **Other Linker Settings**: +8. Add the `-ObjC` flag to **Other Linker Settings**: a. In your project settings, open the **Settings** panel for your target. @@ -58,7 +58,7 @@ To integrate a Firebase SDK with your app: c. Double-click the setting, click the '+' button, and add `-ObjC` -1. Add the `-lc++` flag to **Other Linker Settings**: +9. Add the `-lc++` flag to **Other Linker Settings**: a. In your project settings, open the **Settings** panel for your target. @@ -67,13 +67,13 @@ To integrate a Firebase SDK with your app: c. Double-click the setting, click the '+' button, and add `-lc++` -1. Drag the `Firebase.h` header in this directory into your project. This will +10. 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. -1. Drag `module.modulemap` into your project and update the +11. 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. -1. If your app does not include any Swift implementation, you may need to add +12. 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 +81,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**. -1. You're done! Build your target and start using Firebase. +13. 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