Why do we use use_frameworks! in CocoaPods? - ios

I have used use_frameworks! in CocoaPods Podfile many times. I just wonder why do we use it? I couldn't get the straight forward answer of it.
Example:
platform :ios, '8.0'
use_frameworks!
target "CityWhether" do
pod 'Alamofire'
pod 'SwiftyJSON'
end

use_frameworks! tells CocoaPods that you want to use Frameworks instead of Static Libraries. Since Swift does not support Static Libraries you have to use frameworks.
In another answer, I explained the differences between Static Libraries and Frameworks:
Cocoa Touch Frameworks
They are always open-source and will be built just like your app. (So
Xcode will sometimes compile it, when you run your app and always
after you cleaned the project.) Frameworks only support iOS 8 and
newer, but you can use Swift and Objective-C in the framework.
Cocoa Touch Static Libraries
As the name says, they are static. So they are already compiled, when
you import them to your project. You can share them with others
without showing them your code. Note that Static Libraries currently
don't support Swift. You will have to use Objective-C within the
library. The app itself can still be written in Swift.
Sources: My other answer | AddThis.com Blog

use_frameworks! tells cocoa pods to use dynamic libraries, and was very prevalent at one point due in particular to swift not supporting static libraries, meaning there was no choice - however you often don't need use_frameworks! anymore.
As of Xcode 9 beta 4, and CocoaPods 1.5.0, swift static libraries are now supported. The main advantage is faster app startup times, particularly if you have a lot of pods - iOS 10 and 11 are not the fastest when you have many dylibs.
CocoaPods 1.5.0 was released in early April 2018, so you may need to upgrade to get it: sudo gem install cocoapods.
I've found several pods that don't work correctly with static libraries yet though, so your mileage may vary.

use_frameworks! declares that you want to use dynamic frameworks, instead of static libraries.
With Xcode 9.0 and CocoaPods 1.5.0 released, you could use static libraries with swift if you do not use use_frameworks!.
One problem with use_frameworks! is that all your framework in Pods/Products are frameworks.
Here is a related article: Basic overview of static and dynamic frameworks on ios

Cocoapods use_frameworks
Cocoapods[About] use_frameworks! is responsible for the type of binary:
if use_frameworks! is present - dynamic framework
if use_frameworks! is not present - static library
use_frameworks! has a reflection in Mach-O Type[About] in a corresponding target of Pods project.
Timeline:
CocoaPods 0.36 introduced use_frameworks! which you had to use for Swift pod
CocoaPods 1.5.0 and Xcode 9 allowed you to have a choice
[Vocabulary]

Adding
use_frameworks!
in the Podfile means that we want the listed frameworks to be dynamically installed instead as static frameworks.

Related

How to build Swift framework with 3rd party SPM dependencies

I've built swift frameworks before, but I've never dealt with one that has 3rd party dependencies.
What I have right now is a Swift framework that has a dependency on several Swift packages. When I build it I see MyFramework.framework in the products folder as well as bunch of dependencies. I can make XCFramework out of it, but when integrating (embedding) it into another app I see an error that MyFramework is missing its dependencies (see image below).
What am I doing wrong or missing?
Creating a framework (or xcframework) that has embedded other frameworks is not supported for iOS(I believe this is answered here).
But there is an other way. You can statically link all the dependencies of your library, so in the final framework the binary will also contain the code of its dependencies.
If you are using CocoaPods and the name of the framework is aFramework you can do:
target 'aFramework' do
pod 'Alamofire', :linkage => :static
end
Then you can use the created aFramework.framework in a application target that does not have the Alamofire framework, since the code will be "embedded" in the aFramework's binary.

Use a single pod in swift

