FBLPromise crash with CocoaPods and SwiftPM implemented in both - ios

We've been migrating away from CocoaPods since a while, but not every dependency has made the switch. Like Firebase.
I've had a similar question regarding duplicate symbols, but now I'm facing something new, which is probably because I'm using a dependency in both SwiftPM as in CocoaPods.
After running my (sample) project it crashes:
-[FBLPromise firebaseInstallationID]: unrecognized selector sent to instance 0x600003f5a430
with a warning at the top:
objc[93047]: Class FBLPromise is implemented in both
/xxx/SampleProject.app/Frameworks/FBLPromises.framework/FBLPromises (0x10b3f09a8) and
/xxx/SampleProject.app/SampleProject (0x10af736f0).
One of the two will be used. Which one is undefined.
Prior to my update to Firebase SDK v6.26.0 I would only get the first warning, but since the update it crashes.
I saw a doc about how to use Firebase within libraries and a GitHub issue regarding a similar crash. But nothing seems to work to resolve this crash, other then downgrading.
I uploaded a sample project: https://github.com/basvankuijck/SampleProjectFirebaseCrash.
Removing the SwiftPM Promises dependency is not an option, since the actual project is using a SwiftPM dependency that has a dependency to Promises.
The Podfile is nothing that fancy, and the SampleProject just uses one single SwiftPM dependency.
Anyone who has an idea how to let SwiftPM and CocoaPods play nicely together especially with Firebase in the middle?

I faced the exact same problem with Firebase and FBLPromise. For me it arose because I added Firebase/FireStore in podfile but the rest of the FIrebase dependencies from SPM. Among my other SPM dependencies was FBLPromise as well.
To fix it I had to remove the FIrebase package from SPM and then add it again with FIrestore and other dependencies that I could need from Firebase.
No other solution worked for me.

Related

Migrating from carthage to swift package manager

I have a project that has multiple external dependencies as well as in house ones such as analytics, api, interfaces, that are all integrated with Carthage. I wanted to gradually migrate all of them to SPM starting with the analytics module.
I've restructured my analytics module to a package and integrated it to main my project using SPM (all worked well!). I did the same for all the other modules that also depend on analytics and removed the references from cartfile, .resolved and .private files.
The issue that I'm facing now is that I'm not sure how to remove the integration done by carthage. Even removing the reference from all cartfiles and from framework and libraries, when I run carthage bootstrap it looks like it still fetches that module and adds the framework to my Carthage folder, which I don't want to.
It's the first time I'm using Carthage, so I'm not sure if I might be missing some step when removing just one dependency. If anyone with more experience could help I'd really really appreciate it =]

Package.swift together with Xcode 11 Project, how to use Carthage and SPM alongside?

I feel caught between the Carthage world and the Swift Package Manager (SPM) world, like being stuck in purgatory.
I'm developing a Swift library/SDK, and up until now, I've been using Carthage for dependencies. But since SPM finally works with iOS, I feel it would be great for people who want to use this library to be able to include it via SPM.
However, I've hit a wall. One of my dependencies, namely BitcoinKit works with Carthage but SPM support is broken.
In order to distribute my library, I need to have a Package.swift file, and some other critteria (README, source files in Sources, and tests in Tests). I also need to declare my dependencies in said Package.swift file, so that SPM recursivley can resolve all dependencies (when people install my library via SPM). Here's where I get stuck...
Since I'm still using Carthage I need a Xcode Project file to set up this Carthage dependency. But now my source files cannot import the SPM dependencies. They aren't found. Seems like I MUST include the SPM package dependencies using Xcode and Add Package Dependency feature (Apple doc here). This is not what I want right, I want my Package.swift file to declare the same versions of the SPM packages my library uses. To make it clear, this problem arises due to the fact that I need a Xcode project, due to Carthage.
So I thought maybe I could build BitcoinKit with Carthage (as I'm doing now), and include the built binary (.Carthage/Build/iOS/BitcoinKit.framework) my library, referencing it in Package.swift, but that does not work since SPM does not (yet?) support binaries (relevant Swift Forum Thread).
So what are my options?
1) Wait until someone smart fixes the broken SPM support in BitcoinKit (I've tried myself and failed), and then remove my Xcode project file and complete the transition of to only SPM and for now stick with Carthage...
2) Try to use SPM packages internally in my library installed through Xcode Add Package Dependency feature and manually sync those versions with the ones I declare in my Package.swift. Will that even work? Ugh, terrible solution anyway.
3) Hope to include BitcoinKit.framework built through Carthage as a binary when SPM supports it? When? Might take a while?
4) BitcoinKit also works with Cocoapods, but I guess that gets me nowhere, even worse actually, since Cocoapods creates a .xcworkspace file.
5) Wait until Apple hopefully (does anyone know if there are any plans?) changes so that we include Swift Packages via Package.swift file even when used together with an Xcode project file? That we I could keep on using Bitcoinkit via Carthage and only declare my SPM packages in one place and I guess SPM/Xcode/Swift would be responsible for integrating the dependencies into my Xcode project, but updated and managed through the Package.swift file...?
6) Any other alternative, real solution?
Without looking into the whole 'making bitcoinkit work with SPM' bit I think the 'linking a carthage prebuilt binary' idea sounds best as an interim solution at the very least.
It's not possible to link a binary in the package manifest (yet) but you can link it when you're building:
When building an SPM package from the command line using swift build you can link the binary using -Xswiftc or -Xlinker to pass the args -F path/to/bitcoinkit if you're linking a framework. Keep in mind each argument must have a cross argument flag before it.
When building in Xcode you should be able to solve it with an .xcconfig with the contents:
FRAMEWORK_SEARCH_PATHS = path/to/bitcoinkit
You may have to tweak it a bit but I imagine this should work, worst case having a separate .xcodeproj generated by swift package generate-xcodeproj --xcconfig-overrides myconfig.xcconfig.
There is a WalletExample in yenom/BitcoinKit on GitHub. It comes with a workspace and project.
I was able to include yenom/BitcoinKit with SPM in my Package.swift and I don't use any projects/workspaces.

