'Swift Package Manager (SPM) and Cocoapod Dependency Conflict

Overview

I have two dependencies, one available as a Swift Package, and the other only available as a Cocoapod. The problem is that each has a dependency on a third package, which results in undefined behavior when multiple versions exist.

At a basic level, here is a graphic of my dependencies

APP imports:
  B (SPM) imports:
    C (SPM) imports:
      D (SPM) <-
  E (Pod) imports:
    D (Pod) <-

I would like to remove the D (Pod) version and point to the D (SPM) version either via a Podfile script or build script.


More specific information:

I have a NetworkingService Swift Package that imports Firebase, and my main app imports the NetworkingService. My Podfile imports GoogleMLKit/PoseDetection. Firebase and PoseDetection share dependencies that result in undefined behavior (runtime crash) when a duplicate is present.

Note: This error should be reproducible by removing the intermediary NetworkingService package and importing Firebase to the main app as a Swift package.

Podfile

platform :ios, '15.0'

target 'MyApp' do
  use_frameworks!
  pod 'GoogleMLKit/PoseDetection', '2.5.0'
end

In Package.swift

.package(
  name: "Firebase",
  url: "https://github.com/firebase/firebase-ios-sdk.git",
  .upToNextMajor(from: "8.10.0")
),

They duplicate a few dependencies, including GoogleUtilities and FBLPromises. Launching the app after pod install crashes with runtime exception:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[FBLPromise HTTPBody]: unrecognized selector sent to instance 0x6000017685d0'

Searching that brought me to this GitHub issue where a contributor mentions:

The duplicate warnings are indicative of non-deterministic behavior. When there are multiple copies of a library, the right one may or may not be chosen.

I then attempted to refactor all Cocoapod dependencies with a modified version of this script I found linked on another StackOverflow post. The attempt was to make PoseDetection explicitly point to symbols from GoogleUtilitiesCopy and FBLPromisesCopy. But it seems that even the existence of these copies, despite pointing to the corresponding dependency, created undefined behavior.


Partial Workaround

If I run pod install followed by File > Packages > Update to latest package versions. The app will launch without an immediate runtime crash. However, I encounter other runtime crashes later within the app.***


Ideal Solution

I would like to remove the duplicate pod dependencies and point to the SPM versions either via the Podfile or a build phase script, but I'm not sure where to begin.

Firebase can be imported as a pod, but I do not want to do this because I have an existing SPM infrastructure that depends on Firebase. I'd prefer not to convert all of these packages into pods.



Solution 1:[1]

The main problem with SPM and Cocapods is that: SPM is not aware of Cocapods and Cocapods not aware of SPM.

I had a similar situation where:

  • pod library depends on some Library networking
  • SPM library also depends on the same Library networking.

There are two solutions I think are worth trying.

1.) remove the pod and try to use the XCFramework version of it (should be available). that means you should manually add the library to your project and it should be selected as embed & sign and also as required.

2.) you can convert the pod library to SPM by using a simple binary target. Basically, you need to create a Package file that points to the XCFramework in its archived version (hence it should be a zip file). that way the SPM graph will handle it by itself.

I know it's not ideal, but these two approaches works for me.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 XcodeNOOB