In my project I've around 20-30 PODS and all of them are in OBJECTIVE-C.
In some of the pods I've changed some pieces of code due to requirement.
Now I want to add a pod which is only written in swift. Is it possible to use swift for only that specific pod ? I don't want to use "use_framework" as it will force all other pods to use static frameworks.
Currently use_framework! is either all or none. There is currently an open issue to change that.
Swift static library support will be added in CocoaPods 1.5.0 so that is likely to be the soonest route to a solution for you, but still a ways off.
With the release of cocoapods 1.5.0. Not it's possible to use only a single swift pods. From official docs
you can add use_modular_headers! to enable the stricter search paths and
module map generation for all of your pods,
or you can add :modular_headers => true to a single pod declaration
to enable for only that pod.
By this we can improve store submission time. Here is the official doc page Cocoapods 1.5.0.

Custom CocoaPod Framework with Other Cocoapods

There is so many things written about it but still I am unable to figure it out.
So here what I am doing:
I have create a Cocoapod Test Framework with code borrowed from some tutorial here and there. Repo
Podfile
platform :ios, '9.0'
target 'CocoaPodTestFramework' do
use_frameworks!
pod 'Alamofire'
pod 'SwiftyJSON'
end
In the framework I needed a http call so I used Alamofire and SwitfyJSON pods in my framework workspace. After successful buidling process I get three framework files:
CocoaPodTestFramework.framework
Alamofire.framework
SwiftyJSON.framework
Now When I want to use it a app and created a few test app to test my framework.
Swift: the app is not using cocoapod(normal Xcode Project not workspace), I simply link all the 3 framework and it work.
For Objective-C App, I did the same and it worked.
Now in the another Swift app which uses Cocoapods I have added following in my Podfile
Podfile of Sample App
platform :ios, '9.0'
target 'Cocoapod Test App' do
use_frameworks!
pod 'CocoaPodTestFramework', :path => '/Users/ABCD/Documents/Projects/TEST/CocoaPodTestFramework'
end
Now here the issue comes, whenever I tried to build the app I get
no such module 'Alamofire' in the Referenced framework and in the app it says no such module 'CocoaPodTestFramework'
Having been reading various post/forums/issue since then but unable to figure it out how can it be fixed tried adding pod 'Alamofire' and pod 'SwiftyJSON' in app Podfile as well but still getting the same error.
And also tried adding 'Alamofire' and 'SwiftyJSON' in .podspec (s.frameworks) file of the framework which gives error though.
So I want to know if there is workaround for this or if it is not possible at all?
Read somewhere to use framework project as submodule of the sample app, will this solve the issue?If yes then how can anyone else use this pod if I don't want to share the code I mean without submitting the code only sharing .framework file(Basically Its should like a SDK, source of which I can't share but need to use other pod :P, Even I would like to skip github part searching a way for that as well)
Can anyone help me out of this?
OK...
Here how I have figured it out it may help someone like me...
Podfile
s.dependency "Alamofire"
s.dependency "SwiftyJSON"
The above 2 lines have solved the issue still I don't want to close this thread until I developed the actual SDK to check if this will actually work. :)
I ran through this problem before , I created a dynamic framework that uses pods to accomplish it's process as a chat module , after dragging it to a project it can't see the sub-frameworks and give the same errors you described, finally i figured out that nested frameworks are not allowed in IOS only MACOS ,seems like framework code must be pure code without sub-frameworks to work , wrote a post in Apple forums and they responded like this

Missing required module 'CocoaLumberjack' in iOS 8 app / framework

