Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ios): spm package support #176

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

rigor789
Copy link

@rigor789 rigor789 commented Mar 21, 2023

This is a stab at implementing iOS SwiftPackageManager (SPM) package support.

To properly support SPM packages - they need to be added to the pbxproj directly. The necessary additions were based on what XCode does when adding a new SPM package.

Example diff after adding a package via XCode

diff --git a/platforms/ios/spmtesting.xcodeproj/project.pbxproj b/platforms/ios/spmtesting.xcodeproj/project.pbxproj
index befb7bf..bb37423 100644
--- a/platforms/ios/spmtesting.xcodeproj/project.pbxproj
+++ b/platforms/ios/spmtesting.xcodeproj/project.pbxproj
@@ -17,6 +17,7 @@
 		7661E5843BCA4E5180FBFEE7 /* TNSWidgets.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD2B025F6FED4323A2D8A507 /* TNSWidgets.xcframework */; };
 		79EF994730C54530A4E53CE3 /* build.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 7411B9B261764713BB9736E2 /* build.xcconfig */; };
 		858B842D18CA22B800AB12DE /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 858B833A18CA111C00AB12DE /* InfoPlist.strings */; };
+		9160D19829B2857400DDB6B5 /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = 9160D19729B2857400DDB6B5 /* Numerics */; };
 		CD45EE7C18DC2D5800FB50C0 /* app in Resources */ = {isa = PBXBuildFile; fileRef = CD45EE7A18DC2D5800FB50C0 /* app */; };
 		CD62955D1BB2678900AE3A93 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = CD62955C1BB2678900AE3A93 /* main.m */; };
 		F42CA19633A246F4B89CE99C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DF6330DE9BEE46F2BDB01AFE /* LaunchScreen.storyboard */; };
@@ -79,6 +80,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				9160D19829B2857400DDB6B5 /* Numerics in Frameworks */,
 				7661E5843BCA4E5180FBFEE7 /* TNSWidgets.xcframework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -217,6 +219,9 @@
 			dependencies = (
 			);
 			name = spmtesting;
+			packageProductDependencies = (
+				9160D19729B2857400DDB6B5 /* Numerics */,
+			);
 			productName = JDBridgeApp;
 			productReference = 858B843318CA22B800AB12DE /* spmtesting.app */;
 			productType = "com.apple.product-type.application";
@@ -245,6 +250,9 @@
 				Base,
 			);
 			mainGroup = 858B832518CA111C00AB12DE;
+			packageReferences = (
+				9160D19629B2857400DDB6B5 /* XCRemoteSwiftPackageReference "swift-numerics" */,
+			);
 			productRefGroup = 858B832F18CA111C00AB12DE /* Products */;
 			projectDirPath = "";
 			projectRoot = "";
@@ -553,6 +561,25 @@
 			defaultConfigurationName = Release;
 		};
 /* End XCConfigurationList section */
+
+/* Begin XCRemoteSwiftPackageReference section */
+		9160D19629B2857400DDB6B5 /* XCRemoteSwiftPackageReference "swift-numerics" */ = {
+			isa = XCRemoteSwiftPackageReference;
+			repositoryURL = "https://github.com/apple/swift-numerics.git";
+			requirement = {
+				kind = upToNextMajorVersion;
+				minimumVersion = 1.0.0;
+			};
+		};
+/* End XCRemoteSwiftPackageReference section */
+
+/* Begin XCSwiftPackageProductDependency section */
+		9160D19729B2857400DDB6B5 /* Numerics */ = {
+			isa = XCSwiftPackageProductDependency;
+			package = 9160D19629B2857400DDB6B5 /* XCRemoteSwiftPackageReference "swift-numerics" */;
+			productName = Numerics;
+		};
+/* End XCSwiftPackageProductDependency section */
 	};
 	rootObject = 858B832618CA111C00AB12DE /* Project object */;
 }

I've decided to implement the details in a separate file to keep it fairly self-contained, however I'm happy to refactor if a different style is preferred.

Most changes required directly editing the pbx data structures, as these are not implemented/covered by the xcode package (https://github.com/apache/cordova-node-xcode). For example, SPM has a new type of BuildFile that uses a producRef. Some of these changes could alternatively be implemented in the xcode package directly.

Example usage:

await project.ios?.addSPMPackage('App', {
  name: 'swift-numerics',
  libs: ['Numerics'],
  repositoryURL: 'https://github.com/apple/swift-numerics.git',
  version: '1.0.0'
})

// local SPM packages
await project.ios?.addSPMPackage('App', {
  name: 'local-swift-numerics',
  libs: ['LocalNumerics'],
  path: 'path/to/package',
})
Diff after running the above

diff --git a/platforms/ios/spmtesting.xcodeproj/project.pbxproj b/platforms/ios/spmtesting.xcodeproj/project.pbxproj
index befb7bf..c7d94d5 100644
--- a/platforms/ios/spmtesting.xcodeproj/project.pbxproj
+++ b/platforms/ios/spmtesting.xcodeproj/project.pbxproj
@@ -20,6 +20,7 @@
 		CD45EE7C18DC2D5800FB50C0 /* app in Resources */ = {isa = PBXBuildFile; fileRef = CD45EE7A18DC2D5800FB50C0 /* app */; };
 		CD62955D1BB2678900AE3A93 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = CD62955C1BB2678900AE3A93 /* main.m */; };
 		F42CA19633A246F4B89CE99C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DF6330DE9BEE46F2BDB01AFE /* LaunchScreen.storyboard */; };
