• Since there are some problems with this article, I recommend that you look at “Libraries” in iOS development (part 2) after reading this article

    Before you read the article, you may want to read the following questions. If you know them, you may want to skip them.

  • What is. Framework? How do you make it?

  • Talk about their understanding of dynamic and static libraries.
  • How to use dynamic Framework apps in a project? Can apps that use the Dynamic Framework be listed in the Appstore?
  • Can app hotfixes be implemented through the framework?

I am a preface

  • Recently, I found that many people confuse “.framework &&. a “, “dynamic &&static libraries”, and “.tbd &&.dylib “. Even, some people have been mistakenly thinking that framework is a dynamic library!! In view of the vagueness of many articles on the Internet, plus many articles are quite old, so today I write something to summarize.

  • First, before reading this article, you should know a few things: compilation process, memory partition. Here we go!

Theory of article

Dynamic libraries vs. static libraries

Static frameworks are linked at compile time. Dynamic frameworks are linked at runtime

  • The first thing you have to understand is that these are both compiled binaries. It’s just a different use. Why are there dynamic and static libraries? Take a look at the picture below:



Static library





The dynamic library


  • We can see it clearly:

    • forStatic libraryWhen the link is compiled, theStatic librarytheAll the filesAre added to theTarget app executable fileAnd after the program runs,Static librarywithApp executable fileAre loaded together into the same code area.
      • App executable: The target app executable is the file with the same name as app in the package content displayed after ipA decompression.
    • For dynamic libraries, only the referenced headers are added to the target APP executable when the link is compiled. Unlike static libraries, dynamic libraries add another memory area while the program is running.
    • Let’s take a look at apple’s official documentation for two sentences about dynamic libraries and static libraries.

      - A better approach is for an app to load code into its address space when it's actually needed, either at launch time or at runtime. The type of library that provides this flexibility is called dynamic library. - ** dynamic library **: can be loaded into memory when ** runs or starts **, Load it into a ** independent memory address of your app **. The app's code -- which includes the code of the static libraries it was linked with -- is loaded into the app's address Applications with large executables suffer from slow launch times and large memory Footprints - When the program starts, it will load the app code (including the static library code) into the memory address of the APP. Using dynamic libraries will take more startup time and memory consumption than using static libraries. It also increases the size of the executable.Copy the code
  • For example 🌰 : suppose UIKit is compiled into static libraries and dynamic libraries with a size of 1M and takes 1s to load into memory. Now app1 and app2. If you use static libraries, app1 starts up with 2s and 2 MB of memory allocated to app1. In addition to the startup time and memory consumption of APP2, the static library scheme costs 4s startup time, 4M memory size and 4M installation package size. So when you switch to a dynamic library, it might take the same amount of time to start app1, but you don’t have to load UIKit dynamic library when you start App2. Reduces UIKit reuse, costing 3s startup time, 3M memory size, and 4M installation package size.

  • Many apps use many of the same libraries, such as UIKit and CFNetwork. Therefore, Apple uses a large number of dynamic libraries to optimize the system in order to speed up app startup, reduce memory costs and reduce the size of installation packages. Dyld shared cache: Dynamic linkers on OS X and iOS use the shared cache, which is stored in /var/db/dyld/. For each architecture, the operating system has a separate file containing the vast majority of dynamic libraries that are linked into a single file and whose symbolic relationships have been handled. When loading a Mach-O file (an executable file or a library), the dynamic linker first checks the shared cache to see if it exists, and if so, pulls it out of the shared cache and uses it. Each process maps this shared cache into its own address space. This approach greatly optimizes the startup time of applications on OS X and iOS.

  • Both are linked from *.o object files. It’s all binary, closed source.

.framework VS .a

  • A is a pure binary file, which cannot be used directly. It needs to be used together with header files and resource files. In iOS it is used as a filename suffix for static libraries.

  • . Framework in addition to binary files also have resource files, can be used directly.

  • Framework =.a +.h + bundle when you cannot develop dynamic libraries. When Xcode 6 comes out, we can develop dynamic libraries. Framework = static libraries/dynamic libraries +.h + bundle.

.tbd VS .dylib

  • For static libraries the suffix is.a, what is the suffix for dynamic libraries?
  • Dylib is the suffix of the dynamic library file.

  • So what is.tbD? In fact, careful friends have already noticed that when we import the dynamic library provided by the system from Xcode7, there is no longer.dylib, but.tbd. TBD, on the other hand, is a YAML article file that describes information about dynamic libraries that need to be linked. The main purpose is to reduce the download size of the app. You can see the details here

A small summary

  • First, compared with static and dynamic libraries, dynamic libraries have advantages in package size, startup time, and memory ratio.
  • In order to solve the problem of not using.a files directly, but also with.h and resource files, Apple introduced something called.framework, which also supports dynamic libraries.

Embedded VS. Linked

Embedded frameworks are placed within an app’s sandbox and are only available to that app. System frameworks are stored at the system-level and are available to all apps.

  • OK, so what if we develop a dynamic framework ourselves and copy it into dyLD’s shared cache?
  • In general, you can’t do it the normal way, and Apple won’t let you do it. (Of course, it does not rule out that some reverse gods can achieve their goals through hack means)
  • So how do we develop and use our own dynamic framework?
  • Embedded Binaries.

  • Embedded means Embedded, but not in the app executable, but in the app bundle. When an APP is Embedded in the way of Embedded, unpack ipA after package, you can see a framework folder in the package. The following are the dynamic framework related to the application. In Xcode you can set it here, in red:




Embedded && Link


  • What are the linded Feameworks and libraries?
  • First of all inlinded feameworks and librariesThe following we can connect the system dynamic library, the development of their own static library, their development of the dynamic library. For the static library here, it’s going to be inCompile the linkPhase connection toApp executable fileIn the case of the dynamic library here, although not linked toApp executable file,But all the dynamic libraries set up here will be loaded at startup. (ps. This should be the case in theory, but in my actual tests it doesn’t seem to matter whether it’s loaded or not. Maybe I’m not in the right position. 😂)
  • If you do not want to load the dynamic libraries at startup, delete them in Linded FeameWorks and Libraries and use Dlopen to load the dynamic libraries. (Dlopen is not a proprietary API.)
- (void)dlopenLoad{ NSString *documentsPath = [NSString stringWithFormat:@"%@/Documents/Dylib.framework/Dylib",NSHomeDirectory()]; [self dlopenLoadDylibWithPath:documentsPath]; } - (void)dlopenLoadDylibWithPath:(NSString *)path { libHandle = NULL; libHandle = dlopen([path cStringUsingEncoding:NSUTF8StringEncoding], RTLD_NOW); if (libHandle == NULL) { char *error = dlerror(); NSLog(@"dlopen error: %s", error); } else { NSLog(@"dlopen load framework success."); }}Copy the code

About the Making process

  • For more information on How to Create a Framework for iOS, check out raywenderlich’s tutorial How to Create a Framework for iOS.

  • After reading this tutorial, I add a few points.

    • First, the framework is divided into Thin and Fat Frameworks. Thin means Thin and refers to a single architecture. And Fat is Fat, which refers to multiple architectures.
    • To develop Frameworks that can be debugged by both the real machine and the simulator, combine Frameworks. The merge command islipolipo.
    • If your app is going to be in the App Store, you need to remove the framework of the simulator from the Frameworks before submitting it for review.
    • Personally, when componentizing a project or building an SDK, it’s best to do it as a framework.

practice

Framework of the way to achieve app hot repair

  • Since Apple doesn’t want developers to bypass the App Store to update their apps, only apps that don’t need to be on the App Store can be updated in the framework.
  • But in theory it should work if Dlopen isn’t banned, as long as the signatures are consistent. (Because there is no practice, so it is YY.)
  • Either way, you need to ensure that the framework and app signatures on the server are consistent.

General idea of implementation

  • Download the new version of the framework
  • So let’s go under Document and look for the framework. Then load the framework in the bundle or document based on the conditions.
NSString *fileName = @"remote"; NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentDirectory = nil; if ([paths count] ! = 0) { documentDirectory = [paths objectAtIndex:0]; } NSFileManager *manager = [NSFileManager defaultManager]; NSString *bundlePath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"framework"]; BOOL loadDocument = YES; // Check if new bundle exists if (! [manager fileExistsAtPath:bundlePath] && loadDocument) { bundlePath = [documentDirectory stringByAppendingPathComponent:[fileName stringByAppendingString:@".framework"]]; }Copy the code
    // Load bundle
    NSError *error = nil;
    NSBundle *frameworkBundle = [NSBundle bundleWithPath:bundlePath];

    if (frameworkBundle && [frameworkBundle loadAndReturnError:&error]) {
        NSLog(@"Load framework successfully");
    }else {
        NSLog(@"Failed to load framework with err: %@",error);

    }Copy the code
// Load class Class PublicAPIClass = NSClassFromString(@"PublicAPI"); if (! PublicAPIClass) { NSLog(@"Unable to load class"); } NSObject *publicAPIObject = [PublicAPIClass new]; [publicAPIObject performSelector:@selector(mainViewController)];Copy the code

Set pieces

About the lipo

$ lipo -info /Debug-iphoneos/Someframework.framwork/Someframework
# Architectures in the fat file: Someframework are: armv7 armv7s arm64Copy the code
$lipo -- create a.framework b.framework -- output output.frameworkCopy the code
$lipo -- create a. framwork -thin armv7-output a-output-armv7. FrameworkCopy the code

From source code to APP

What do we do when we click build?

  • Pre-process: replace macros, remove comments, expand header files, produce.i files.
  • Compliling: Convert previous.i files into assembly language to produce.s files.
  • Asembly: Converts an assembly language file into a machine code file, producing a.O file.
  • Link: References to other library references in the.o file, resulting in the final executable (including multiple.o files for Link).

ld && libtool

  • Ld: used to generate executable files.
  • Libtool: a tool for generating lib.

Build phases && Build rules && Build settings

  • Build Phases: This is done to control the process from source to executable, so it is source oriented, including which files are compiled and some custom scripts are executed during the Build phases.
  • Build rules: controls how certain types of source files are compiled. If certain types of source files are compiled specifically, you should edit them here. At the same time, there will be a lot of use of xcode environment variables, the full official documentation is here: Build Settings Reference
  • Build Settings: sets the details of the Build operation. In this window you can see a large number of Settings, from compilation to packaging to code signing. Note the section classification of the Settings. At the same time, you can easily understand the meaning of the option through the inspector on the right.

Talk about the Mach – O




Mach-O


  • You need to select this Mach-o Type when creating the framework.
  • Short for Mach Object file format, it is a file format for executables, Object code, dynamic libraries, and kernel dumps. As an alternative to the A.out format, Mach-o provides greater extensibility and improved access to information in symbol tables.

The resources

  • Apple Official Documentation
  • Add dynamic library for app submission to AppStore
  • Framework Dynamic Update

Afterword.

@Sunny what’s wrong with meQuestions raised.