I'm having a problem with integrating a cocoa pod (CocoaLumberjack in this case) into an iOS app and my own frameworks.
The Podfile looks like this:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, "8.0"
target "CommonModule" do
use_frameworks!
# CocoaLumberjack wasn't officially released with Swift support yet
# pod 'CocoaLumberjack'
pod 'CocoaLumberjack', :git => 'git#github.com:CocoaLumberjack/CocoaLumberjack.git', :commit => '6882fb5f03696247e394e8e75551c0fa8a035328'
xcodeproj 'CommonModule/CommonModule.xcodeproj'
end
I have a hierarchy of modules (dynamic frameworks) like this:
CommonModule
ModelsModule (has a dependency CommonModule)
And finally, the main app:
MySwiftApp (dependency both ModelsModule and CommonModule)
Now, CocoaLumberjack is used in several files in CommonModule and works as expected. However, every time I do import CommonModule in any file in ModelsModule, I get the following compile error:
~/Developer/ModelsModule/ModelsModule/SomeFile.swift:2:8: error: missing required module 'CocoaLumberjack'
import CommonModule
^
Any idea how to solve this issue?
UPDATE: Some people Recommend to use Carthage. I would like to avoid that, if possible.
You'll also need to ensure that CommonModule.framework and CocoaLumberjack.framework (and any other frameworks) are listed in the Embedded Binaries section of your application target.
All the new iOS 8-style dynamic frameworks must be embedded within your app—even those that you aren't using directly, but that are dependencies of your dependencies—so you might end up seeing references to items you don't recognize.
Incidentally, there is a new Swift-based logging engine called CleanroomLogger that might make things easier if you're having trouble interacting with CocoaLumberjack from Swift.
I am assuming that CommonModule is swift and that your also using CocoaPods 0.36 as I see your calling use_frameworks!. I'm also assuming that you're using the Obj-C version of CocoaLumberjack, and trying to use it with Swift. That use_frameworks! flag tells CocoaPods to generate frameworks of the pods for linking in your Xcode project. So you need to say at the top of your class
import CocoaLumberjack
instead of using the Swift-Bridging-Header
Here is the blog post on cocoapods.org where they talk about the how to author a pod for the new use_frameworks! flag. Scroll down to the part Common Header Pitfalls
It could also be that your podspec creates a dependency to use CocoaLumberjack, and when linked to your project CocoaLumberjack and CommonModules, but Common Module is not referencing it correctly in the library. To get past that you need to refer to it as a framework when you import it into your Objective-C library
#import <CocoaLumberjack/CocoaLumberjack.h>

ObjC: Statics are not consistent across multiple frameworks when contained in cocoapod

So my situation specifically uses the Objection dependency injection library. However, I believe this could be an issue for other libraries as well.
Platform
iOS 8.0 Xcode 6.1.1. Cocoapods 0.35. Objective-C.
Set up:
I have 4 projects. 3 universal frameworks and a test app (I'm creating an api). The test app does not utilize cocoapods (though some other app might).
All three of my frameworks need to use injection. I created a pod file that looks like
workspace 'workspace.xcworkspace'
platform :ios, '8.0'
xcodeproj 'path/to/proj/one'
xcodeproj 'path/to/proj/two'
xcodeproj 'path/to/proj/three'
target :Project1 do
pod 'Objection', '1.4'
end
target :Project2 do
pod 'Objection', '1.4'
end
target :Project3 do
pod 'Objection', '1.4'
pod 'SDWebImage', '~>3.7.1'
end
Problem
When I use this set up singletons don't work in Objection. However, they only don't work if they (the singleton class) is defined in project 1 and then I call [JSObjection createInjector]; in project 2 (the projects don't make a difference, it is that create is called in a different project to the definition).
Current theory
After battling with this for a while I believe it is due to the warning along the lines of:
Objection is defined in Project 1, Project 2 and Project 3.
Which one will be used undefined.
So when the class registers itself with the injection system (e.g through objection_register_singleton(ClassX)). It is using the JSObjection definition from its project, which might not be the one being used for a class that injects it (e.g. objection_requires_sel(#selector(myClassXObject))).
Question
I want to be able to use the iOS frameworks setup as, from what I understand, it is better overall than static libs. However, I also want to be able to use Cocoapods (and have any app, that uses my api, use Cocoapods).
How do I either a) share one definition across multiple frameworks or b) setup a framework as a Cocoapod (I've seen that this is being developed).
I would love to be able to keep the frameworks linked through the xcode workspace so when one is built the frameworks it depends on are also built. Though having said that, my api will probably become a Cocoapod at some point anyway.
Thanks in advance (and for reading to here)
Indigo

Resources