As in the Appole doc
it states that:
If you are building your own static library and using shell scripts to
package it in a .framework directory, you need to migrate to building
a framework with a dynamic library instead, as this is the correct way
to build a framework. Static frameworks are not a supported way of
sharing static libraries.
Why Apple disallows static library in a framework?
And is it a contraction of this post ?
Or maybe that post confuses static library and static framework?
All frameworks in iOS are dynamic, right?
Apple said:
A framework is a hierarchical directory that encapsulates a dynamic library, header
files, and resources, such as storyboards, image files, and localized
strings, into a single package. Apps using frameworks need to embed
the framework in the app's bundle.
A static library has to be loaded when app launches, without considering wether if its required right away or not. At the other hand a dynamic library is loaded only when it is required, hence improving the launch timings of the app and decreasing the memory pressure of the phone.
As an example consider I am using an e-commerce app which also allows to scan barcode and give details about the products. Now when I launch the app, I won't need the barcode functionality rightaway. I need to land inside the app first and start shopping. When I need to scan some barcode, I am happy to wait and let the framework loaded then but not at the start of the app.
Here is how Apple says this in its documentation:
Two important factors that determine the performance of apps are their launch times and their memory footprints. Reducing the size of an app’s executable file and minimizing its use of memory once it’s launched make the app launch faster and use less memory once it’s launched. Using dynamic libraries instead of static libraries reduces the executable file size of an app. They also allow apps to delay loading libraries with special functionality only when they’re needed instead of at launch time. This feature contributes further to reduced launch times and efficient memory use.
Documentation link: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/OverviewOfDynamicLibraries.html
Related
I have main application target. And I'm moving some code into frameworks to reduce compile time of the huge project.
Default framework type is Dynamic (BuildSettings -> Mach-O Type). I understand benefits of using Apple's dynamic frameworks as several apps will use the same framework and each application size will be lower (because the app size doesn't include this dynamic frameworks).
But if I'm using my own frameworks and only in my application, why should I choose dynamic frameworks.
It looks like the app size will be bigger with dynamic frameworks Source and application start time will be longer (because it needs to connect all these dynamic libraries, but with static they are already a part of app executable).
App store size probably will be bigger as well with dynamic frameworks as well.
Would be helpful if somebody can fill me in what benefits can we get using dynamic frameworks 🤝
Your assessment is mostly correct.
It is possible to not directly link against frameworks, but instead load them on demand with dlopen.
This can be used both for a plugin system where only one of many available libraries will be needed, or to defer the loading of particularly heavy frameworks, which would actually reduce the launch time of your app.
Further reasons I can think of for using dynamically linked frameworks are:
Licensing reasons.
If you're developing a closed-source library for other developers to use, then a static library normally has a lot more information still embedded than a dynamic library and with a static library you can easily conceal the fact that you're using it, both of which you might not want.
If you have symbol clashes (e.g. due to linking against a static library multiple times, as might be the case with the Rust standard library), then you can split the different codebases into frameworks in order to separate the namespaces.
I feel weird about difference between advantage of dynamic linking library in Window or Linux and iOS.
⬇️ sentences below are to prove why I feel weird.
I learned that library can divided into static library and dynamic library
Advantage of using dynamic library is allow other application to use same dynamic library ( in Window, .dll file) so that each of application memory usage can be reduce and it can be easiar to redistribute dynamic library rather than to redistribute application.
Actually I could have experienced "there is no XXX.dll file" in using some applications
And in Xcode, when to create new project, we can choice framework and static library in framework & library.
And after creating project, we can choice how to being what Mach-O Type is like "Executable, Dynamic Library, Static Library" etc..
So, I think that if I choice Mach-O type with Dynamic Library, the project will be compiled using dynamic linking library in linking way.
⬇️ I really wonder about.
But like in Window, Could iOS user downloads .so file in their iPhone in order to work normally app or update dynamic library?
Could others app launched in iPhone use same dynamic library ?
Because I could't experience about that.
If it(1,2) can't be, why to use dynamic library even we couldn't get actual advantage of using dynamic library like in Window or Linux ?
Your understanding of dynamic and static libraries is correct.
Static Linking
The compiled source code (object code, the .o files) and the compiled library code are combined into a single executable [1]
Dynamic Linking
The compiled source code (object code) and the library code are not combined together. The references to the dynamically linked library are resolved at runtime while the app launches or while running (the second part is not applicable in the case of iOS Apps) [1]
Q1
iOS borrows heavily from MacOS on how its applications work. Executables in both the OSes are Mach-O files. Now, on macOS dynamically linked libraries or dylibs are intended and designed to be updated without having to update the entire app. And by design, this is possible in iOS as well. What prevents this is Apple's guidelines restricting apps from downloading executable code from the internet. Any new update has to go through their review process. [2]
Q2
Yes, some dynamically linked libraries are shared across apps. However, they are created and updated by Apple through iOS updates. All Apple frameworks like UIKit, SceneKit, etc are examples of this. This is why these frameworks are weakly linked in Xcode with the option 'Do Not Embed'
Q3
Using your own dylibs are not completely pointless. If you ship extensions in your app, then dylibs are an excellent option to share code between the app and extensions without increasing the binary size. In this case, the executables share the same library. [3]
[1] https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/OverviewOfDynamicLibraries.html#//apple_ref/doc/uid/TP40001873-SW1
[2] https://developer.apple.com/app-store/review/guidelines/#app-completeness#2.5.2
[3] https://developer.apple.com/forums/thread/73802
[Vocabulary]
But like in Window, Could iOS user downloads .so file in their iPhone in order to work normally app or update dynamic library?
Dynamic library in iOS world is .dylib and they are updated along with OS updates. As an example Swift standard library[About] has a copy in every app before ABI OS stability[About]. But you cannot still download .dylib manually
Could others app launched in iPhone use same dynamic library ?
Of course. For example core libraries(runtime(Objective-C, Swift), Foundation)... distributed as dynamic libraries to share binaries through different applications and processes(IPC)
If it(1,2) can't be, why to use dynamic library even we couldn't get actual advantage of using dynamic library like in Window or Linux ?
You are able to create a dynamic framework with dynamic library inside(from iOS v8) which can be used for extensions(share some code inside different application)
Does iOS lost most of the advantage of using dynamic frameworks?
Since iOS will copy all the dynamic frameworks needed into the app bundle, it doesn't share dynamic frameworks between apps and save memory. Except for sharing memory with the main app and its extensions.
App using dlOpen can not ship to App Store. Which means Apple disallow dynamic framework from being used officially.
The old Apple document says dynamic frameworks save app launch time, but the new document says they don't. Is the old document outdated?
Here is the comparision:
make the app launch faster and use less memory once it’s launched
Load fewer dynamic libraries. This can be one of the longest parts of an app’s total launch time. Apple recommends using only up to six non-system frameworks
See if you can remove any of the dynamic libraries you’re using by replacing them with static versions or compiling their sources directly.
Does it mean if we use dynamic frameworks with dlOpen to load them later, it will be faster than static frameworks? Because the dynamic frameworks take some time to link in the begining, but they save more time in loading into memory. And loading time of static frameworks is greater then the linking time in dynamic frameworks. Is that true?
So it looks like there is none adavantage of using dynamic frameworks on iOS, right?
And how about on macOS and Linux? Do dynamic frameworks have any advantage? If so, how do they work?
You're correct in all of this. Non-system (i.e. not provided by Apple) dynamic libraries going to be less efficient in pretty much every way on iOS. They give you no space or memory savings, and they cost you at launch time.
The old Apple document you reference was almost entirely written before the iPhone. It's referring to late-loading libraries in Mac apps, which can help launch time.
On systems with shared libraries (or when using system libraries, which are shared on iOS), dynamic libraries save disk space, and can be shared between processes which saves memory and load time (because it's already loaded by some other process). But if you don't share the library, you can't really get any of those benefits. On systems that allow runtime loading of libraries (not iOS), dynamic libraries can delay the cost of loading seldom-used code, possibly indefinitely (if the code is never used). Furthermore, it opens up the opportunities for plugins and other extensions.
I have an app implemented in native iOS (Swift). There is a web version of the app as well. A client wants to embed my app to its own app and suggested I use an iFrame and load the web version.
I understand this is a tricky solution as Apple might reject the app for not using native implementation.
What I want to ask is if there is a way to package my app entirely as a Framework and load it that way (app size is fairly big, with several viewControllers and functionality).
I understand that I won't have access to App-load functions like the AppDelegate.
Also what happens if my app has Library dependencies ? (such as Alamofire)
Any other things I should be concerned about ?
Thank you
There are obviously a lot of options around this as far as design/approach.
I've done this multiple times (with apps live on the app store) and really it's just like developing any Framework.
First: AppDelegate. The easy way around this is to have the app's AppDelegate subclass your Framework's AppDelegate:
#UIApplicationMain class ParentAppDelegate: FrameworkAppDelegate { }
Just make sure the App calls super on all the relevant methods.
Second: Dependencies. This is probably the most annoying part since Frameworks can't embed other frameworks. But you still have a few easy options:
Have the enclosing app embed the needed framework
Add the sources of the needed framework directly to your framework.
Use a dependency manager (e.g. cocoapods) that takes care of this for you.
Other Concerns: One trap you can easily run into is working with Bundles. Anytime you dynamically load images/strings/IB references/etc. you will need to specify you're using the Framework's bundle, as at times it can default to using the app's bundle. The easiest way to do this is with this init e.g. Bundle(for: self.self)
Also keep in mind that the settings in info.plist and entitlements your framework needs will need to be added by the parent app.
General Comments on Approach: My advice (take it or leave it ☺️) would be caution around simply adding your full application to a client's application. Aside from IP and App-Review concerns, it can result in adding a lot of complexity or a fork of your current application to support it, making future maintenance a hassle.
Instead I would recommend putting only the portions of the application your client requires into a separate framework that both you and your client use for your separate applications.
I am working with a fat static library that uses dlopen() to load interal modules(.so) files inside the static library. On stackoverflow, developers says dlopen() is a private API.
In this case is it fine to use dlopen() or being an private API it shouldn't be used in user libraries irrespective of the library nature i.e static/dynamic.
If I can't use the dlopen() then can someone point to any resource for alternative way to accomplish the same task.
Note: This is regarding baresip BSD library. (http://www.creytiv.com/)
Update: The library is first trying to load all configured modules statically and if it fails then it is trying to load them dynamically using dlopen(). so removing the dynamic loading code will resolve my problem.
dlopen is not allowed on the iOS versions < iOS 8. See e.g. here.
Using dlopen with literal parameters has always been OK.
dlopen is documented, so it’s not a private API. Just type man dlopen in your terminal, or see App Extension Programming Guide > Handling Common Scenarios, or Dynamic Library Usage Guideline >1, 2.
If you try to use dlopen with code signed by you but not included in the app reviewed, you are infringing App Review Guidelines 2.5.2:
2.5.2 Apps should be self-contained in their bundles, and may not read or write data outside the designated container area, nor may they download, install, or execute code, including other apps.
and you may get a message like this:
Your app, extension, and/or linked framework appears to contain code designed explicitly with the capability to change your app’s behavior or functionality after App Review approval, which is not in compliance with App Store Review Guideline 2.5.2 and section 3.3.2 of the Apple Developer Program License Agreement.
This code, combined with a remote resource, can facilitate significant changes to your app’s behavior compared to when it was initially reviewed for the App Store. While you may not be using this functionality currently, it has the potential to load private frameworks, private methods, and enable future feature changes. This includes any code which passes arbitrary parameters to dynamic methods such as dlopen(), dlsym(), respondsToSelector:, performSelector:, method_exchangeImplementations(), and running remote scripts in order to change app behavior and/or call SPI, based on the contents of the downloaded script. Even if the remote resource is not intentionally malicious, it could easily be hijacked via a Man In The Middle (MiTM) attack, which can pose a serious security vulnerability to users of your app.