How to add or read Google calendar events iOS [Swift] without using Cocoa Pods

I am currently working on integrating Google Calendar into my iOS project which uses GoogleAPIClientForREST And GoogleSignIn libraries. Project Git can be found here. I am able to add or read all my Google calendar events.
However, I have been asked to make it work without using Cocoa Pods. I have added all the necessary frameworks by dragging and dropping into my project, it builds and runs but I'm getting a crash at this line (attached screen shot for ref) GIDSignIn.sharedInstance().scopes = [kGTLRAuthScopeCalendar] .
Here's working screenshot where am getting the kGTLRAuthScopeCalendar element in array. (Using Cocoa Pods)
Here's screenshot where am getting a crash because the kGTLRAuthScopeCalendar element in array has 0 values. (Without Using Cocoa Pods)
Does anyone have any idea what I might have missed, or am I wrong in my implementation without CocoaPods if yes, how?. Please help.
SO links previously referred: 1. How to Create events using Google Calendar API iOS Swift , 2.https://code.tutsplus.com/tutorials/ios-sdk-working-with-google-calendars--mobile-19155
Does anyone have any idea what I might have missed, or am I wrong in my implementation without CocoaPods if yes, how?
Cocoapods is just a dependency manager and distribution mechanism — it doesn't add any actual functionality to your code on its own. You could simply remove the Podfile from your project and you'd be left with a working project that no longer "uses Cocoapods."
One of the lovely things about a dependency manager like Cocoapods is that it manages not only the things that your project needs directly, but also the things that those dependencies need, and so on. There are only two pods listed in your Podfile, but your Podfile.lock shows about 18 pods because the two that you use directly each depend on other pods.
I don't think there's nearly enough information in your post to let us really understand what specific thing(s) you've missed in removing Cocoapods, but from your screenshot it looks like you only have about six frameworks installed in your project while, again, your Podfile.lock shows many more pods than that. It may be that some of the frameworks you need are embedded inside top level ones in your project, but the fact that your project doesn't work correctly even though you're presumably using exactly the same source code is a strong indication that you've left out one or more of the frameworks you need.
Go through the list of pods in Podfile.lock and make sure that the framework each one specifies is included in your new project.

Can't Use "Vendored Framework" CocoaPod Inside Workspace Playground