+		FB5FF72957114376A4D3FBAD /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = F9982C4368B241CAAAC8A80B /* Numerics */; };
 /* End PBXBuildFile section */

 /* Begin PBXCopyFilesBuildPhase section */
@@ -80,6 +81,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				7661E5843BCA4E5180FBFEE7 /* TNSWidgets.xcframework in Frameworks */,
+				FB5FF72957114376A4D3FBAD /* Numerics in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -220,6 +222,9 @@
 			productName = JDBridgeApp;
 			productReference = 858B843318CA22B800AB12DE /* spmtesting.app */;
 			productType = "com.apple.product-type.application";
+			packageProductDependencies = (
+				F9982C4368B241CAAAC8A80B /* Numerics */,
+			);
 		};
 /* End PBXNativeTarget section */

@@ -251,6 +256,9 @@
 			targets = (
 				858B83EF18CA22B800AB12DE /* spmtesting */,
 			);
+			packageReferences = (
+				BA3D72BD1B4C400DB16DECFA /* XCRemoteSwiftPackageReference "swift-numerics" */,
+			);
 		};
 /* End PBXProject section */

@@ -553,6 +561,25 @@
 			defaultConfigurationName = Release;
 		};
 /* End XCConfigurationList section */
+
+/* Begin XCRemoteSwiftPackageReference section */
+		BA3D72BD1B4C400DB16DECFA /* XCRemoteSwiftPackageReference "swift-numerics" */ = {
+			isa = XCRemoteSwiftPackageReference;
+			repositoryURL = "https://github.com/apple/swift-numerics.git";
+			requirement = {
+				kind = upToNextMajorVersion;
+				minimumVersion = 1.0.0;
+			};
+		};
+/* End XCRemoteSwiftPackageReference section */
+
+/* Begin XCSwiftPackageProductDependency section */
+		F9982C4368B241CAAAC8A80B /* Numerics */ = {
+			isa = XCSwiftPackageProductDependency;
+			package = BA3D72BD1B4C400DB16DECFA /* XCRemoteSwiftPackageReference "swift-numerics" */;
+			productName = Numerics;
+		};
+/* End XCSwiftPackageProductDependency section */
 	};
 	rootObject = 858B832618CA111C00AB12DE /* Project object */;
 }

General notes about using SPM packages:

  • after adding an spm package - they need to be resolved before building via xcodebuild. For example: xcodebuild -resolvePackageDependencies will download/resolve the newly added packages.
  • building projects with SPM packages always needs to be done via the xcodebuild -scheme rather than -target

Additional features to consider:

  • Implementing version ranges (currently only supporting minimum + upToNextMajorVersion)

ref #130

@vercel
Copy link

vercel bot commented Mar 21, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
trapeze ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 20, 2023 5:01pm

@mlynch
Copy link
Contributor

mlynch commented Mar 22, 2023

Nice, thanks for the contribution! Will take a look soon

@mlynch
Copy link
Contributor

mlynch commented Mar 22, 2023

First pass looks good to me. The SPMHelper I didn't see why it needed to be a class instead of just a few functions in that file but not a big deal. Any thoughts on what the configure operation would look like? Thanks for doing this!

@rigor789
Copy link
Author

First pass looks good to me. The SPMHelper I didn't see why it needed to be a class instead of just a few functions in that file but not a big deal. Any thoughts on what the configure operation would look like? Thanks for doing this!

It can go either way - really just wanted to save having to type/pass in the pbxProject instance to every helper call, and instead I'm passing that in the SPMHelper constructor once.

For the configure operation, perhaps something like this would work nicely?

platforms:
  ios:
    targets:
      App:
        spmPackages:
          - name: "swift-numerics"
            libs: [ "Numerics" ]
            repositoryURL: "https://github.com/apple/swift-numerics.git"
            version: "1.0.0"

@mlynch
Copy link
Contributor

mlynch commented Apr 3, 2023

@rigor789 apologies, forgot to respond. That looks good!

@rigor789
Copy link
Author

rigor789 commented Apr 3, 2023

