ionic-team / trapeze

The mobile project configuration toolbox. Manage native iOS, Android, Ionic/Capacitor, React Native, and Flutter apps through a simple YAML format.
https://trapeze.dev
Other
323 stars 40 forks source link

feat(ios): spm package support #176

Open rigor789 opened 1 year ago

rigor789 commented 1 year ago

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 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 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:

Additional features to consider:

ref https://github.com/ionic-team/trapeze/issues/130

vercel[bot] commented 1 year ago

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 commented 1 year ago

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

mlynch commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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

rigor789 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 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 commented 1 year ago

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.