Can you make a Podspec with conditional dependencies? - ios

I want to know if you can define dependencies on an static lib in a podspec depending on the type of the Target that the Pods project is going to be linked to.
I need to be able to NOT add a dependency to an static lib if the target project is itself an static lib.
Why I need this?
I've built a podspec for cocos2d-iphone v3 and using it in a personal pet project. Works perfectly when you use it as a dependency for an executable. Unfortunately it doesn't works well the way I've organiced my project:
It's a multiplatform project app consisting in two xcode projects for the ios and osx executables. Both link to an static library with shared code (another xcode project). I've made the cocos2d a dependency for that last static library.
Unfortunately, cocos2d has a dependency over lib z, which is also static. As you can't link two static libraries the link phase fails. The error message is as follows:
file: -lz is not an object file (not allowed in a library)
It's easy to remove that dependency but I would prefer the process to be more easier for the end user.
My approach to solve this problem would be add a conditional in the podspec so the lib z only is added if the project is not an static library. I guess it can be done with pre_install hooks, but they are discouraged by the cocoapods team.
Is there any other way to accomplish this?

Related

Is there a work around for CocoaPods mutually exclusive frameworks vs static libraries in Swift?

CocoaPods requires that either all dependencies are frameworks or all dependencies are static libraries. It is not supported if you mix these two within the same workspace.
Is there any work around when you find yourself wanting to depend on Pods of both types?
I understand that I could just bring the code into my project, but this is pretty annoying, given numerous transitive dependencies and projects that are so reliant on CocoaPods that they do not have .xcodeproj files to drop in.
Is it possible to create a framework project that uses static CocoaPods libraries and expose that as a private pod?
Are there any other work-arounds?

iOS dependency management and packaging