No worries, I'll look at adding the configure operation like that. And just a note, we're test driving these changes against real projects, so will adjust anything as needed if we run into anything odd (though so far, it's bee working great!)

@rigor789
Copy link
Author

Update: added support for local SPM packages.

For local packages, the definition requires the package name, libs and a path, for example:

// local SPM packages
await project.ios?.addSPMPackage('App', {
  name: 'local-swift-numerics',
  libs: ['LocalNumerics'],
  path: 'path/to/package',
})

PS.: I will be looking at implementing the configure operations next.

@rigor789
Copy link
Author

Update:

Added the configure operation, for example test.yml:

platforms:
  ios:
    version: 16.4
    targets:
      App:
        spmPackages:
          - name: "swift-numerics"
            libs: [ "Numerics" ]
            repositoryURL: "https://github.com/apple/swift-numerics.git"
            version: "1.0.0"
          - name: "local-swift-numerics"
            libs: [ "ComplexModule", "RealModule" ]
            path: "../path/to/local-swift-numerics"

image

Diff after running the above operation

diff --git a/packages/common/test/fixtures/ios-and-android/ios/App/App.xcodeproj/project.pbxproj b/packages/common/test/fixtures/ios-and-android/ios/App/App.xcodeproj/project.pbxproj
index 5928a9c..f0d9623 100644
--- a/packages/common/test/fixtures/ios-and-android/ios/App/App.xcodeproj/project.pbxproj
+++ b/packages/common/test/fixtures/ios-and-android/ios/App/App.xcodeproj/project.pbxproj
@@ -28,6 +28,9 @@
                507D3D05271DC2D000EEA707 /* My Share Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 507D3CFB271DC2D000EEA707 /* My Share Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
                50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; };
                A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; };
+               6457BCEED2DC47EDBF855E6E /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = 483ED33D8EA44A62977EF3A4 /* Numerics */; };
+               CBB5D9DA80524BD886CE16B9 /* ComplexModule in Frameworks */ = {isa = PBXBuildFile; productRef = EFED82049B0144B7B4441595 /* ComplexModule */; };
+               487C691400984C4C939C59A9 /* RealModule in Frameworks */ = {isa = PBXBuildFile; productRef = 0933A1A614C64F4884E6F617 /* RealModule */; };
 /* End PBXBuildFile section */

 /* Begin PBXContainerItemProxy section */
@@ -127,6 +130,9 @@
                        buildActionMask = 2147483647;
                        files = (
                                A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */,
+                               6457BCEED2DC47EDBF855E6E /* Numerics in Frameworks */,
+                               CBB5D9DA80524BD886CE16B9 /* ComplexModule in Frameworks */,
+                               487C691400984C4C939C59A9 /* RealModule in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
@@ -287,6 +293,11 @@
                        productName = App;
                        productReference = 504EC3041FED79650016851F /* Awesome App.app */;
                        productType = "com.apple.product-type.application";
+                       packageProductDependencies = (
+                               483ED33D8EA44A62977EF3A4 /* Numerics */,
+                               EFED82049B0144B7B4441595 /* ComplexModule */,
+                               0933A1A614C64F4884E6F617 /* RealModule */,
+                       );
                };
                507D3CC1271DC20100EEA707 /* My App Clip */ = {
                        isa = PBXNativeTarget;
@@ -411,6 +422,10 @@
                                507D3CE1271DC20300EEA707 /* My App ClipUITests */,
                                507D3CFA271DC2D000EEA707 /* My Share Extension */,
                        );
+                       packageReferences = (
+                               EBF7078813744D8DB3856886 /* XCRemoteSwiftPackageReference "swift-numerics" */,
+                               E4715DA7E0374B379A8EE091 /* XCLocalSwiftPackageReference "../path/to/local-swift-numerics" */,
+                       );
                };
 /* End PBXProject section */

@@ -1065,6 +1080,42 @@
                        defaultConfigurationName = Release;
                };
 /* End XCConfigurationList section */
