I have an existing iOS app and want to add a large chunk of code that I've been developing as another project just for ease of testing. The new chunk basically deals with saving an image to various sharing services, etc.. Because that sharing code needs a lot of testing and future updating, I was wondering what the best way to incorporate that code chunk into my existing app.
I don't know if it should be a static library, dynamic library or a framework, and honestly, I'm not really sure what the difference is, or how I should go about it and get it set up in Xcode.
All I know is that I need/want to keep a separate testing and updating app for the sharing code and have the main app use it.
First, some general definitions (specific to iOS):
Static library - a unit of code linked at compile time, which does not change.
However, iOS static libraries are not allowed to contain images/assets (only code). You can get around this challenge by using a media bundle though.
A better, more formal definition can be found on Wikipedia here.
Dynamic library - a unit of code and/or assets linked at runtime that may change.
However, only Apple is allowed to create dynamic libraries for iOS . You're not allowed to create these, as this will get your app rejected. (See this other SO post for confirmation and reasoning on such).
Software Framework - a compiled set of code that accomplishes a task... hence, you can actually have a static framework or a dynamic framework, which are typically just the compiled versions of the above.
See the Wiki on Software Framework for more details.
Hence on iOS, your only option is basically to use a static library or static framework (the main difference being that a static framework is distributed as a compiled .a file most often, whereas a static library may simply be included as a subproject - you can see all of the code - which is compiled first and its resulting .a file used as a dependency by the project).
Now that we're clear(er) on these terms, setting up a static library and supporting media bundle for iOS isn't too difficult, and there are many tutorials on how to do such. I personally would recommend this one:
https://github.com/jverkoey/iOS-Framework
This is a pretty straight-forward guide and doesn't have the disadvantage of dealing with "fake static libraries"... check it out for more info...
Once you've created your static library, it's as easy as including it as a submodule within Git for use across different projects.
Good Luck.
EDIT
Regarding a subproject within a project, as far as I know, to get this to work/compile correctly, you essentially have to set up a compile chain where the subproject is compiled first, which creates a static framework .a file that is used as a dependency by the project.
Here's another useful tutorial which talks about this:
http://www.cocoanetics.com/2011/12/sub-projects-in-xcode/
EDIT 2
As of iOS 8, Apple now permits developers to create dynamic frameworks! (Note: your app must have a minimum target of iOS 8 to include a dynamic framework... back porting isn't allowed.)
This has been added as a new project template. In Xcode 6.1, this can be found at:
New Project -> iOS -> Framework & Library -> Cocoa Touch Framework
Mach-O file format(Mach Object - .o)
In iOS world every source file is converted into object files - ABI[About] Mach-O file[About] which will be packaged into a final executable bundle(application, framework), file (library) and it's behavior is determined by Mach-O type[About]
Package is a directory which behavious itself as a file - opaque file. It is created for user experience to complicate making some changes into internal structure that can cause unpredictable program behaviour. Package is used in Document Package or with a Bundle. You can use Show Package Contents in a Finder
Bundle is a directory with a specific structure to organize a binary(executable code) and resources for that code(e.g. images, nibs... Assets.car file[About]).
Bundle contains Info.plist[About] file. Bundle was created for developer experience. Also it can be packaged. There are several types of bundle:
application bundle - Application target
framework bundle and versioned bundle as a subtype - Framework Target
loadable bundle(aka plug-in bundle) - '... Bundle' (UI Testing Bundle, Unit Testing Bundle) - can be loaded at runtime. .bundle extension for Mac OS
[Mac OS] XPC Service - Cross Process Communication is a kind of Inter Process Communication (IPC). It can be used as a module on a different process(managed by launchd root process)[About]
others(dSYM[About] bundle)
Application - .ipa, .app[About] - packaged application bundle - launchable program.
Application extension[About] - from iOS v8 - extends functionality of Application which are available when user interacts with other application. App extension as a bundle is a part of Containing app but it is run on their own sandbox(processor, memory...), app which try to use app extension is called Host App. Types of extension app:
Action
Share
Photo Editing
Today aka widget
...
to share common code and resources. It's available when Deployment target is iOS 8+.
Tests - packaged loadable bundle which is used to test a binary. Plug-in architecture allows us to add a new functionality(test cases) as a separate module into existing binary
Libraries and Frameworks
[Library vs Framework]
Martin Fowler on InversionOfControl
A Library is essentially a set of functions that you can call, these days usually organized into classes. Each call does some work and returns control to the client.
A Framework embodies some abstract design, with more behavior built in. In order to use it you need to insert your behavior into various places in the framework either by subclassing or by plugging in your own classes. The framework's code then calls your code at these points. The main control of the program is inverted, moved away from you to the framework. This phenomenon is Inversion of Control (also known as the Hollywood Principle - "Don't call us, we'll call you"
Libraries and Frameworks on iOS
They can help you to solve: modularity, reusing, encapsulation, improve build time
Library is a collection of Mach-O object files[check static or dynamic] compiled for one or more architectures.
Static library - .a(aka static archive library, static linked shared library[doc]) - When you add it into your application the static linker during compilation time will merge the object files from the library and package them along with the application object files into one single executable file. The disadvantage is a big output file
From Xcode 9.0, Swift static library is supported.
Dynamic library - .dylib(aka dynamic shared library, shared object, dynamically linked library[doc]) is dynamically linked with the app's executable at load or runtime, but not copied into it. On practice app's package will contain Frameworks folder with .dylib file. All iOS and macOS system libraries are dynamic. The disadvantage is a slow launch time since all dynamic libraries should be copied and linked.
[iOS static vs dynamic library]
[Static vs dynamic linking]
Text-based stub library - .tbd[About], it is a text stub of dynamic library which is located on a target device. As a result you should not package a dynamic library into your bundle. It has a size effect.
Framework aka binary framework - .framework is a not packaged framework bundle(to allow developers to easily take a look at headers and resources) which contains a compiled static or dynamic library, header files and resources.
Static framework contain a static library packaged with its resources.
Dynamic framework aka Embedded framework - from iOS v8 - contains the dynamic library and resources. In addition to that, dynamic framework can include different versions of the same dynamic library in a single bundle (versioned bundle). Also Embedded framework is used in App Extension
[Static vs dynamic framework]
Umbrella framework [Aggregate target] is a framework that contains other frameworks. It is not officially supported on iOS and that is why it is not recommended for developers to create them[Official doc]. In actuality it's a set of sub-frameworks(or Nested Frameworks). When you create a framework which has a dependency, a consumer (such as an app) is responsible for adding this dependency along with your framework into the project. As a developer, it's natural to try to find a way to transfer this duty from consumer to your's. As a result you think that Umbrella framework is the rescue but usually it leads to a serious issues with managing versions and complexity of creating and supporting it.
Fake Framework - is a result of specific operations under a static library to create a bundle with .framework extension that will behave yourself as a dynamic framework. This technic was used when Xcode did not support creating a framework since did not have a framework template. One of realisation of a fake framework. With Xcode 6, Apple has added iOS framework support.
Modular Framework[About] - #import it is a framework which contains a .modulemap file inside. Module can contains submodules. The main advantage is that you save a build time with Modular Framework.
Universal Library or Framework (aka Fat) [lipo] [Aggregate target] contains multiple architectures. For example your release build should support a some arch which you can regulate via Build Active Architecture Only [ONLY_ACTIVE_ARCH]
XCFramework[About] was introduced by Xcode 11 and it is a bundle which includes multiple architectures(arm, x86_64...) and platforms(iOS, MacOS...). It should replace a Universal Framework
Dependency[About] You are able to use third party code as a part of your target. It allows you to reuse a code from a lot of sources like - another project, project in the same workspace, another target, library, framework etc.
How to build and use a Static Library:
[Swift consumer -> Swift static library]
[Swift consumer -> Objective-C static library]
[Objective-C consumer -> Swift static library]
[Objective-C consumer -> Objective-C static library]
How to build and use a Dynamic Framework[change to static]
[Swift consumer -> Swift dynamic framework]
[Swift consumer -> Objective-C dynamic framework]
[Objective-C consumer -> Swift dynamic framework]
[Objective-C consumer -> Objective-C dynamic framework]
[Xcode Build System]
[Xcode components]
[Dynamic linker]
You can also create .podspec file for CocoaPods( http://guides.cocoapods.org/making/private-cocoapods.html#1.-create-a-private-spec-repo ) and use it like any other pod with the only difference that it's your private pod and is not visible to outside world(I'm not sure what will happen if your pod should create CoreData model, but that's not the case, as I understand).
Related
I have read many articles about static/dynamic library/framework. So my understanding is (let me know if it's inaccurate):
Framework = Library + Bundle
Static = Linking at build time
Dynamic = Linking at run time
In Xcode, we have "Static Library" and "Framework". Which raises a few confusing points:
Why there's no "Dynamic Library" option?
Given that we can already link framework statically, why do we still need a "Static Library"? (isn't StaticFramework = StaticLibrary + Bundle? )
Why there's no "Dynamic Library" option?
Because Dynamic Library is not permitted for iOS apps at beginning.
Given that we can already link framework statically, why do we still need a "Static Library"? (isn't StaticFramework = StaticLibrary + Bundle? )
Because old Xcode only support Static Library.
Static Framework was added later, and they keep the Static Library.
There are many concepts that must be clear
Libraries have two categories based on how they are linked to the executable file
Static library .a, .so. link at compile time. wiki
Dynamic libraries .dylib .dll etc. link at runtime. only apple can use it for iOS for some safe reason, we cannot build this.
ps, a special kind in apple platform
Text Based .dylib stubs — .tbd
Framework
Framework is a package that can contain resources such as dynamic libraries, strings, headers, images, storyboards etc.
vs Libraries, Framework has more features
Framework also has static and dynamic
iOS 8 later, we can use a dynamic framework, why Apple releases this. maybe Extension and App share code
this Dynamic Framework for iOS is named embedded frameworks, because when we build the app copy the framework in app bundle.
so the embedded framework is different from system dynamic Frameworks like UIKit.Framework
Why there's no "Dynamic Library" option?
the embedded library is allowed with the Framework option, but dynamic framework shared in muti app is also not allowed
Given that we can already link framework statically, why do we still need a "Static Library"? (isn't StaticFramework = StaticLibrary + Bundle? )
well, Xcode not only support Objective-c and Swift, but also support C, C++ which may use the static library
Trying to prepare a single dynamic framework to my customer. My framework (A.framework) uses third-party recognition static framework (B.framework). I can't provide separate A and B frameworks to the customer.
Ideally B.framework should be built and included into my A.framework's binary, so the customer's app will only embed A.framework without any additional actions to link with that third-party app.
What I did:
Added B.framework to the project.
Added B.framework to "Linked Frameworks and Libraries" in the corresponding target.
Built A.framework.
Created a demo application and included A.framework to the project.
Added A.framework to "Embedded Binaries".
Demo app's build fails with message "Missing required module 'B'" (despite the fact that it is used in A.framework only).
Note:
I neither created any modulemap files for B.framework, nor additional run scripts
Making A.framework static is not acceptable because it includes some resources (storyboards, icons and some other files)
Tried to make un-recommended "umbrella" framework but got stuck on loading B.framework's bundle in demo app
Tried to make fake "umbrella" framework by simply copying B.framework inside A.framework, but got 2 problems - huge size of A.framework and Mach-O error while exporting the demo application (because of Mach-O difference between dynamic A and static B frameworks)
Any ideas would be highly appreciated!
UPD 1: This is not about umbrella framework because the proper umbrella framework implementation requires to load sub-framework from bundle which is not good. The fake framework implementation (sub-framework simply copied to umbrella) won't work for release because of different Mach-O values - dynamic and static. Plus fake umbrella framework has a huge size because sub-framework is being fully copied inside umbrella.
UPD 2: Created a small test project: StaticFrameworkTest which has 3 sub-projects:
Demo-application with dynamic framework dependency (framework A) and shouldn't know anything about framework B
Dynamic framework with static framework dependency (framework B) which ideally should be included in A framework's binary.
Static framework B
A static framework is by definition a fat static library combined with any additional required resources. As such you can embed your third party static library inside your own and also include images, storyboards, plist etc.
You can't do that in a static library (i.e. *.a), but in a static framework you can do.
See for example https://www.raywenderlich.com/65964/create-a-framework-for-ios for details on how to do that (at the end of the article it creates the static *.framework out of the static *.a and some resources)
A dynamic framework can never embed a third party static library. The main application that imports the dynamic framework will always have to also explicitly link against the static library, which it seems that is not what you want.
I'm a novice on XCode and I'm making an iOS Framework with Swift2, including 3rd party libraries(*.a) and frameworks.
I want to provide it as API to others, but I also want to hide the 3rd party libs and frameworks files from my framework distribution files because they are private.
Therefore I just want to open API interfaces and classes I defined.
Is it possible? How to configure my build options?
You can do that but there are some things you need to consider:
You cannot embed one framework into another one. That means if you do not have the sources to a particular framework you have to ship it alongside your own framework. If you have the sources you may consider compiling them into your framework directly.
Depending on the sources that you use in the framework you might have to do some post processing of the framework to obfuscate private headers etc. For example, if you use Objective-C or C code alongside Swift you definitely need to do some post processing of your *.framework file to hide any API that you want to keep private.
If you use Swift code in your framework please be aware that your framework can only be used by someone with the same Swift compiler version due to the absence of an ABI. That means binaries produced by one compiler version have a high likelihood of being incompatible to a newer version of the compiler.
Static linked libraries can be linked and therefore "merged" into your framework binary directly. You just need to make sure that you have a compatible binary for the architecture you want to target, e.g., you cannot use a static linked library that was build for simulator and link it against your framework that you want to build for the actual iOS device.
If you use Swift in your framework, the users of your framework need to include the Swift dylib libraries in their app bundle - either by using Swift in the app or by enabling the Embedded Content Contains Swift Code build setting.
Up until iOS7, Apple did not support dynamic linking due to security concerns. Code reuse between developers usually relied on static libraries, which were built as part of the executable of the app.
Introducing extensions in iOS8 seems to change this a bit, because extensions are separate executables. Sharing code between an extension and its containing app is done via a framework. Apple is saying this in their release notes:
Frameworks for iOS. iOS developers can now create dynamic frameworks.
Frameworks are a collection of code and resources to encapsulate
functionality that is valuable across multiple projects. Frameworks
work perfectly with extensions, sharing logic that can be used by both
the main application, and the bundled extensions.
Emphasis is mine.
Source: https://developer.apple.com/library/content/documentation/Xcode/Conceptual/WhatsNewXcode-Archive/Articles/xcode_6_0.html#//apple_ref/doc/uid/TP40014509-SW14
Further, in the extension dev guide, they explain that you can share code between an extension and the containing app via a "embedded framework".
Source: https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW1
My question is - what is an embedded framework, how does it differ from a dynamic framework, and will we really see proper dynamic linking in iOS8? All the documentation I've read seems ambiguous about this.
"Embedded" and "Dynamic" frameworks don't refer to the same aspect of frameworks. They are not the opposite of one another. First, let's define what's a framework: in Apple lingo, a framework refers to some compiled code + the public headers of said code.
Now a dynamic framework is a framework whose code was built as a dynamic library. It is the opposite of a "static" framework, where the code would be built as a static library. In case you're wondering, Wikipedia has a very nice explanation of what's the difference between a static and a dynamic library.
And finally, an embedded framework is a framework that is packaged within an app, as opposed to being installed system-wide, in "/System/Library/Frameworks" for example.
An embedded framework is simply one that's included in the app bundle, rather than a global framework which is installed in system directory.
Dynamic Frameworks doesn't means dynamically linked framework. Apps still just work in a sandbox environment. It's not like your custom frameworks are going to be installed with the iOS. Each one of your apps that uses the common framework that you've developed is going to be copied inside every app's bundle.
You can see this for yourself. Go to your Xcode's Derived Data directory and inside the app's data, you'll find all the embedded frameworks copied.
The only new thing with creating Frameworks with iOS 8 compared to static libraries is that the public header files and assets gets bundled within the Framework. If you've been doing this sort of things with earlier versions of Xcode, you'll remember the pain with supplying public headers and then adding the search path within Xcode settings and for assets we had to pass in a separate bundle.
This only downside of using Frameworks that I see is that now we can't simply use lipo to generate a fat static library for all kind of architectures.
IMO Apple is using the word 'dynamic' to suggest 'independent'.
Watch WWDC2014 - Building Modern Frameworks for more details.
I have application separated into library part and the Application which links with the library.
Library uses AFNetworking, and thus requires SystemConfiguration and MobileCoreServices frameworks. They are added to build process and library builds nicely.
Why I need to add the same frameworks to my the Application part in order to build properly and not to see linking errors?
Is it not enough to link only with library?
I assume the library is a static library. You are only adding the frameworks when building the static library in order to access the include files; you are not linking with the frameworks. This is because a static library is not linked when it's built; it's simply a collection of object files. Try this from the command line to list the object files:
$ ar t /path/to/my/library.a
When the static library is linked with the app binary you must provide the libraries and frameworks of both, just as if the object files in the static library had been part of the app binary source tree.
Just think of the static library a simple collection of object files and it should make sense to you.
Apple's iOS frameworks contain dynamic shared libraries. AFAIK, when our app launches there is a process which gets created and dynamic shared libraries that the process is linked with gets loaded in to the memory. If the dynamic shared libraries are already loaded in the memory(for some other app process), they are shared with our app process. This is per process activity.
Since the static library is linked as part of the application binary itself and does not create a separate process, it becomes necessary to inform the runtime to load the frameworks that the static lib links with. Hence it is logical to add the frameworks used by static library in the application as well.