I'm completely new to iOS development and coming from an Android background. I was starting to look at what alternatives are out there for dependency management in iOS and found out that CocoaPods seems to be the most prevalent option.
After reading a lot of links about this topic I'm kinda at a loss and wondering what is the usual way dependencies are handled in iOS.
I have two questions:
1) What would the equivalent of using gradle to generate library (.aar) projects be in iOS? If there's any equivalent option. From what I've seen one can wrap static libraries and headers into frameworks and these can be used in other apps, is this the standard way to do it?
2) If (1) is correct, does CocoaPods offer a mechanism to add frameworks as dependencies?
I don't have a Android background but from what I understand of .aar files CocoaPods does something very similar. CocoaPods uses .podspec files (described here) to generate static libraries (and soon dynamic frameworks which are new in iOS 8) that are then linked into your project.
A podspec can define source files, assets, libraries, or frameworks that a source vendors for linking into your application. So yes it does support adding frameworks as dependencies, although until iOS 8 frameworks were not supported at all on iOS.
As far as the 'standard' way to do it, I think that's based on opinion. There are a few general ways to include dependencies you can choose from.
Drag files, frameworks, and whatever else you need into your project manually. Updating these is more difficult and that also means you have to configure your .xcodeproj depending on what features that library needs (such as ARC)
Drag a provided .xcodeproj into your project, and link the relevant target from the given project. This can be nice if the library provides a project that can build a framework or static library, in this case you'd pull in that library but their project would handle custom compiler flags.
Do either of the above while including them as git submodules. Assuming nothing massive changes in the project this helps a lot with updating your dependencies.
Use CocoaPods. CocoaPods will handle all the custom linking and updates based on semantic versioning (usually).
Use Carthage. Carthage is an in- between CocoaPods and the .xcodeproj solution. It will download code based on semantic versions defined by git tags, then you drag the generated frameworks into your project.
All of these options have pros and cons and the decision normally comes down to how you feel about the control you have over the inclusion of the library, and how automated you want it to be.
I do not have android nor iOS background however I've been developing a CI tool for both platforms and here are the answers
As You mentioned this a framework and pods (libraries) from cocoapods are distributed that way. For instance, have a look at Apphance. When spec is clicked it's visible that this library will be accessible as a Apphance-Production.framework.
You add pods to Podfile and download them with pod install command. This command will made classes from Apphance accessible from the code. Some people do commit downloaded pods, other not (it's like adding jars or aars to source control).

handling dependencies for iOS Framework project

I've created iOS Framework project using this method: https://github.com/jverkoey/iOS-Framework
Works pretty neat but I'm a little confused on how to include libraries/frameworks that are needed by my framework to work and, in particular, how to do it so that in case 3rd party client app that uses my framework can include these libs as well without conflicts.
Let's say my framework code needs these two things:
FacebookSDK.framework
libFlurry.a
The first one is an iOS Framework. When I add it to "Link Binary With Libraries" phase in my Framework and try compile the client project that uses my framework the linker complains about missing symbols - I need to add FacebookSDK to the client project which is great: there is no possibility of conflicts if client apps wants to use Facebook.
However when I do the same with Flurry static library I get duplicate symbols error when compiling client project. Which confuses me a bit, because isn't FacebookSDK.framework just a packaged static library?
ukaszs-iMac:FacebookSDK.framework lukasz$ file Versions/A/FacebookSDK
Versions/A/FacebookSDK: Mach-O universal binary with 3 architectures
Versions/A/FacebookSDK (for architecture i386): current ar archive random library
Versions/A/FacebookSDK (for architecture armv7): current ar archive random library
Versions/A/FacebookSDK (for architecture cputype (12) cpusubtype (11)): current ar archive random library
So my questions are:
why a library embedded in framework (like Facebook) is not linked to my Framework project product, whereas library included as .a file is?
how to include .a file in my framework so that it does not produce duplicate symbols error when client app using my framework also needs this particular static library?
For the use case you are describing, you should be linking to these external libraries from your application, NOT your own framework. It can be one or the other, but it can't be both.
If you decide that these dependancies belong as the responsibility of the application, you would remove them from "Link Binary With Libraries" and any other explicit linking configuration, and just project your framework project with the path to these frameworks and libraries so it can find the symbols (but not link against them) at compile time (i.e. the path to the libraries should be included LIBRARY_SEARCH_PATHS).
Use cocoapods , it's easy (http://cocoapods.org/)
Your application developers will have to include the podfile and download the dependencies.
While developing your SDK use a reference application/demo app on top of the SDK to simulate this.
You shouldn't link anything when building your framework but just create a *.a binary with your framework's objects.
Also you should not include code from other libraries in your framework as client applications may be adding the same libraries directly or requiring different versions of them, thus creating conflicts.
Off course you can reference *.h header files from other libraries in your framework in order to compile your objects.
As a result the installation steps for your framework should detail other required frameworks/libraries needed, their supported versions, how to add resource files (if any), etc. Just some of the many reasons why you may want to consider Creating a CocoaPods' podspec instead.
You should use CocoaPods. Your dependency on Facebook can be done by linking against the CocoaPod.
If you want to include that particular version of Facebook in your pod, you can put it in your repo and use the vendored_frameworks property to refer to it.
Similarly if you wanted to vendor libFlurry.a, you could do so using s.vendored_libraries.
For system libraries, you don't need to vendor them, e.g. libZ.a.
I strongly recommend creating your CocoaPod using pod lib create YourPodName. They've recently changed the mechanism for how this works and it's really nice.
You can create an Example project that shows how to use your code in context of an app.
Then one of the other neat things I just learned about, someone can do pod try YourPodName and it will automatically download, integrate and run the Xcode project.
CocoaPods is worth the trouble.
I am building my framework project using CocoaPods.
The framework uses some 3rd libs from CocoaPods.
Podfile specifies to install dependency on target of the framework.
When I build the framework, it includes all libs in the binary.
If I add use_frameworks! in Podfile, when the framework is built, it will not include 3rd party libs.
Use CocoaPods dependancy manager. Here's a good guide,
7 miniute video tutorial
Mostly if you install third party frameworks you can install with cocoapods (which is really nice, I would definitely do that) or they offer you to download the framework and include it in your Project.
If you decide to download the library and include it there is normally a list of frameworks you need in the "Getting started" guide.
Means: Offer them to install using cocoapods and to download your library but do not include anything else, give them a list what they need.

Creating static library which depends on other static library (RestKit)

I followed the following tutorial to create a static library:
https://github.com/jverkoey/iOS-Framework/#developing-the-framework-as-a-dependent-project
It all works until I try to incorporate the RestKit into my static library. There I am completely lost. Am I supposed to include the RestKit library into my static library or only in the App which will use my library?
If I don't include RestKit in my library, I can't compile it as it depends on another library (RestKit) so what would be workaround for this?
I tried to look everywhere but haven't found a good step by step tutorial to create a static library which itself depends on other static libraries.
What I did to get this working was to add RestKit to my static library using their git-submodule instructions here. Then I performed the exact same steps on the projects that were going to use my static library EXCEPT:
I did not add RestKit to the "Target Dependency" section of the Build Phases
I did not add the libRestKit.a to the "Link Binary With Libraries" section. All other references still needed to be added.
I was then able to reference RestKit in both my static library and my iOS project.
COCOAPODS MEGA HACK
I was able to get this working with cocoa pods, but it will only work if this is your only cocoapods project. I started with all of my projects in a single workspace. Then I had my single podfile install RestKit to my static library and all projects that were going to reference my static library. Then for each project that I wanted to reference my static library I removed the pod reference under "Linked Frameworks and Libraries". Everything was then working as expected.
As you can expect, this would probably break all other pod references (unless you managed them all through that one static library), but it does seem to work.
Shorty after asking the question I finally managed to get it working here the steps if someone has a similar problem:
Create an actual app as explained int this section. After adding your library add all the other libraries you use to the application. (In my case it was the RestKit framework, add it as a submodule and not with cocoapods as with cocoa pods it didn't manage to get it to work properly).
After adding all your libraries, follow the third party libraries instruction for modification for the application and make the same modification for your static library.
e.g. for Restkit I had to add
-ObjC -all_load
to the Other Linker Flags and add
"$(BUILT_PRODUCTS_DIR)/../../Headers"
to the Header Search Path inside my static library.
I still couldn't build as the <RestKit/Restkit.h> wasn't found, so I needed to change the build order of the frameworks to assure that Restkit was built before my library.
This is done inside the edit Scheme of the build menu. Make sure that all the dependent libraries are on top of your library (if your static library or the dependent libraries aren't already in there add them with the '+')
Afterward everything worked for me. I am not sure if this is the best method to do it or if it would be better to include the third party library inside your statistic library.
Update I still run into problems when trying to build my library, if someone has a better solution or can shed some light on how to create a static framework which depends on other frameworks I would appreciate it.

How to create a PodSpec for a project with a static library target?

I have an Xcode project (foo) which builds a static library (libfoo.a) with some important pre/post build steps. Traditionally, when I use this library in another project I add foo.xcodeproj as a subproject in my main project, and then hookup the build dependency settings in the main project.
I'm looking to make this easier with CocoaPods, but I'm not sure it's designed for this. Am I supposed to copy the build settings out of the foo project into a pod spec, so that CocoaPods can build it the way it wants? What about my pre/post build steps?
There is info on creating Pods for closed source pre-compiled libraries like the TestFlightSDK, but I don't want to precompile my library.
Using the pre_install hook (0.17 docs with a minor change in syntax) you can perform any build action that you need.
The usage of this hook is not encouraged in the master repo, however for private specs it is supported.
With Cocoapods you don't need to be concerned about the target, per se. It makes a new project with all the source files from your library and creates a single libPods.a which includes all Pod dependencies.
If you create a Podspec with the correct source_files and public_header_files, it should just work.
Could use the prepare_command hook(documentation) and in it alter your Xcode project using the ruby gem xcodeproj(xcodeproj site) which is used by CocoaPods. I'm not sure, but is probably possible to add build scripts with it.
Not sure whether this is accepted or not for podspecs in the public repo.
Seems like there's already answer for you:
Create podspec to ship static library
There are both ways revealed (As an .a + headers library, or as a .framwerork)
Think .framework is a preferred way to share.

Resources