+
+/* Begin XCRemoteSwiftPackageReference section */
+               EBF7078813744D8DB3856886 /* XCRemoteSwiftPackageReference "swift-numerics" */ = {
+                       isa = XCRemoteSwiftPackageReference;
+                       repositoryURL = "https://github.com/apple/swift-numerics.git";
+                       requirement = {
+                               kind = upToNextMajorVersion;
+                               minimumVersion = 1.0.0;
+                       };
+               };
+/* End XCRemoteSwiftPackageReference section */
diff --git a/packages/common/test/fixtures/ios-and-android/ios/App/App.xcodeproj/project.pbxproj b/packages/common/test/fixtures/ios-and-android/ios/App/App.xcodeproj/project.pbxproj
index 5928a9c..f0d9623 100644
--- a/packages/common/test/fixtures/ios-and-android/ios/App/App.xcodeproj/project.pbxproj
+++ b/packages/common/test/fixtures/ios-and-android/ios/App/App.xcodeproj/project.pbxproj
@@ -28,6 +28,9 @@
                507D3D05271DC2D000EEA707 /* My Share Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 507D3CFB271DC2D000EEA707 /* My Share Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
                50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; };
                A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; };
+               6457BCEED2DC47EDBF855E6E /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = 483ED33D8EA44A62977EF3A4 /* Numerics */; };
+               CBB5D9DA80524BD886CE16B9 /* ComplexModule in Frameworks */ = {isa = PBXBuildFile; productRef = EFED82049B0144B7B4441595 /* ComplexModule */; };
+               487C691400984C4C939C59A9 /* RealModule in Frameworks */ = {isa = PBXBuildFile; productRef = 0933A1A614C64F4884E6F617 /* RealModule */; };
 /* End PBXBuildFile section */

 /* Begin PBXContainerItemProxy section */
@@ -127,6 +130,9 @@
                        buildActionMask = 2147483647;
                        files = (
                                A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */,
+                               6457BCEED2DC47EDBF855E6E /* Numerics in Frameworks */,
+                               CBB5D9DA80524BD886CE16B9 /* ComplexModule in Frameworks */,
+                               487C691400984C4C939C59A9 /* RealModule in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
@@ -287,6 +293,11 @@
                        productName = App;
                        productReference = 504EC3041FED79650016851F /* Awesome App.app */;
                        productType = "com.apple.product-type.application";
+                       packageProductDependencies = (
+                               483ED33D8EA44A62977EF3A4 /* Numerics */,
+                               EFED82049B0144B7B4441595 /* ComplexModule */,
+                               0933A1A614C64F4884E6F617 /* RealModule */,
+                       );
                };
                507D3CC1271DC20100EEA707 /* My App Clip */ = {
                        isa = PBXNativeTarget;
@@ -411,6 +422,10 @@
                                507D3CE1271DC20300EEA707 /* My App ClipUITests */,
                                507D3CFA271DC2D000EEA707 /* My Share Extension */,
                        );
+                       packageReferences = (
+                               EBF7078813744D8DB3856886 /* XCRemoteSwiftPackageReference "swift-numerics" */,
+                               E4715DA7E0374B379A8EE091 /* XCLocalSwiftPackageReference "../path/to/local-swift-numerics" */,
+                       );
                };
 /* End PBXProject section */

@@ -1065,6 +1080,42 @@
                        defaultConfigurationName = Release;
                };
 /* End XCConfigurationList section */
+
+/* Begin XCRemoteSwiftPackageReference section */
+               EBF7078813744D8DB3856886 /* XCRemoteSwiftPackageReference "swift-numerics" */ = {
+                       isa = XCRemoteSwiftPackageReference;
+                       repositoryURL = "https://github.com/apple/swift-numerics.git";
+                       requirement = {
+                               kind = upToNextMajorVersion;
+                               minimumVersion = 1.0.0;
+                       };
+               };
+/* End XCRemoteSwiftPackageReference section */
+
+/* Begin XCSwiftPackageProductDependency section */
+               483ED33D8EA44A62977EF3A4 /* Numerics */ = {
+                       isa = XCSwiftPackageProductDependency;
+                       package = EBF7078813744D8DB3856886 /* XCRemoteSwiftPackageReference "swift-numerics" */;
+                       productName = Numerics;
+               };
+               EFED82049B0144B7B4441595 /* ComplexModule */ = {
+                       isa = XCSwiftPackageProductDependency;
+                       package = E4715DA7E0374B379A8EE091 /* XCLocalSwiftPackageReference "../path/to/local-swift-numerics" */;
+                       productName = ComplexModule;
+               };
+               0933A1A614C64F4884E6F617 /* RealModule */ = {
+                       isa = XCSwiftPackageProductDependency;
+                       package = E4715DA7E0374B379A8EE091 /* XCLocalSwiftPackageReference "../path/to/local-swift-numerics" */;
+                       productName = RealModule;
+               };
+/* End XCSwiftPackageProductDependency section */
+
+/* Begin XCLocalSwiftPackageReference section */
+               E4715DA7E0374B379A8EE091 /* XCLocalSwiftPackageReference "../path/to/local-swift-numerics" */ = {
+                       isa = XCLocalSwiftPackageReference;
+                       relativePath = "../path/to/local-swift-numerics";
+               };
+/* End XCLocalSwiftPackageReference section */
        };
        rootObject = 504EC2FC1FED79650016851F /* Project object */;
 }

@rigor789
Copy link
Author

I believe this is ready for review @mlynch.

We haven't needed it yet, but perhaps in the future we could add a getSPMPackages api to list them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants