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

Add support for Swift Package Manager (SPM) as the dependency manager for iOS #587

Open
sja26 opened this issue Jan 24, 2023 · 40 comments
Open

Comments

@sja26
Copy link

sja26 commented Jan 24, 2023

Introduction

Deprecate Cocoapods as the dependency manager for iOS, and add support for Swift Package Manager (SPM) as its successor.

Details

There is growing evidence that SPM is on a trajectory to replace Cocoapods as the most popular dependency manager for iOS apps.

I surmise that Cocoapods, being the only option to integrate React Native into an iOS app, is preventing a significant and growing number of iOS developers from trying out React Native.

Some background:

  • Cocoapods was released in 2011 written in Ruby, it became the de facto dependency manager for iOS apps.
  • SPM was released as part of Swift 3.0 in 2016.

References:

Discussion points

Focusing on the data gathered by JetBrains' most recent annual survey for Swift and Objective-C developers in 2022. The results of 3 questions stand out as the main motivators to address the aforementioned trajectory of SPM.

Do you use Swift and Objective-C together in the same project?

  • 62% Yes, most of my codebase is in Swift
  • 23% Yes, most of my codebase is in Objective-C
  • 16% No

Which dependency manager do you use?

  • 61% CocoaPods
  • 47% Swift Package Manager
  • 18% None
  • 11% Carthage
  • 1% Other

Do you plan to replace CocoaPods dependencies with SPM packages?

  • 48% No, and I don’t plan to in the next 12 months
  • 28% Yes
  • 24% No, but I plan to in the next 12 months
@nplasterer
Copy link

Just wanted to add some support for this discussion. We've been running into a lot of issues with trying to create a react native bridge to iOS for a react native SDK. The main issue is that our iOS SDK cannot be made into a cocoapod as one of our dependencies has dropped cocoapod support entirely https://forums.swift.org/t/swiftnio-is-dropping-support-for-cocoapods/56840. This has made it impossible for us to offer our integrators a RN SDK.

@cipolleschi
Copy link

Hi @sja26 and @nplasterer. Thank you for starting this proposal, it is very valuable indeed.

Swift Package Manager is something we are looking into as well, but currently it is not a feasible path for us.

The major blocker for this effort is that SPM, right now, does not support packages with mixed languages. A package in SPM must be only in Swift, Objective-C or C++. Whenever you try to mix them, SPM raises an error.

Other blockers:

  • we are using Cocoapods also to run some scripts that prepares the project properly (setting the right flags) and that run Codegen.
    • Mitigation: both problems could be mitigated with the new Swift Plugins, but they are still in an unstable state (e.g.: it is not easy to integrate them with an App, see here, for example).
  • the current structure of React Native does not work well with the structure suggested by SPM.
    • Mitigation: refactoring React Native and using the various SPM property in more advanced ways.

I would love to support you if you want to make some experiment with SPM to see how far you can go. I tried a couple of times in the past with not a lot of success, but I'm periodically try this path again because, as you, I also think that we should move to SPM at some point in the future.

@sja26
Copy link
Author

sja26 commented Apr 12, 2023

Hi @cipolleschi, thank you for the summary.

Regarding the major blocker:

A package in SPM must be only in Swift, Objective-C or C++. Whenever you try to mix them, SPM raises an error.

Yes, but only if you want the package to include the source code. If not including the source code is acceptable then a binary framework can be distributed as a Swift package, which can be accomplished in two phases:

  1. Creating an XCFramework
    Creating a multiplatform binary framework bundle (Apple Developer Article)
    Binary Frameworks in Swift (WWDC19)
  2. Distributing as a Swift Package
    Distribute binary frameworks as Swift packages (Apple Developer Article)
    Distribute binary frameworks as Swift packages (WWDC20)

There are trade-offs when using binary frameworks as explained in the above resources, therefore this could be seen as an interim solution until SPM evolves to meet your original desire to include the source code in the Swift package.

we are using Cocoapods also to run some scripts that prepares the project properly (setting the right flags) and that run Codegen.

