Skip to content

Added support for swift package dependencies with expo-target config#122

Closed
Warabi1915181 wants to merge 1 commit intoEvanBacon:mainfrom
Warabi1915181:main
Closed

Added support for swift package dependencies with expo-target config#122
Warabi1915181 wants to merge 1 commit intoEvanBacon:mainfrom
Warabi1915181:main

Conversation

@Warabi1915181
Copy link
Copy Markdown

@Warabi1915181 Warabi1915181 commented Jun 19, 2025

Motivation

Currently we can only add swift packages inside Xcode. However, we need to manually do so after each expo prebuild --clean. While Expo and React Native seem to be adding support to add SPM support in the near future, we still need a way to optionally add it to different apple targets.

Execution

Pull request #44 is a promising contribution. It added integration with the swift package methods from the @bacons/xcode parser. However, it is lacking some of the version patterns that Xcode supports. It is also outdated with unresolved conflicts and a bug where a XCRemoteSwiftPackageReference is created regardless the package already exists or not. This pull request aims to solve all these issues.

Test Plan

Test Procedure

Create a new expo project npx create-expo-app@latest.

Install the forked apple-targets script. Since I did not upload my forked version, I build it locally and link it with npm link.

Create a new apple target (say, watch) using npx create-target watch.

In targets/watch/expo-target.config.js, add theswiftPackages. Here, we use the Firebase iOS SDK (Swift) library as an example, as well as demonstrating the ability to add multiple products from the same package (FirebaseAuth and FirebaseCore are two product dependencies from firebase-ios-sdk package).

/** @type {import('@bacons/apple-targets/app.plugin').ConfigFunction} */
module.exports = config => ({
  // existing default configs ...
  frameworks: ["SwiftUI"],
  swiftPackages: [
    {
      name: "FirebaseAuth",
      repositoryURL: "https://github.com/firebase/firebase-ios-sdk",
      kind: "upToNextMajorVersion",
      minimumVersion: "11.14.0",
    },
    {
      name: "FirebaseCore",
      repositoryURL: "https://github.com/firebase/firebase-ios-sdk",
      kind: "upToNextMajorVersion",
      minimumVersion: "11.14.0",
    }
  ]
});

Note

One important note is that the frameworks array cannot be empty or undefined. When framework is empty, there is no longer a build phase for frameworks, which causes xcode failing to import the swift packages. I personally think it is neither a bug in this plugin config nor the xcode parser, because this behaviour is the same when we add a swift package to a project target without framework inside xcode -- it will not automatically create a build phase and link the swift packages. However, unlike xcode users who can easily add the build phase and link the libraries, Expo users may expect to handle all these automatically via a plugin config. This feels like a design choice so I would keep it minimal and decide not to fix this in this PR, although this problem is tightly coupled with the feature of this PR.

Then run npx expo prebuild -p ios --clean. Wait for the prebuild to finish. Run xed ios to open up the project in Xcode.

Now you can see the Swift package dependencies are added to the project and the target.
CleanShot 2025-06-19 at 22 50 29@2x

A more rigorous test can be done by comparing the .pbxproj file from adding swift package inside XCode, and the file generated from this Expo config plugin.

if (!existingProductDependency) {
const packageProduct = XCSwiftPackageProductDependency.create(project, {
productName: name,
package: reference.uuid as unknown as XCRemoteSwiftPackageReference, // in Xcode 16, this should be the UUID of the reference, not the whole object
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wanted to flag, this changeset works great for my need (similarly need to pull in an SPM package into an Apple Target).

However, I am using Xcode 26 (with the latest 26.2+ Tahoe MacOS) and this flag here seems to encounter an error. This might be valid for Xcode 16 (I have not tested) but it might have gone back to "normal" in Xcode 26 - getting these errors (note, I injected some logs to debug).

[DEBUGGER] Replacing TargetName.entitlements with entitlements JSON from config
configureTargetWithSwiftPackages target PBXNativeTarget {
  uuid: 'XXDDCEB16C218EC8877E08XX',
  props: {
    isa: 'PBXNativeTarget',
    buildPhases: [],
    buildRules: [],
    dependencies: [],
    buildConfigurationList: XCConfigurationList {
      uuid: 'XXBAF26C8423445623FD65XX',
      props: [Object]
    },
    name: 'TargetName',
    productName: 'ProductName',
    productReference: PBXFileReference {
      uuid: 'XX0AB0FD90B6C986171471XX',
      props: [Object]
    },
    productType: 'com.apple.product-type.app-extension'
  }
}
configureTargetWithSwiftPackages props.swiftPackages?.forEach((pkg) => { {
  name: 'PackageName',
  repositoryURL: 'https://github.com/path/to.git',
  kind: 'branch',
  branch: 'main'
}
configureTargetWithSwiftPackages name PackageName
configureTargetWithSwiftPackages repositoryURL https://github.com/path/to.git
configureTargetWithSwiftPackages requirement { kind: 'branch', branch: 'main' }
configureTargetWithSwiftPackages reference not found, creating new one
configureTargetWithSwiftPackages project.rootObject.props.packageReferences not found, creating new one
configureTargetWithSwiftPackages existingProductDependency not found, creating new one
configureTargetWithSwiftPackages target.props.packageProductDependencies not found, creating new one
✖ Prebuild failed
Error: [ios.xcodeProjectBeta2]: withIosXcodeProjectBeta2BaseMod: Unable to serialize object: 'XX0514057567EC4CA0096CXX'
Error: [ios.xcodeProjectBeta2]: withIosXcodeProjectBeta2BaseMod: Unable to serialize object: 'XX0514057567EC4CA0096CXX'
    at XCSwiftPackageProductDependency.toJSON (/Users/user/Desktop/project/node_modules/@bacons/xcode/src/api/AbstractObject.ts:203:17)
    at XcodeProject.toJSON (/Users/user/Desktop/project/node_modules/@bacons/xcode/src/api/XcodeProject.ts:564:32)
    at write (/Users/user/Desktop/project/node_modules/@bacons/apple-targets/build/with-bacons-xcode.js:71:66)
    at action (/Users/user/Desktop/project/node_modules/@expo/config-plugins/src/plugins/createBaseMod.ts:90:17)
    at async interceptingMod (/Users/user/Desktop/project/node_modules/@expo/config-plugins/src/plugins/withMod.ts:109:21)
    at async evalModsAsync (/Users/user/Desktop/project/node_modules/@expo/config-plugins/src/plugins/mod-compiler.ts:190:25)
    at async compileModsAsync (/Users/user/Desktop/project/node_modules/@expo/config-plugins/src/plugins/mod-compiler.ts:83:10)
    at async configureProjectAsync (/Users/user/Desktop/project/node_modules/@expo/cli/build/src/prebuild/configureProjectAsync.js:92:14)
    at async prebuildAsync (/Users/user/Desktop/project/node_modules/@expo/cli/build/src/prebuild/prebuildAsync.js:164:9)

The errors go away and the plugin changes run w/o issue if I make this:

package: reference

instead of

package: reference.uuid

as you have it.

@wodin
Copy link
Copy Markdown

wodin commented Mar 2, 2026

See also #177

@Warabi1915181
Copy link
Copy Markdown
Author

When I drafted the PR last year, I wanted to add basic support for SPM quickly so that people can start using it immediately. It is definitely in an immature state and I agree with EvanBacon that SPM should be handled with another config plugin. As the PR #177 to include @bacons/spm has been finally created, I think this PR is no longer needed.

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.

3 participants