Creating a single static library from several dependent projects - ios

I am attempting to create a static library wrapping the SQL Cipher functionality along with all of the associated dependencies i.e. OpenSSL, SQLite and some other wrapper e.g. FMDB.
The problem is the complete lack of documentation from Apple. The example they provide at https://developer.apple.com/library/ios/technotes/iOSStaticLibraries/iOSStaticLibraries.pdf is miserly and useless in all but the most simple of circumstances.
The issue I have revolves around the concept of creating a static library that links to multiple other dependent Xcode projects. I have the following structure in Xcode within a Static Library project:
I have created all of the necessary links etc and utilise LIPO to create a universal binary. The problem is that the output generates a library class for each of the projects so I end up with the following:
I may be entirely missing the point but I was expecting a single entry point library and not the individual libraries.
I have read that Xcode project resources will not be included in the Static Library build and will still have to be handled by the consuming application/project i.e. by adding them individually! Does this rule apply in this case?

Upon further investigation it would appear this is the desired outcome.
To resolve, I utilised the libtool command to combine the libraries.

Related

iOS Reusable components

During my work with development of iOS applications, i noticed that almost every application has some parts that are repeated. For example every application has user management logic, Login, Sign Up, Forgot password.
And every time, i find my self trying to manually import already developed logic (View controllers, nibs, storyboards).
My question is how can i implement these common features in separate component, so i can simply reuse them every time i start new project. Also notice that there should be possibility for small customisations, for example all apps have login screen, but UI design varies for every app.
Long story short, what i need is:
How to encapsulate commonly repeated features in separate component.
How to inject the component in the newly started project.
How to make customizations at the component, without changing the component core.
I guess that here should be made some combination of Framework (Or static library) and cocoa pods, but i wanted to hear if somebody have already developed some concept about this.
Yes, exactly as you supposed, the way I opted for to reuse components is through a static library or sometimes a framework of reusable components, implementing common logic or well structured classes to inherit from in the new projects, which I make available to the new projects as a CocoaPods development pod sitting on my development machine or in a shared git repository. This way should answer your questions 1 and 2. For your question 3, you can either opt to perform customisations to the core dismissing pod updates, or to adapt the core methods to a possible override in the destination project. Hope it helps.
How to encapsulate commonly repeated features in separate component.
Whatever you choose you are going to have to factor out the code your separate component requires from your code base. This is the first step in the entire process - so think long and hard about if it makes sense to turn it into a separate component.
So now you have some code you would like to reuse...
There are a number of ways of doing this, such as Xcode's workspaces, stand alone source files, static libraries and frameworks. Cocoa pods is a package manager and will help you maintain your framework - not write it :(
Xcode's workspaces
A workspace is an Xcode document that groups projects and other
documents so you can work on them together. A workspace can contain
any number of Xcode projects, plus any other files you want to
include. In addition to organizing all the files in each Xcode
project, a workspace provides implicit and explicit relationships
among the included projects and their targets.
Static Libraries
Introduction to Using Static Libraries in iOS
Static libraries provide a convenient mechanism for sharing code among
multiple applications. On iOS, static libraries are the only supported
library type. This document explains how to extract code from your
application into a new static library and how to use that static
library in multiple applications.
Frameworks
In OS X, shared resources are packaged using standard frameworks and
umbrella frameworks. Both types of framework feature the same basic
structure and can contain resources such as a shared library, nib
files, image files, strings files, information property lists,
documentation, header files, and so on. Umbrella frameworks add minor
refinements to the standard framework structure, such as the ability
to encompass other frameworks.
Frameworks are packaged in a bundle structure. The framework bundle
directory ends with the .framework extension, and unlike most other
bundle types, a framework bundle is presented to the user as a
directory and not as a file. This openness makes it easy for
developers to browse any header files and documentation included with
the framework.
Source Files
These are the classes you have factored out of your code base. You could just include them in each project you use them - for instance a separate repo, that contains all of your shared/common code that you add to your Xcode project's workspace. Very simple, not the best to maintain.
How to inject the component in the newly started project.
Depending on how you choose to implement your common code will effect this step. For source files you just need add them to the project and set the target. For frameworks or static libraries you will have to embed them in your project
For workspaces you will add the projects containing the shared code to the main projects workspace.
How to make customizations at the component, without changing the component core.
Again you may find yourself refactoring code so that you expose the UI controls or logic functions that you want to be able to customize. As a general rule the more you expose the more complex the code gets.

iOS Framework build: what is the best practice to link with third-party libraries?