I wonder if using Gradle could be a suitable replacement see Building Swift projects?

the current structure of React Native does not work well with the structure suggested by SPM.

Could you elaborate further with an example please?

Fingers crossed WWDC23 will deliver more SPM improvements.

@cipolleschi
Copy link

If not including the source code is acceptable then a binary framework can be distributed as a Swift package.

@sja26 currently, React Native can't be really built as an isolated framework. 😅 The technical detail here is that the App is responsible to generate the code of Codegen, so that code won't be available in advance so that we can prepare a framework with it.
So the idea of shipping it as an XCFramework is not feasible as well. 😞

Also, I feel that being able to step into the React Native code is extremely useful for contributors that have to debug their libraries. We would like to keep this option open in the foreseeable future.

I wonder if using Gradle could be a suitable replacement see Building Swift projects?

Second problem, React Native internals can not be implemented in Swift. The core engine of React Native is in C++ and there is not full interoperability between Swift and C++. We should pass through Objective-C++, but the extra layer could have some performance implication (that we still have to test, thought) but that, so far, we haven't had time to explore. So, currently, we can't use Gradle to build Swift projects. However, it looks interesting and it could be interesting to use the same tooling for both Android and iOS.

Could you elaborate further with an example please?

React Native is structured as it follows (simplifying it):

  • React (with iOS code)
  • ReactCommon (with C++ code)

Within those folders, there are subfolders which are separated modules.
In some of those subfolders, there are folders called platform that contains ios, android and cxx folders for the specific platforms.

A simple difference between the structure suggested by SPM and our current structure is the absence of the Sources and Tests folders, for example. Also, we have nested folders that should be extracted in their own packages.

I'm not saying that it is not doable, but currently, this work will require a lot of effort and it will break several things also internally at Meta.

@chuckluck44
Copy link

chuckluck44 commented May 9, 2023

@cipolleschi For clarification Swift Packages do support mixed languages without use of frameworks. The only requirement is that Swift and any C family languages be separated into their own folders/targets, but they ship as one product and the code can be stepped through normally.

Our own SDK is shipped as a swift package that uses a mix of swift, C, and C++. Swift is able to call C++ by wrapping calls in a C header in the c++ target, but Swift/C++ interoperability is also in the works https://github.com/apple/swift/tree/main/docs/CppInteroperability . You also have the option of creating a package completely in obj-c, c, and/or c++ (c++ requires a c or objc wrapper at the moment). In that case everything could be contained in a single target.

Regarding the folder structure issues, symlinks may work as a temporary fix. This is the approach we took when initially moving from an xcframework to swift package distribution. But that hasn't been tested in a while.

I understand this is a pretty large undertaking. There just isn't much of reason for newer iOS sdks to support CocoaPods st this point since SPM ships with xcode, can work in conjunction with both Carthage and CocoaPods (assuming there aren't any duplicated dependencies requirements across the graphs), and is much more tightly integrated with the ecosystem. Our SDK is only going to support cocoa pods because we have many integrators in our space that use react native and we need to distribute a node module, but other teams may just forgo supporting at all.

@cipolleschi
Copy link

@chuckluck44 I understand what you are saying. I completely agree that it is something important, but currently, we don't have much capacity to work on this, unfortunately.

The only requirement is that Swift and any C family languages be separated into their own folders/targets,

That's not the case, currently. For example, see the ImageManager. As you can see, in this folder we have a mixture of cpp and mm files. Restructuring the structure of the framework is a delicate task as React Native is also used internally, where we have yet another build system and dependency manager.
We need to make sure that all the changes we make for the OSS do not break the internal system and viceversa.

There just isn't much of reason for newer iOS sdks to support CocoaPods st this point since SPM ships with xcode, can work in conjunction with both Carthage and CocoaPods (assuming there aren't any duplicated dependencies requirements across the graphs), and is much more tightly integrated with the ecosystem. Our SDK is only going to support cocoa pods because we have many integrators in our space that use react native and we need to distribute a node module, but other teams may just forgo supporting at all.

I completely agree with this point, and we received the feedback also from other partners. The problem is slightly wider than this though.

We don't only use Cocoapods to install dependencies, but is also running some other tasks: it configures build flags to make sure that the project is properly configured and it runs some code generation tasks.
Of course, we can move both of these tasks to some script that SPM can invoke, especially now with the Xcode Plugins, but this is extra work that we need to plan for.

@chuckluck44
Copy link

chuckluck44 commented May 11, 2023

@cipolleschi Thanks for the quick response. So the ImageManager example would actually work with its current folder structure. As the SPM Docs mention, its only swift and C-family languages that need to be separated:

Targets can contain Swift, Objective-C/C++, or C/C++ code, but an individual target can’t mix Swift with C-family languages. For example, a Swift package can have two targets, one that contains Objective-C, Objective-C++, and C code, and a second one that contains Swift code.

That being said, I have total respect for your teams current situation. Folder structure is obviously just a single aspect of migrating a project of this size/complexity. I only wanted to surface the fact that a majority of your mixed language issues may not be a problem anymore.

@cipolleschi
Copy link

@chuckluck44 Thank you for your suggestion and understanding. Improving the setup is on our radar. We really hope we would be able to prioritize it soon!

@ScottRobbins
Copy link

Fwiw, there is an open proposal about mixed language support here.

I suspect not much will gain traction for SPM until the fall, but it may be worth the RN team to review if this would achieve what they need when time allows.

@cipolleschi
Copy link

Thanks for the link! Will take a look as soon as I can!

@mfazekas
Copy link

mfazekas commented Oct 26, 2023

FWIW there is an RFC to Cocapods repo to support SPM via cocoa pods.

See CocoaPods/CocoaPods#11942 and related PR: CocoaPods/Core#743

@cipolleschi
Copy link

FWIW there is an RFC to Cocapods repo to support SPM via cocoa pods.

See CocoaPods/CocoaPods#11942 and related PR: CocoaPods/Core#743

Interesting, in this way we can start migrate our packages toward SPM incrementally.
One of the major limitation currently is that SPM does not allow to run preprocess commands. We need to run some preprocessing on pure C++ packages like Glog to make sure they are compatible with iOS, and so far that's not possible. But with this PR we can start migrating the React packages and live in a mixed world.

Unfortunately, we currently don't have bandwidth to work on this, but we know we will have to work on Swift support and SPM sometime soon.

Thanks for signalling this.

@chrisaljoudi
Copy link

What's the latest on this? Would be a pretty big win, Cocoapods is sadly one of the least ergonomic aspects of React Native development.

@cipolleschi
Copy link

No news so far. I do understand that it's a bit of a pain. It is a pain for us internally as well. Unfortunately, we don't have the resources to prioritize this work at the moment: our current priority is to ship the New Architecture to the OSS and we are hyperfocused on that.

Rolling out the New Architecture and deprecating the old one could also help us reducing the surface that cocoapods/SPM needs to cover, ultimately simplifying the work to convert Cocoapods to SPM.

We are also wait for some official support from Appe to run some custom code after a package is downloaded: we are currently adjusting some packaged (Folly and boost, for example) right after they are downloaded.
Cocoapods makes it very easy with prepare_commands.
SPM does not have anything similar. Yes, there are Build Plugins and I have experimented a bit with them. They might partially solve the problem, but the approach needs deeper testing and experimentation.

@wuguishifu
Copy link

Is there any temporary workaround for TPLs that only support SPM and don't have Pod support for latest versions of Swift? I'm trying to use AudioKit, but its Pod version is way out of date. Is there a way to manually compile and inject them?

@tsapeta
Copy link

tsapeta commented May 14, 2024

@wuguishifu In theory you should be able to fork it and publish to CocoaPods on your own or pull in this code into your library codebase (in accordance with the license of course).
The third option that comes to my mind is to make a local podspec and use GitHub as the source, i.e. combination of :podspec and :git params of the pod function (see the last section in the Podfile Syntax Reference). It's probably the best way, if only it works, I've never tried that 😅

@wuguishifu
Copy link

Thanks for the info! That sounds mostly doable. I'm pretty new to native iOS stuff (I've done mostly expo go and native android stuff) so I definitely appreciate the suggestions.

@mfazekas
Copy link

mfazekas commented May 17, 2024

I've added a POC of a library, that patches react-native so libraries can declare swift package manager dependencies.

See https://github.com/mfazekas/rn-spm-rfc-poc/

In this POC the library can define the swift package manager dependencies like this:

ReactNativePodsUtils.spm_dependency(s,  
     url: 'https://github.com/apple/swift-atomics.git', 
     requirement: {kind: 'upToNextMajorVersion', minimumVersion: '1.1.0'}, 
     products: ['Atomics'] 
   ) 

The changes to react-native are in this patch file:
https://github.com/mfazekas/rn-spm-rfc-poc/blob/main/example/patches/react-native%2B0.74.1.patch

This means that we'd still be using Cocoapods, but we'd allow rn-libraries to declare their swift package manager dependencies.

Added a separate RFC: Declare swift package manager dependencies in react-native library podspec

@cipolleschi
Copy link

cipolleschi commented May 20, 2024

@mfazekas, the React Native patch here seems pretty harmless to me, if you can open a PR against core, I'd be happy to land it.
IIUC, the goal is to let a React Native library to depends on some packages that are exposed only through SPM, right?

For example:

  • Imagine that I have a library RNAlgorithms.
  • I want for this library to depend on swift-algorithms

Right now, there is no way to achieve this.

After the patch, there is.

Is my understanding correct?

@mfazekas
Copy link

@cipolleschi yes exactly that is the goal of the patch, I'll open a PR.

facebook-github-bot pushed a commit to facebook/react-native that referenced this issue Jun 25, 2024
…44627)

Summary:
React-Native uses Cocapods for native dependency management on iOS. While CocoaPods is flexible and popular, Apple's Swift Package Manager is the new standard. Currently consuming packages available only via Swift Package Manager is not possible. This change implements a single extension so .podspec files can declare Swift Package Manager dependencies via
```ruby
ReactNativePodsUtils.spm_dependency(s,
     url: 'https://github.com/apple/swift-atomics.git',
     requirement: {kind: 'upToNextMajorVersion', minimumVersion: '1.1.0'},
     products: ['Atomics']
   )
```

bypass-github-export-checks

## Changelog:

[IOS] [ADDED] - libraries can now declare Swift Package Manager dependencies in their .podspec with `ReactNativePodsUtils.spm_dependency`

Pull Request resolved: #44627

Test Plan:
https://github.com/mfazekas/rn-spm-rfc-poc/

Is a simple demo for the feature:

1. Podspec declare dependency with:

   ```ruby
   if const_defined?(:ReactNativePodsUtils) && ReactNativePodsUtils.respond_to?(:spm_dependency)
     ReactNativePodsUtils.spm_dependency(s,
       url: 'https://github.com/apple/swift-atomics.git',
       requirement: {kind: 'upToNextMajorVersion', minimumVersion: '1.1.0'},
       products: ['Atomics']
     )
   else
     raise "Please upgrade React Native to >=0.75.0 to use SPM dependencies."
   end
   ```

2. [`import Atomics`](https://github.com/mfazekas/rn-spm-rfc-poc/blob/e4eb1034f7498dedee4cb673d327c34a6048bda2/ios/MultiplyInSwift.swift#L1C2-L1C15) and [`ManagedAtomic`](https://github.com/mfazekas/rn-spm-rfc-poc/blob/e4eb1034f7498dedee4cb673d327c34a6048bda2/ios/MultiplyInSwift.swift#L7-L13) is used in the code

3.) `spm_dependency` causes the dependency to be added via `post_install` hook in the workspace

<img width="261" alt="image" src="https://github.com/facebook/react-native/assets/52435/ad6aee1c-ac88-4c84-8aa3-50e148c4f5b2">

4.) `spm_dependecy` causes the library to be linked with `Atomics` library

<img width="817" alt="image" src="https://github.com/facebook/react-native/assets/52435/bfc8dfc0-aeb7-4c75-acbd-937eab1cbf80">

Limitations:
1.) only works `USE_FRAMEWORKS=dynamic pod install` otherwise the linker fails [with known Xcode issue - duplicate link issue](https://forums.swift.org/t/objc-flag-causes-duplicate-symbols-with-swift-packages/27926)
2.) .xcworkspace needs to be reopened after `pod install` - this could be worked around by not removing/readding spm dependencies

### See also:

react-native-community/discussions-and-proposals#587 (comment)
react-native-community/discussions-and-proposals#787

Reviewed By: cortinico

Differential Revision: D58947066

Pulled By: cipolleschi

fbshipit-source-id: ae3bf955cd36a02cc78472595fa003cc9e843dd5
@robertjpayne
Copy link

robertjpayne commented Jun 30, 2024

FWIW there is an RFC to Cocapods repo to support SPM via cocoa pods.
See CocoaPods/CocoaPods#11942 and related PR: CocoaPods/Core#743

Interesting, in this way we can start migrate our packages toward SPM incrementally. One of the major limitation currently is that SPM does not allow to run preprocess commands. We need to run some preprocessing on pure C++ packages like Glog to make sure they are compatible with iOS, and so far that's not possible. But with this PR we can start migrating the React packages and live in a mixed world.

Unfortunately, we currently don't have bandwidth to work on this, but we know we will have to work on Swift support and SPM sometime soon.

Thanks for signalling this.

This is no longer true and hasn't been for a fair amount of time. SPM allows pre-build and build commands. Both are suitable for this sort of pre-build processing.

SPM has come a long ways in just a few short years, I'm currently exploring the feasibility of actually vending a fork that would be SPM compatible.

blakef pushed a commit to facebook/react-native that referenced this issue Jul 15, 2024
…44627)

Summary:
React-Native uses Cocapods for native dependency management on iOS. While CocoaPods is flexible and popular, Apple's Swift Package Manager is the new standard. Currently consuming packages available only via Swift Package Manager is not possible. This change implements a single extension so .podspec files can declare Swift Package Manager dependencies via
```ruby
ReactNativePodsUtils.spm_dependency(s,
     url: 'https://github.com/apple/swift-atomics.git',
     requirement: {kind: 'upToNextMajorVersion', minimumVersion: '1.1.0'},
     products: ['Atomics']
   )
```

bypass-github-export-checks

## Changelog:

[IOS] [ADDED] - libraries can now declare Swift Package Manager dependencies in their .podspec with `ReactNativePodsUtils.spm_dependency`

Pull Request resolved: #44627

Test Plan:
https://github.com/mfazekas/rn-spm-rfc-poc/

Is a simple demo for the feature:

1. Podspec declare dependency with:

   ```ruby
   if const_defined?(:ReactNativePodsUtils) && ReactNativePodsUtils.respond_to?(:spm_dependency)
     ReactNativePodsUtils.spm_dependency(s,
       url: 'https://github.com/apple/swift-atomics.git',
       requirement: {kind: 'upToNextMajorVersion', minimumVersion: '1.1.0'},
       products: ['Atomics']
     )
   else
     raise "Please upgrade React Native to >=0.75.0 to use SPM dependencies."
   end
   ```

2. [`import Atomics`](https://github.com/mfazekas/rn-spm-rfc-poc/blob/e4eb1034f7498dedee4cb673d327c34a6048bda2/ios/MultiplyInSwift.swift#L1C2-L1C15) and [`ManagedAtomic`](https://github.com/mfazekas/rn-spm-rfc-poc/blob/e4eb1034f7498dedee4cb673d327c34a6048bda2/ios/MultiplyInSwift.swift#L7-L13) is used in the code

3.) `spm_dependency` causes the dependency to be added via `post_install` hook in the workspace

<img width="261" alt="image" src="https://github.com/facebook/react-native/assets/52435/ad6aee1c-ac88-4c84-8aa3-50e148c4f5b2">

4.) `spm_dependecy` causes the library to be linked with `Atomics` library

