Embedding Dependency Frameworks into a Single Dynamic Framework - ios

I have this project that is designed to be used as a Dynamic Framework, named ProjectA.framework.
However, ProjectA depends on other dynamic frameworks, such as Alamofire, Realm, and a couple smaller ones. I want to generate a single .framework file that contains all the frameworks embedded, but I'm not sure if it's possible.
Now I have ProjectB, that will use ProjectA as a dynamic framework, and ideally I would like to drag only the ProjectA as a dependency. I'm using Carthage, and it automatically fetches and builds all dependencies, but I'm dragging only ProjectA.framework into the Linked Frameworks and Libraries section.
The projects builds, but gets a runtime error, complaining that one of the third party dependencies was not found.
It is possible to achieve what I am trying to do?
Is this a limitation of carthage or a wrong setup on my side?

Related

set up a carthage/cocoapod project to distribute multiple dependencies

Sorry if these questions are basic/dumb. I haven't had to do any framework setup stuff in the past. I've just contributed to projects in the past. I want to distribute different parts of an SDK with Cocoapods and Carthage. For example,
github "MyOrg/Core" -> Has interfaces I want to use in SmallerModule.
github "MyOrg/SmallerModule" -> Has third party dependencies I do not own
Are there general rules on how to set this up? My Core project would have interfaces that SmallerModule needs access to. Should SmallerModule be a part of the Core project or should they be separate Xcode projects?
Secondly, if it is a separate project, how does SmallerModule have access to the interfaces in Core? Do I need to include it as a dependency in SmallerModule? If so, wouldn't Core be duplicated if someone tried to pull in both Core and SmallerModule since Core is a dependency for SmallerModule?
Should SmallerModule be a part of the Core project or should they be separate Xcode projects
I guess it depends by the granularity of what you need to be exposed. SmallerModule might be separated or merged inside Core, remember that once you expose it, it's quite complicate coming back, eg: you might generate dependencies to other projects.
Secondly, if it is a separate project, how does SmallerModule have access to the interfaces in Core?
If you split the projects, SmallerModule will easily have the access to the interfaces of the Core dynamic framework, the thing you must do first is generate such framework.
Do I need to include it as a dependency in SmallerModule
eg: if you use Carthage as dependency manager, you should create a Cartfile inside the project SmallerModule containing this line:
github "MyOrg/Core"
then on SmallerModule “Build Phases” settings tab, click the “+” icon and choose “New Run Script Phase”, add the following contents to the script area below the shell:
/usr/local/bin/carthage copy-frameworks
Add the paths to the frameworks you want to use under “Input Files”, e.g.:
$(SRCROOT)/Carthage/Build/iOS/Core.framework
Add the paths to the copied frameworks to the “Output Files”, e.g.:
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Core.framework
then after resolving the dependency:
carthage update
You will find Core.framework inside the folder ./Carthage/build/iOS/ so you may drag and drop such framework inside your SmallerModule to be able to compile it.
wouldn't Core be duplicated if someone tried to pull in both Core and SmallerModule since Core is a dependency for SmallerModule
Since you'll be using a dependency manager (eg: Carthage), it won't be a problem. All the dependencies will be resolved (if they link the same version eg: tag x.y.z) by the dependency manager itself during the resolution process (carthage update).
Note that if SuperSmallerModule has to bind your SmallerModule, then assuming everything is fine, must create a Cartfile with:
github "MyOrg/SmallerModule"
and follow the same process, also explained here.

How to re-export a framework and use it in another project in iOS? (Should I?)

I have two projects I'm working on in XCode. Project 2 depends on Project 1, and I want it to be able to use the same frameworks I have embedded in Project 1 (they're Carthage dependencies). I discovered the "Re-exported Framework Names" section in Build Settings, but I'm not at all clear on how I might use it.
What should I put in that field? Just the name? (PromiseKit). Or the filename (PromiseKit.framework)? Or the full path?
How do I then reference this framework in Project 2? Right now I'm getting a build error: framework not found PromiseKit for architecture arm64 and I can't see any obvious way to add that framework link.
And a broader question: do I need to do this? I'm a relative newbie and working on the assumption that setting up separate Carthage dependencies for both projects means that there will be two separate compiled frameworks in my final binary, which would be a waste. But is XCode cleverer than I think and taking this into account?
If the two projects are related, put them in the same Xcode workspace and then you can share the frameworks between the two.
If the projects are independent, put the frameworks into a separate folder, add them separately to both projects and when adding them to the projects, don't choose Copy files if needed.

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.

Split a big swift project to frameworks with core framework and module frameworks

I'm trying to split my large Swift framework to many module frameworks so every module in my application will be independent in order to reuse on another apps.
Due to the fact that I have a big data like classes and libraries that shared with all of the modules I thought to create a core_framework contains share data and enforce the app to use this framework in order to enable use all the other frameworks (one or more)
I saw an example of FBSDK there is a core framework and other functionality frameworks : FBSDKCoreKit and FBSDKLoginKit
This is important to me that all the other frameworks will not contains the core framework for reasons of efficiency.
My question is - after creating the core framework what I have to do in my nodule framework so it's will recognize the core classes and functionality but will compile with out the core's files?
Thanks
When you split up a project into submodules, what you have to do is quite simple, though some details depend on how you partition your project.
Easiest case: 1 project with N targets
Say you only work on this one app and split it into modules. The easiest way is to add more Framework Targets to the project.
You then need to embed them in your app target. Make sure it's part of both "Embedded Binaries" and "Linked Frameworks and Libraries".
Now you have a new framework module.
Create a couple of them ("Core" and "Module 1", for example). Then:
In "Module 1"'s General project settings, add "Core" to "Linked Frameworks and Libraries". There's no embed option for frameworks, as they cannot include libraries, only the dependency on them.
In the app target, embed & link "Module 1".
That's all you need to set up.
I tried to diagram the embed and link settings so you see that only the app target contains the other frameworks:
Slightly more complex: multiple projects
The basic setup from above applies to all other variants: frameworks (modules) can depend on other frameworks, but they cannot ship with them. Only the application can finally resolve the binary file dependency.
If you split your project into multiple sub-projects, e.g. extracting deployable open source libraries for other people, then you have to make "Module 1" aware of "Core" in each project, linking to the "Core" module the same way as detailed above. What makes isolated Xcode projects a bit more complicated is: how does the "Module 1" project know about the Core.framework?
You could expose each module via Carthage and depend on one from the other,
you could use CocoaPods,
you could check out dependencies via git submodule.
The options above keep each module project autonomous. Dependencies are part of the directory tree of a module.
A bit less orderly:
You could create a Xcode workspace, drag all projects inside, then drag the Core.framework from the "Products" group of one project to the "Linked Libraries" list on another, or
drag the Core.framework file from the Finder onto the "Module 1" project (optionally selecting "Copy files if necessary" to put the resulting binary into the "Module 1" directory tree).
The above options can work, too, but they form assumptions about the location of files in the file system. The workspace approach should help to reduce problems with outdated framework binary files, though, as the workspace can help create formalize build dependencies from inter-project dependencies. Just like the app target depends on its framework targets, and like test targets depend on the app target to be compiled first.

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).

Resources