Swift Package Manager (SPM) and Cocoapod Dependency Conflict - swift

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.

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.

Related

Redefinition of module 'Firebase'

I'm trying to integrate Firebase into my app, but as soon as I'm building it after I thought I finished my install I get:
Redefinition of module 'Firebase'
as well as
Could not build Objective-C module 'SwiftOverlayShims'
which I have no idea what that means but I'm assuming its a result of the first.
My podfile looks like this:
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
target 'app' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
pod 'Firebase/Auth'
# Pods for app
end
So I don't think theres anything conflicting there. I saw a solution that told me to go into my Header Search Path and see if my project had multiple Firebase directories, but I have no custom paths, so that wasn't it. Any insight?
EDIT: Here is the exact display from my errors
Uncommenting the platform line in my podfile and changing it to iOS 10.0 did get rid of the error saying "Could not build Objective-C module 'Firebase'" So we have made some progress.
Here is the path when selecting "previously defined here"
From what I can tell, it is only giving me one location. Selecting the redefinition error just gives me the relative path of module.modulemap , so I am assuming that is referring to the same thing. I am also getting multiple warnings like this
Skipping duplicate build file in Copy Files build phase: /Users/me/Library/Developer/Xcode/DerivedData/app-elgcucdextsnzqbtlznbqeulbfks/SourcePackages/artifacts/Firebase/FirebaseAnalytics.xcframework/ios-arm64_i386_x86_64-simulator/FirebaseAnalytics.framework
as well as a couple other frameworks in the ios-arm64_i386_x86_64-simulator directory, so maybe that has something to do with it.

XCFramework "Cannot load underlying module"

I've built an SDK as an XCFramework, which shares dependencies with the app that uses it. When I build, I'm getting:
...SDK.swiftmodule/arm64-apple-ios.swiftinterface:20:8: Cannot load underlying module for...
This occurs in the Compile Swift Sources action and the break is in the import MySharedDepedency statement in the swiftinterface file
As stated, the SDK in the project as an xcframework bundle. MySharedDependency is fulfilled with cocoapods. use_modular_headers is set in the Podfile, it's modulemap is included in the linker flags (by cocoapods).
Its DOES work if I use the use_frameworks! flag in the Podfile but only with dynamic linkage and for internal politics reasons, I need this to work with static linkage. If I add the :linkage => :static argument, I get the same error as with no use_frameworks! call
I've tried changing the order of the linked frameworks in Build Phases (so that the pods are linked before the SDK framework). I've tried adding recursive header/framework/module search paths everywhere I can find a MyDependency.modulemap...
Yes, I've cleaned caches, deintegrated, clean installed, erased deriveddata, restarted xcode, my machine, ...
Argh! Thanks for any help...
I had the same exactly the same scenario and the same problem
I solved using #_implementationOnly in every file from my xcframework's code like:
#_implementationOnly import Alamofire
After that just rebuild your XCFramework, clean and build your app's project.
It works like a charm without use_frameworks!

Swift Package Manager (package successfully added, but Module not found)

I'm new in Swift. I want to create iOS app that can connect to PostgreSQL database. First I found library https://github.com/vapor/postgresql.git that should be added to my project via Swift Package Manager. Using tutorial I added required library to my project successfully (File -> Swift Packages -> Add Package Dependency):
list of added packages from SPM
But when I try to import this module into my view controller, Xcode shows error that module is not found:
not found
I tried several times to rebuild my project, created new project just for testing this issue. Also I found information about build phases and added this lib as a dependency:
build phases
But I still get error: "No such module PostgreSQL".
Can anyone help me?
I found solution by myself. I compiled C static library "libpq" (can be found in PostgreSQL sources) and added it to my swift project. Included this library by adding special bridging header file. Finally I got what I wanted.
P.S. If someone what to repeat, he or she should know: static C library must be compiled for iOS device architecture (and also in iOS simulator architecture which differs from iOS device arch.).

Local swift package with local dependency

I have a project that I plan on developing in modules, the final application will be any number of the modules built together based on a configuration. I have a swift package that has all of my common code it it, we can call that the platform package. I then went to create my first feature, this went just fine however when I created the wrapper application to pull in each feature, I got this error from SPM in xcode11:
package 'Platform' is required using a revision-based requirement and it depends on local package
'Feature1', which is not supported.
Looking at the code base for SPM here (line 72)
https://github.com/apple/swift-package-manager/blob/master/Sources/PackageGraph/DependencyResolver.swift
It looks like this is something that is just not supported, the mixing of local and remote dependencies? Is this a limitation of SPM / should I be trying to use another tool for this type of app architecture?
In my case, I was trying to add a package, which I was developing, and its Package.swift contained dependencies of the form:
dependencies: [
.package(path: "../PackageName"),
// etc
Changing the references to specific repos solved the problem:
dependencies: [
.package(path: "http://github.com/..."),
// etc

How to link CocoaImageHashing pod with Swift project (dyld: Library not loaded)

I'm trying to use the CocoaImageHashing pod from a Swift project so that I can do some perceptual hashing for image duplicate detection.
I setup the workspace following the CocoaPods instructions and attempted to run the default Hello World swift file.
dyld: Library not loaded: #rpath/CocoaImageHashing.framework/Versions/A/CocoaImageHashing
Referenced from: /Users/sarge/Library/Developer/Xcode/DerivedData/PHashTest-cdongczzcrynrfclysczwalanrlq/Build/Products/Debug/PHashTest
Reason: image not found
(lldb)
My Podfile is:
platform :osx, '10.12'
target 'PHashTest' do
use_frameworks!
pod 'CocoaImageHashing', :git => 'https://github.com/ameingast/cocoaimagehashing.git'```
end
I tried commenting out the use_frameworks! line in case this was some kind of dynamic library problem. I then get a build error.
Framework not found CocoaImageHashing
My General > Linked Frameworks and Libraries does include the CocoaImageHashing framework. I see Xcode building files from it during a build.
Is there something I have to do to get the CocoaImageHashing pod to build the dynamic library that Swift expects? Or do I need to not use Swift because CocoaImageHashing has to be included dynamically.
(I'm very unfamiliar with Swift so I don't know what to look for)
You should include the framework at General -> Embedded Binaries as well.