<img width="817" alt="image" src="https://github.com/facebook/react-native/assets/52435/bfc8dfc0-aeb7-4c75-acbd-937eab1cbf80">

Limitations:
1.) only works `USE_FRAMEWORKS=dynamic pod install` otherwise the linker fails [with known Xcode issue - duplicate link issue](https://forums.swift.org/t/objc-flag-causes-duplicate-symbols-with-swift-packages/27926)
2.) .xcworkspace needs to be reopened after `pod install` - this could be worked around by not removing/readding spm dependencies

### See also:

react-native-community/discussions-and-proposals#587 (comment)
react-native-community/discussions-and-proposals#787

Reviewed By: cortinico

Differential Revision: D58947066

Pulled By: cipolleschi

fbshipit-source-id: ae3bf955cd36a02cc78472595fa003cc9e843dd5
@mfazekas
Copy link

0.75-rc.6 does have facebook/react-native#44627 integrated now

@jpudysz
Copy link

jpudysz commented Jul 30, 2024

@mfazekas thank you for this PR, I used it with patch-package and v. 0.74. You are a hero!

@karlhorky
Copy link

Updates from @orta of the CocoaPods team:

TLDR: We're still keeping it ticking, but we're being more up-front that CocoaPods is in maintenance mode.

I use CocoaPods as a Hidden Abstraction in My Framework

E.g. I maintain Unity, React Native, Flutter etc. A lot of these projects will (and should) be migrating to Swift Package Manager with time.

Sources:

@cipolleschi
Copy link

@karlhorky thanks for flagging it. We were aware of that, we had been informed already.
I'll try to push some work on this, but that's not going to happen in the next months. If this happens, it will be probably next year.

@aslattum
Copy link

@mfazekas how would we go about using #787 in a react native expo app so I can pull in swift package dependencies? I've tried it out a couple times, but it says that its not available.

@cipolleschi
Copy link

@aslattum first of all, which expo SDK are you using? We introduced this feature in 0.75, so you need an SDK that supports that.
Secondly, the feature only works with dynamic frameworks, so make sure to install your pods with:

USE_FRAMEWORKS=dynamic bundle exec pod install

@aslattum
Copy link

@cipolleschi thanks for the quick reply, so I can actually see and execute the function from looking in node modules; however, I wasn't doing USE_FRAMEWORKS=dynamic bundle exec pod install. Do you know the best way to wire that up with expo? I couldn't even find where the pod install is happening although I know its happening during npx expo prebuild

@cipolleschi
Copy link

one way would be to modify the Podfile in your ios folder (I think it should be possible to use a config plugin for that) and add

ENV["USE_FRAMEWORKS"] = "dynamic"

at the top of the Podfile file. This will work in the same way as calling USE_FRAMEWORKS=dynamic bundle exec pod install

@aslattum
Copy link

@cipolleschi yeah that makes sense and I could do that; however, I'm working on creating a expo native module and the user of the module should only have to touch the javascript portion of the package. So I definitely can modify the Podfile to get it working, but that won't work on install of the package itself by a consumer.

Seems like I should try to find a config plugin to do it on generation then 👍🏻

@jpudysz
Copy link

jpudysz commented Sep 17, 2024

There is already a plugin for that. Check documentation for expo-build-properties

@aslattum
Copy link

@jpudysz so I was able to use this. It seems like exactly what I want. The issue I'm running into is I'm trying to create a native expo module that will be used within another react native app so I would want run this plugin on install of the package. All of the examples online show adding the config to the example project in the plugin, not at the root of the package. Any suggestions here?

@jpudysz
Copy link

jpudysz commented Sep 17, 2024

Because main app decides how to build dependencies.

@aslattum
Copy link

aslattum commented Sep 17, 2024

@jpudysz yeah that makes sense. Basically what I'm trying is:

  1. Use native swift and kotlin libraries (which are private)
  2. Create a expo native module that essentially wraps these libraries with code that makes it accessible to react native
  3. Publish this expo native module so that it can be used directly by a react native app src code.

The part that is getting wonky is number 2. Any good suggestions for that?

