The article was written on 04/08, 2016, moving to dig gold

The first iOS encapsulation Framework

What if we want to share certain functions with others, but we don’t want to expose implementation details? At this point, we can wrap our code into a framework that provides an interface without exposing the implementation; Not only that, but there are many other benefits to incorporating code into the framework, which are not listed here.

Here’s how to package it as a framework.

1. Create the project


Create a project using OS X > Framework&Library > Bundle:

2. Add Headers


Add Headers to Build Phases:

Headers expanded looks like this:

3. Add project code


Add the files that need to be packaged to the project, preferably by copy:

4. Merge header files


To make it easier for others to use the framework, create a header file that contains all the classes you want to expose, so that others can import only one header file when using your framework.

5. Expose classes


After the code is added to the Project, all.h files automatically appear under the Headers Project, and then we drag the classes that need to be exposed under Public.

Note here: Private is still public and not Private, so don’t be misled by its name. Keep Private classes under Project.

6. Change some Settings:


6.1 info.plist > Bundle OS Type code = FMWK

6.2 Build Settings > Base SDK = Latest iOS, select Latest

6.3 Build Settings > Linking:

  • Dead Code Stripping = NO;
  • Link With Standard Libraries = NO;
  • Mach-O Type = Static Library.

There are two possible scenarios for Mach-O Type :(1) select Static Library and print Static Library; (2) Select the Relocatable Object File as a dynamic library.

Static libraries are recommended. Dynamic libraries seem to be rejected when submitted for AppStore approval; But I read some information online that dynamic library is also possible, but there will be some computer audit rules need to pay attention to, such as x86/ I386 package and ARM architecture package lipo together, just use the real package. (This has not been tested, and I do not know whether it is true, if there are friends who have tested hope to let me know, thank you!)

6.4 Build Settings > Packaging > Wrapper Extension = framework.

7. Modify the output path


7.1 In order to find the framework generated after running, we created a directory build under the project directory in advance to store the files generated after running;

7.2 Then, you need to modify the output path:

Build Settings > Per-configuration Build Products Path = (CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

8, compile,


8.1 Select Generic iOS Device and compile.

8.2 Select the emulator and compile.

8.3 After successful compilation, two folders will be generated under build, one is generated by Device compilation and the other is generated by Simulator compilation, where the corresponding framework is stored.

9, merging,


Now that you have two frameworks for both devices and emulators, you need to merge them so that they work for both devices and emulators.

9.1 The two frameworks are not merged here, but their binary files, JJFramework as shown below;

9.2 How to merge? First, open terminal, CD to build folder; Then enter the command:

Lipo-create Device binary emulator binary-output The name of the composite file;

Note :(1) note the Spaces. (2) The name of the synthesized file must be the same as the name before the synthesis; otherwise, an error will be reported when using the Framework.

To merge two JJFrameworks, enter the following command:

lipo -create Debug-iphoneos/JJFramework.framework/JJFramework Debug-iphonesimulator/JJFramework.framework/JJFramework – the output JJFramework.

JJFramework in the Build folder is the synthesized binary.

9.3 Remove the Generated Framework from the device or emulator and replace the original binary file with the synthesized binary file:

10, Delete info.plist


That’s pretty much the end of the story. In addition, if info.plist is not used in the framework, it can be removed to avoid conflicts. (I was in this situation once)

OK, framework is packaged.

There are many ways to encapsulate the framework, and this is just one of them; And there should be an easier way, and I’ll make it up later if I have time.

Article 2 uses bundles to manage resources

The previous article used bundles to create the framework. This article uses the iOS framework directly, which is much easier.

Xcode version 7.2.1 is used for this article.

First, iOS -> Framework&Library -> Cocoa Touch Framework creation project.

The name of the project should be the same as the name you would expect for the SDK. Here, use ExpeSDK as the project name.

Delete expesdk. h and expesdktests. m files from the project. If you don’t need them, move them to the wastebasket.

3. Change some configuration in Build Settings

3.1 Architectures default to ARMV7 and ARM64. Armv7s architecture can be added, mainly for compatibility with 5C, if 5C is not considered, this step can be ignored.

3.2 Change the output path: Create a build directory under the project root directory, change the following configuration, the output file will be in the build file, this step is just to find the output file.

Per-configuration Build Products Path > (CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

3.3 The following Settings are recommended:

Mach-O Type > Static Library; (Static library, dynamic library is not allowed if you need to review Appstore)

Dead Code Stripping > NO; (Whether to eliminate invalid code)

Link With Standard Libraries Is set to YES by default, or it will work if there is no special requirement.

Setting it to NO can also be packaged, but Other Linker Flags must be configured when using the Framework.

Enable Bitcode > NO; (Old library support)

4. Copy files to be shared to the project. The files copied here are config.h and config.m;

Build Phases -> Headers:

Drag the headers that need to be shared into Public and keep the private ones in Project.

Six, compile,

Simulator compilation:

Compile the Device:

Merge binary files

After successful compilation, the framework of the simulator and device is generated in the build directory, and their binaries are merged so that the framework can be used on devices and emulators.

Device framework:

The simulator framework:

7.1 Open the terminal and CD to the Build directory:

CD Path to the build file

7.2 entering the compositing command :(lipo-create device binary simulator binary-output compositing file name)

lipo -create Debug-iphoneos/ExpeSDK.framework/ExpeSDK Debug-iphonesimulator/ExpeSDK.framework/ExpeSDK -output ExpeSDK

After composition, a new binary file will be generated in the build directory:

7.3 Replacing Binary Files

The new binary is then replaced with the binary in the Device Framework.

Move out of the framework.

OK, framework completed!


A lot of times, we’re going to need images, xiBs, whatever, and we’re going to need bundles to manage it.

The easiest way to create a Bundle is to create a new file and call it xxx.bundle.

Here I create a new tuxiang.bundle and right click to show the package contents and put in two images tx_1.jpg and tx_2.png.

1, create an app project showApp

Add expesdK. framework and tuxiang.bundle to the project. Xcode will automatically copy tuxiang.bundle to app mainBundle when the application runs.

In expesdk. framework config.m I have written a method to fetch the image from tuxiang.bundle as follows:

- (UIView*)configUI
{
    UIImage * image = [config getPNGImage:@"tx_2"];
    UIImageView * imgView = [[UIImageView alloc] initWithImage:image];
    imgView.frame = CGRectMake(0, 20, 375, 600);
    return imgView;
}
+ (UIImage*)getPNGImage:(NSString*)_image_name
{
    NSBundle * txBundle = [self getBundle:@"tuxiang"];
    NSString * imgPath = [txBundle pathForResource:_image_name ofType:@"png"];
    return [UIImage imageWithContentsOfFile:imgPath];
}
+ (UIImage*)getJPGImage:(NSString*)_image_name
{
    NSBundle * bundle = [self getBundle:@"tuxiang"];
    NSString * imgPath = [bundle pathForResource:_image_name ofType:@"jpg"];
    return [UIImage imageWithContentsOfFile:imgPath];
}

+ (NSBundle*)getBundle:(NSString*)_bundle_name
{
    NSLog(@"mainBundle resourcePath = %@",[NSBundle mainBundle].resourcePath); NSString * Component = [NSString stringWithFormat:@"%@.bundle",_bundle_name]; // NSString * bundlePath = [[NSBundle mainBundle].resourcePath stringByAppendingPathComponent:component]; NSString * bundlePath = [[NSBundle mainBundle] pathForResource:_bundle_name ofType:@"bundle"];
    
    NSBundle * bundle = [NSBundle bundleWithPath:bundlePath];
    return bundle;
}
Copy the code

Provide external methods in the config.h file:

- (UIView*)configUI;
Copy the code

Call configUI from showApp:

Import the header file first

#import "ExpeSDK/config.h"
Copy the code

And then call the function in viewDidLoad

- (void)viewDidLoad 
{
    [super viewDidLoad];
    
    config * ObjCon = [[config alloc] init];
    [self.view addSubview:[ObjCon configUI]];
}
Copy the code

4. Operation:

It was the intended effect.

The third article makes the framework directly in the project

If we write a project, we can create the framework directly in the project.

1, create project, project name showLog

Create a new class LogMessage in showLog and write a function there. The purpose is to package this function as a framework and share it with the framework.

LogMessage.h

@interface LogMessage : NSObject
+ (void)logInfo; // Share the method @endCopy the code

LogMessage.m

@implementation LogMessage
+ (void)logInfo
{
    NSLog(@"log info success!");
}
@end
Copy the code

3. Next, create the framework in your project

You will see the interface for the new project, select Cocoa Touch Framework. I’m going to call it LogSDK.

After the new target is built, you can see that there are 1 or 2 more files in the project.

4, select a new target: LogSDK, General > Deployment Info > Deployment target

Modify the configuration according to the following figure:

Go to LogSDK > Build Phases and drag the.m file to Compile Sources and the.h file that needs to be public to Headers > Pulic and the private file that needs to be private to Headers > Project.

6. Change the output path:

Create a new build directory under the project file

LogSDK > Build Settings > Build Locations :

Change the configuration in the figure above as follows:

(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

7. Compilation:

You need to select LogSDK first:

Then the simulator and Device are compiled respectively.

8. After successful compilation, merge as described in Step 7 of the previous article.