How to link a (subproject) framework against a pod? - ios

I am creating a new app MyApp, where I decided to put some parts of the app in a seperate framework MyFramework, instead of the app itself to make them reusable in other projects. The framework has its own project (MyFramework.xcodeproj) which is a subproject of the main app project (MyApp.xcodeproj). The main app project has a dependency (does linking & copying) on the framework (MyFramework.framework), of course. This part works fine so far.
Now, MyFramework needs a cocoa pod (Alamofire) in order to work. As far as I understood, I don't want to set up cocoa pods for the MyFramework.xcodeproj project directly, so I just set it up for the main app MyApp.xcodeproj (now MyApp.xcworkspace because of pods) and also included the Alamofire pod there. I then linked MyFramework.xcodeproj against the Alamofire.framework (not the MyApp_Pods.framework), but did not set Alamofire for copying. The MyApp.xcodeproj does the usual cocoapods linking/copying/bundling stuff, so also includes the Alamofire.framework in the final product. This worked partially fine.
(Note: I say 'partially fine' here because I occasionally had errors in the MyFramework sources not finding the Alamofire module when compiling, which could be fixed by re-linking the Alamofire.framework in the MyFramework.xcodeproj. Besides that, building and running the app works fine.)
The issue is now, when I try to archive the app, the Alamofire module is again not found in the MyFramework sources. The error occurs both, when archiving the MyApp (which also builds MyFramework), as well as archiving MyFramework directly. The error occurs not in the linking phase, but in the compile phase of a source Swift file that has an import Alamofire statement.
I suspect something like the linking of the Alamofire.framework to use a wrong relative path that can be found while building, but is different on archiving or such. I already tried to set the Alamofire.framework path to Relative to build products, but couldn't get this to work, not even for regular building (not archiving).
I'm now stuck and wondering whether my whole setup with linking from the MyFramework.xcodeproj project to the Alamofire.framework and having Alamofire included as a pod is correct.
Can anybody give me a hint what might be wrong here? Either in the paths or in the whole setup?

This won't tackle the problem itself, but would provide a solution that serves your need:
Transform MyFramework into a pod. Host it in your private spec repo, or — even simpler — use the git parameter in the pod file to access it.
pod 'MyFramework', :git => 'https://gitsever/maxscompany/MyFramework.git'

Related

Embedding XCFramework in application with project framework dependencies

I have an Xcode workspace which features a project with an iOS Application target, and another project with a Framework target. The framework target is dependent on another framework, which is integrated in the form of an xcframework:
MyApp
MyFramework
OtherFramework
Using regular OtherFramework.framework would require it to be linked to MyFramework and then embedded in MyApp even though MyApp doesn't require the framework itself. However when integrating with xcframework, this project then fails to build with a No such module 'OtherFramework' error.
Project settings:
MyFramework Project
MyApp Project
Removing OtherFramework.xcframework from the MyApp target fixes the build issue, but then causes library not loaded errors as the framework is not present in the application.
Demo project here: https://github.com/msaps/XCFramework-Link-Issue
How are you meant to link an xcframework in an application and link in a dependent framework?
Why?
pyckamil just posted this article which explains the issue in detail: Everything wrong with XCFrameworks.
It turns out Xcode has an optimisation for the ProcessXCFrameworkLibrary step which extracts the correct .framework from an .xcframework for the active build architecture. This is only run once which causes issues for additional targets that try to link the same framework.
Update
This issue is resolved in Xcode 12.0
UPDATED - Resolved in Xcode 12.0
shinsuk came up with a reliable workaround that works by adding architecture-explicit framework search paths to ensure the correct .framework within an XCFramework is found.
Details can be found in the README.
Check build settings and defining the Framework Search Paths to a folder which contains the frameworks in question. If the frameworks are placed in your project directory, simply set the framework search path to $(SRCROOT) and set it to recursive.
check the response Getting error "No such module" using Xcode, but the framework is there
IMO, It seems not xcframework issue.
Check out this answer: https://stackoverflow.com/a/59435627/2661407
Umbrella frameworks are not supported on iOS, watchOS, or tvOS.
OtherFramework.xcframework should be signed and embedded in your host app.
and add "#executable_path/Frameworks" setting into your MyFramework.framework > Build settings > Runpath Search Paths.
I had this issue as well after using xcframework instead of framework. So I changed my project structure:
The MyFramework Peoject embed OtherFramework.xcframework,Then make it exported using #_exported import OtherFramework in MyFramework Project. And the MyApp just link MyFramework but can both import/use MyFramework and OtherFramework.
BTW, It seems to custom the #rpath and manual codesign the OtherFramework.
I had an issue like that as well.
First, make sure if you have MyFramework.framework file within the same directory as MyApp.
Second, when building MyFramework.framework, make sure that OtherFramework.xcframework is as well in MyFramework's project directory.
And one more thing, check target SDK versions. They should be somewhere on the same level.
I had the same issue as you, and after seeing your pbxproj I think it can be solved the same way.
Change your framework search path to recursive (either through UI or manually editing the pbxproj "$(SRCROOT)/../Frameworks" => "$(SRCROOT)/../Frameworks/**"), like so: https://github.com/msaps/XCFramework-Link-Issue/pull/1/files