@cipolleschi
Copy link

Do you have control over those two libraries? Because if that's the case, the best solution would be to add support for Cocoapods by writing a podspec.
Even if you don't have control over those, you can create a local podspec in your library and reference to that. We are doing the same thing in React Native for some libraries we need that are not exposed via cocoapods.

@aslattum
Copy link

@cipolleschi yeah we do have control over those libraries and I've written podspecs for them. The problem is we didn't want to push those podspecs to a public repository, but if we pushed them to the cocoapods trunk spec repo then we could reference them in the react native podspec. Is that the path you'd follow or is there another way to keep them private? Can't really reference git or path dependencies in a podspec.

@aslattum
Copy link

aslattum commented Sep 18, 2024

@cipolleschi in the example you give, I see that you have RCT-Folly.podspec and you are referencing that in the React-Core.podspec. How is the React-Core.podspec able to know where to look for the RCT-Folly.podspec. Do you all publish the spec to cocoa pods trunk or something else?

@cipolleschi
Copy link

You have two alternatives:

  1. you can have a private cocoapods repository. This will be your private company repository. You can publish all the pods you want there as if it was the public repo but only members of the company can use them.
  2. if only your apps need to access those private podspecs, you can use the :path or :podspec alternatives to link the pods. This is what we do in React Native. Here we have a script that installs the dependencies in the app using that approach. Then other podspecs can depends on the local pods and trust the app that will provide all the dependencies that they need.

@YangJonghun
Copy link

@cipolleschi
How about collaborating with Tuist?
https://community.tuist.io/t/supporting-react-native-on-moving-on-from-cocoapods/164

@pepicrft
Copy link

pepicrft commented Nov 5, 2024

This is exciting! We've been following the development of SPM quite closely, and I have mixed feelings with SPM being the most sensible replacement within the context of React Native. Note that I might be biased, but here are some thoughts that I had regarding the idea:

  • React Native needs to construct a dependency graph off the content in node_modules using the Node module system, and map that to a graph that's compilable and intractable from Xcode. SPM's graph is designed around Package.swift and strict conventions around where sources should be located. One might think that that's fine, React Native could ask developers to follow the sources convention, but what about the dependencies between packages? SPM doesn't understand about the Node module system, nor can be instructed to look up dependencies elsewhere. So in that sense, this is really dependent on Apple to make their graph loading more flexible (will they be keen to do so for RN?), or maybe the React Native team coming with some trick using file-system symlinks to simulate the convention that SPM expects (do you really want to go down that path?)
  • That'd just be the graph of packages, but those need to be integrated into an Xcode project that contains the target of the app. Xcode projects have always been in the developers' repositories and they've been responsible for keeping it up to date with React Native and Xcode's recommendations. Through "CocoaPods" patches could be applied, but that felt a bit hacky. Imagine if the graph spanned not only the packages but also the app side. And not only that, imagine not having to manage the Xcode project anymore. Xcode projects can become an implementation detail and the underlying CLI (not sure if this would be some Meta-maintained CLI or Expo) would generate them on the fly and make them the input of xcodebuild or open them in Xcode for building and running them.

While I understand the concern of depending on something that's not Apple-official, which is something we've been hearing since the day we wrote the first line of code in the generation code, Xcode projects are here to stay, and the generation logic is so battle-tested at this point, that we could extract it (in fact we are doing it), and treat that a community effort shared between Meta, Expo and Tuist. The solution would be something along the lines of:

  • package.json contain a section describing an Xcode project target
  • Some Node logic would construct a graph that's serialisable and pass it to the Swift logic to output an Xcode workspace on the other end.
  • Then Expo / React Native CLI would use that as input of the xcodebuild command.

We don't have a lot of resources to spare to implement something like this, but we'd be happy to share the context and the knowledge and figure out a model where React Native feels comfortable building on this foundation like it did when it made the decision to use CocoaPods. I think eliminating the dependency on Ruby, CocoaPods, and the need to maintain an Xcode project can significantly improve the developer experience when building React Native apps for Apple platforms.

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

No branches or pull requests