I'm build a Framework for iOS and my framework has AFNetworking as dependency.
So what is the best practice to include AFNetworing? Reading other posts (specially this question here) i came up with three options:
Copy all the .h.m files from AFNetworing in to my project and compile my framework with it. But according to this, it will possible cause a situation where some third part developer using my Framework are already using AFNetworking and will get a compile-time error that some class is declared twice.
Use CocoaPods and link AFNetworking to my Framework. This is causing this error: -lPods is not an object file (not allowed in a library).
Build something like the Aeris SDK where the third part developer using my Framework will be responsibly to add AFNetworking to their project.
I think that option 3 is the best but i don't know how to do that. How can i dev my framework calling AFNetworking classes/methods but do not include on the final framework product?
Thanks!
That's a very bad practice to use third party library in you library.
Ideally you should avoid doing that.
But if you really need it, you can define and add prefixes to class names.
Refer this article Avoiding dependency collisions in iOS static library managed by CocoaPods
Ok. I decided to go with the option 3.
A just added all the header files from any third-party lib to the my framework project (you can also add the .m files but not include them on the static library target).
And a i also documented everything, so developers using my framework will know what are the dependencies and how to include/install them on their own projects (including third-party lib versions, CocoaPods support, etc).
I decided not to go with option 1 because that will cause some situations where a project will have two copies of the same lib compiled on the final app. Even if a change the namespace for the libs on my framework code (to prevent "duplicated symbols" errors) that will still cause some other possible problems like an APP with larger size, possible bugs related to two or more instances of the same lib running together, etc...

Avoiding header conflicts when creating and depoying Static Libraries in iOS

I have created a static library in iOS where I have certain common functionality for my projects. I used the instructions for the iOS Universal Framework and everything works great.
I have a module in the static library that requires AFNetworking. So I installed the cocoapods, and included it in my static library
However, when I include my static library into another project that also needs AFNetworking, and I run the project, I get a duplicate symbol error for all the common classes.
What is the best approach to avoid a conflict like this?
The best approach is not to include any 3rd-party libraries / frameworks inside your framework.
Here's Apple reference regarding "How to build your own framework". There are a lot of guidelines that will help to build a good framework that will not cause any errors if you'll link it to any project.
AFNetworking is a framework that is application specific, so you should not include it into your framework. You may weakly link your framework to AFNetworking, but you should avoid strongly linking it.
Here's resource regarding weak linking.
For example, if you are using 3rd-party library, you should specify that your framework require user to add dependencies in order to use it.
Here's an example how AFNetworking does it.
Also, check this framework, and it's requirements regarding dependencies in its specification.
The best way to do this (in my opinion) is to underscore the class names to keep them unique.
So let's say your library is called XYLibrary. It will have a bunch of AFNetworking files like AFNetworking.h and AFNetworking.m. Rename those to XY_AFNetworking.h and XY_AFNetworking.m. This should hopefully keep them unique from other instances of that library in another project.
You should do this for any other 3rd party libraries as well.

Creating a distributable framework for iOS Applications

I am currently building a library which should be used internally in a few iOS projects but should also be distributed to customers accessing our services with the library. The Library itself consists purely of C++ code and I am basically able to create Apps with it on iOS which work fine. My problem is creating a single, easily distributable file that can be given out to customers which can easily install them, use the provided headers and don't need to have the headaches that I am currently facing when it comes to linking.
Our code depends on two other projects, namely boost and websocketpp. For boost there is the script on github which I took to generate a framework. For websocketpp, I imported it into XCode and used the scripts from this github project to build a framework. I added both frameworks to my (potential) framework as dependencies and used the same script to build one.
I have an app using my library as a sub-project working fine. Even including the framework into the project and running it on a device works fine. So far so good.
However, trying to create an archive of the App project lead to several questions and headaches.
My library did not seem to contain the code for all architectures. So I tried to archive the Framework projects, which after small modifications in the build scripts to use different locations to search for headers worked fine.
It does not seem to contain all binary code or references to local files (i.e. my specific location of boost). I gathered that from Linker errors that I still get that tell me that some boost calls could not be satisfied.
The second issue made me think that I am must be doing something fundamentally wrong and my intuition tells me that it can't be that difficult and "hackish" to create frameworks or libraries for others for iOS development.
As you probably have found out by now, I am not very experienced when it comes to iOS and I am wondering if I am missing something fundamentally. So, I am sure that this question is rather broad, so some more concrete questsions:
Is there a(nother) way to generate some kind of distributable (preferably a framework) which contains: my public headers, my binary code compiled for all platforms supported for iOS development, the binary code of dependencies?
Is the only way to do that by adding some handwritten scripts to the build process?
I have the feeling that the information I found is quite outdated since it's older than a year and mostly refers to Xcode 4.2 or 4.3 -- so has there anything changed in this regard recently?
For example one error I get is:
File is universal (2 slices) but does not contain a(n) armv7s slice: <file>
The <file> slice is the path to the file in the framework in the Products folder of a different XCode workspace (the library was build in a different workspace then the app). I dropped the framework folder into the project for this test from a completely different location.
What is going on here?
Why does it keep referencing to some internal XCode directory?
How do I properly export it?
Since I guess my setup is probably skrewed up and weird from all the different things I tried up to now: How does this setup look like in a ideal situation?
Yes, there are some questions regarding this on SO already, however, either I don't see or don't understand in those replies:
...how to handle depencies of my code to other third-party code properly.
...how to generate a distributable file.
Have you checked your project build phase under Compile Sources and Copy Files to see if you are including your framework source files in your build?
You may also try the C/C++ Library template under OSX -> Framework & Library.
Finally, there's also kstenerud’s iOS Universal Framework, which I found very useful. I wrote a few articles in my blog on using it.