Swift Build Error - No such module 'Feature1'

I am getting compile error when I added a framework into my app. Framework Feature1 is built successfully but from module App import is not working.
How to solve this issue?
There are several potential misconfigurations the issue can arise for,
Please confirm that you have opened the .xcworkspace but not .xcodeproj file. Also make sure you have build Feature1 first before you build App.
Make sure that iOS Deployment Target is set same for all modules with App. For example is Apps deployment target is set to 9.0, Feature1s deployment target also need to be set to 9.0.
Make sure your main module (App) and your used framework (Feature1) have same set of configurations. i.e. If your Project has three configurations, Debug, Release, ReleasePremium than your Framework also need to have three configurations Debug, Release, ReleasePremium. Also make sure that the archive configuration is set same for both App and Feature1. i.e. if your Apps archive scheme is set to ReleasePremium, your Fearure1s archive scheme also need to be set into ReleasePremium.
Please assure that you do not need to import Feature1 in each .swift files when its already added in the Bridging-Header.h.
In case of issue came from Pod files, make sure you have uncommented #use_frameworks! into use_frameworks! from you Podfile. Sometime re installing pod works if Feature1 has any dependency on pods.
If none of the above steps works, delete your derived data folder and try re building.

No such module 'Alamofire' when importing module into Cocoa Touch Framework and embedding framework into App Project

I've bee really struggling with this bug the past few days.
So I have a workspace we can call XYZWorkspace.
Then I have an app project in this workspace called XYZ.
Then I have a Cocoa Touch Framework in this workspace called XYZCore (which contains reusable non-UI files)
Lastly, I have Cocoapods set to install Alamofire on the XYZCore framework.
I have XYZCore listed as an Embedded Framework of the XYZ app project target.
Here is my issue, when I build the XYZCore framework, Alamofire gets imported properly. However, when I build the XYZ app target, I get the error "No such module 'Alamofire'" in the XYZCore.
I know that Pods is set up properly on the XYZCore framework because when I build that scheme, everything succeeds. I think I don't have something set up correctly from connecting XYZCore to XYZ app.
Other information: I have custom configuration files set up for the XYZ app project that import the Pods configuration files.
Some checklist steps I've performed:
Made sure building from the workspace
Marked the Schemes for both the framework and app target as Shared
Deleted Derived Data and Cleaned build folder
I've even gone as far as restart the project completely to make sure I didn't miss a step, however something is still connected correctly. I've done this setup on other projects without any issues, could someone help me?
this usually happens when your frameworks are not set-up correctly on the target's Build Phases settings page.
Have you checked that under Target/Build Phases/Embed-Frameworks // Link-Binary-With-Libraries everything is added correctly? If so can you provide with screenshots of those screens, also maybe try running 'pod install' again on your root folder, it has worked for me several times.

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.

Xcode: create Framework with pod dependecies

I create a framework that use AFNetworking (installed with pod).
I can import this framework on my project and I can use all classes/methods that I exposed, so project compile.
When I try to run project on simulator, I obtain this error:
dyld: Library not loaded: #rpath/AFNetworking.framework/AFNetworking
Referenced from:
/Users/.../Library/Developer/CoreSimulator/Devices/F56F98F0-2AE0-4C87-AC9A-6E3B449762D1/data/Containers/Bundle/Application/BFA5359F-8FCE-4402-8487-CD9C002CB673/MyProject.app/Frameworks/MyFramework.framework/MyFramework
Reason: image not found
I already included 'MyFramework' under:
Build phases -> Embed Frameworks
I suppose I missing something on building Frameworks, but I can find out what! I already seen this unanswered question.
Who can I use MyFramework without installing Pod on MyProject again?
It is really delayed, for this issue but I have got my project working. It might not be the best way but it works. I am putting it here for future reference.
I wanted to do it without using Pods in the main project. The reasoning is, we are bundling our SDK into a framework.
So essentially, the first step I took was to get the framework project bundling without using the workspace. I just dragged the Pods project into the framework project.
Then I added the frameworks the the pods project creates and add them to my framework. I set them to optional and code sign. You can see them in the picture of where I added them under the build phases.
Then add them to your main project. not the framework the normal way by adding the project and or the framework. Then add it to the Embedded binaries and Linked Frameworks.
If it helps anyone, the solution mentioned by #ArtyomDevyatov does work. The trick is that you have to add 's.dependency' in podspec file.

Resources