I've created a sample project illustrating my issue here.
In summary, I'm trying to use a "vendored framework" CocoaPod inside a workspace playground. I think this is possible but requires a bit of fiddling with project settings, and I can't quite figure out what to change.
To observe the issue in the sample project, do the following:
Open CocoaPods-Test/CocoaPods-Test.xcworkspace in Xcode.
Pods should be installed and committed in the repository, but can run pod install if necessary.
Note that the CocoaPods-Test target builds and runs successfully, importing PromiseKit and TwilioChatClient pods.
Navigate to Playground.playground within the workspace.
Note that the playground executes fine while importing PromiseKit but if TwilioChatClient is imported, playground execution fails with "no such module 'TwilioChatClient'".
After reading the following resources:
https://github.com/CocoaPods/CocoaPods/issues/5334
https://github.com/CocoaPods/CocoaPods/issues/5215
https://github.com/CocoaPods/CocoaPods/issues/5563
https://github.com/CocoaPods/swift/issues/3
https://github.com/CocoaPods/CocoaPods/issues/4135
https://github.com/CocoaPods/CocoaPods/issues/2240
https://github.com/CocoaPods/CocoaPods/issues/6669#issuecomment-300188519
https://guides.cocoapods.org/using/troubleshooting.html
https://www.objc.io/issues/6-build-tools/cocoapods-under-the-hood/
I think the issue is probably related to the fact that TwilioChatClient is a "vendored framework" (see its podspec), which means a pod target is not created for it. After reading the above resources, I feel like a solution is within reach, but I can't quite figure it out.
While the sample project here illustrates what I think is the underlying issue, the issue that prompted me to create this example project is just a small bit more complicated.
In my project, I create a framework target containing all my app's code (so it can be imported into my app and also into my playgrounds using app resources). This framework then has pod dependencies, including PromiseKit and TwilioChatClient. The execution error in the playground is different ("Couldn't lookup symbols" instead of "no such module"), as I am not importing the CocoaPods module directly but my framework which uses the pod framework.
I suspect if I can solve the "no such module" issue, it will help me solve my "couldn't lookup symbols" issue.
Finally, this seems like a good opportunity to make an open source contribution others don't seem to have wanted to do (see discussion here). Tangentially, I'd love to contribute but just don't feel like I understand what exactly is going on with CocoaPods, the Xcode build process, etc., after reading about it a bit (e.g. here and here). Any references to help understand the Xcode build process and what CocoaPods is doing under the hood are appreciated. It seems like the resources I've found are either "a very high level overview" (which I get), or "digging through the source code", with not a whole lot in between.
If you must have this work, I came up with a workaround by creating a framework target inside the Pods project which is named the same as the vendor framework, and uses all its headers publicly, using the framework as a sole dependency. I have forked your GH example and linked it here.
It's not the most elegant solution, but it will help you out in a pinch.
UPDATE
Build "fake" framework first, then build app target, then go to playground.

How can I use a 3rd party Framework inside my CocoaTouchFramework and my consuming App?

I am developing an iOS App and a CocoaTouchFramework. The iOS App depends on the framework. My goal is to use a 3rd party Framework (in this case AlamoFire) inside my CocoaTouchFramework. According to this Stack Overflow link it is discouraged to have a Framework embed another framework. The way I understand it is that the consuming iOS App (the app which depends on the framework) needs to provide the 3rd party dependency and that my framework can reference that dependency. I don't know how to set this up in Xcode however. Here is what I have currently set up in Xcode:
AlamoFireApp is the actual App and AlamoFramework is my own Framework that will use AlamoFire to perform various network requests. I embedded the AlamoFire dependency into the App. How can I use AlamoFire in the Framework now? I've tried linking to AlamoFire from within the Framework (Adding Alamofire.framework) in the Link Binary With Libraries section) but I always get the No such module 'AlamoFire' error when I try to import AlamoFire in my Framework's classes.
Any help is appreciated.
#cbbcloud you can make your own cocoa pods using alamo fire. All you have to do is add them as dependency in pod spec. And then you can import the use the framework to build your framework.
Pod::Spec.new do |s|
s.name = 'YourFrameworkName'
//other info
s.dependency 'Alamofire'
end
If you are new to cocoapods , follow this link
https://guides.cocoapods.org/making/index.html
Ok I've found a way to do it. I was able to solve the problem by dragging the AlamoFire.Framework into my framework (in this case, AlamoFramework) in Xcode. The important part that makes this work is to check the 'Copy items if needed' checkbox.
After checking this, the compiler can resolve the Alamofire module and there are also no linker issues. However this approach seems to contradict the recommendation of Rob Napier in his answer to this question that states:
The only appropriate time to link dependencies is at the application layer.
I haven't done full-time iOS development for very long so if anyone has any input they can give to clear up this issue, that would be great. But my problem has been fixed for now so I can continue with development.

Resources