How to use open source iOS libraries without collisions?

I'm writing an iOS library (SDK) and I need JSON decoding support. There are lots of choices, but the problem is upstream collisions.
If I add, say, JSONKit to my library, and another third party library does the same, then the upstream user who wants to use both my library and the other library will experience a collision.
It would appear then that it's impossible for me to add any third party libraries into my library because of the risk of collisions. How can I use iOS libraries as dependencies of mine without causing collisions for upstream developers?
How can I use iOS libraries as dependencies of mine without causing collisions for upstream developers?
Just specify that that third party library is a dependency of your library, provide appropriate links to the project, and any necessary instructions, version info, etc..
If that package/distro is not well-suited for distribution (e.g. they just have a pile o' source files), then create a public project (fork) which includes a proper static library target.
We're having this same issue. Here's my thoughts on how to solve it (perhaps we can figure out a robust solution together). For versioning control, we're using Git:
One option is simply to prefix all classes within your library with your own identifier. In such, even if the class is part of JSONKit, I'd still prefix it with my own identifier ("JG") to get the classname "JGJSONKit.h". In this manner, it's much less likely that a collision would occur.
This method has the drawback that should a third party repository (such as JSONKit) be updated, however, it's more difficult to pull these changes into our library's version of JSONKit.
This may be acceptable, however, if this code is intended to be exported as a static library (as you'd still maintain full control over the code, and you'd be able to manually pull changes to third party repositories and rename them appropriately, if you should so choose to do such in future updates of the static library).
Another option I've considered is using Git submodules. This solution seems to be better should your library be open source (or at least open source to the developers that have access to it -- not necessarily available publicly). In such, developers could choose to simply not include any submodule that they were already using within their own project.
Ideas?
Edit:
Here's the solution that we came up with:
1) We encapsulated our shared code (which we'd written- not a third party) into a project with a static library target and our shared resources (xibs and images) into a bundle following this tutorial:
https://github.com/jverkoey/iOS-Framework
2) We created a Git repository that included said static library and bundle.
3) We forked all desired third party libraries (so we could make changes to them if desired) and also added the original repos as another remote within each forked repo (so that should changes be made upstream, we could easily pull them into our own fork)
4) We added -objc to the "other linker" flags (important) so that all categories would work correctly during runtime.
All in all, the solution is near perfect for us:
We avoid collisions by either hiding the third party libraries (not including them in the public headers but private instead), or we warn that those libraries are used within the project for publicly exposed headers and that developers should not add them again (they can use the already included code instead, which is kept up-to-date via the simplicity of including them via said Git submodule method)
I hope this helps your efforts too!
I had a look at JSONKit and i see that it isn't a Static Library, it is a src file to copy into your project.
All Classes, etc. in your project must be prefixed with your (cough) globally unique two letter prefix, including classes you copy and paste off the internet.
You would be better off if JSONKit was a library. Your library would depend on JSONKit, but not contain it, and it would be up to whoever building an app with your library to make sure JSONKit was also included and linked against - no collisions (although distributing a library that is dependent on other third party libraries that aren't yours to distribute is inherently somewhat tricky).
If other people are pasting this JSONKit file into their libraries and then distributing them you have only two options*
Modify JSONKit.h & .m, prefixing all symbols (you must do this with any code you include as source)
or choose something else (NSJSONSerialization?).
This doesn't mean you can't have third party library dependencies (or that doing so is dangerous), just that copying a source file into your project is not the same as adding a library dependency.
*arghh, ok 3.. you could weak link all the symbols from JSONKit and leave it up to the library user to supply JSONKit.m, but then still the problem is the other libraries..
TLDR.. avoid JSONKit, it isn't suitable to use 'as is' in a library that you want to distribute.

Resources