The article was written on 04/08, 2016 and moved here

The first iOS encapsulates the Framework

What if we want to share some functions with others, but don’t want to expose the details of the implementation? At this time, we can encapsulate our code into the framework, providing external interfaces without exposing the implementation; Not only that, but there are many other benefits to integrating code into the Framework, which I won’t list here.

Let’s take a look at how to package it into the framework.

1. Create a project


Create projects using OS X > Framework&Library > bundles:

2. Add HEADERS


Add Headers to Build Phases:

Headers expands like this:

3. Add project code


Add files that need to be wrapped and packaged into 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 when someone uses your framework, they only need to import this header file.

5. Expose classes


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

One caveat here: Private is still public, not Private. Don’t be misled by the name. Private classes are kept under Project.

6. Change some Settings:


> Bundle OS Type code = FMWK

6.2 Build Settings > Base SDK = Latest iOS

Build Settings > Linking:

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

For Mach-O Type, there are two possible situations :(1) Select Static Library to Type Static Library; (2) Select Relocatable Object File and type it as a dynamic library.

Static libraries are recommended, as dynamic libraries appear to be rejected when submitted for AppStore approval; But read some information online that dynamic library is also possible, but there will be some machine audit rules need to pay attention to, such as do not put the x86/i386 package and the ARM architecture package LIPO together, just use the real package. (About this has not been tested, do not know whether it is true, if a friend has tested the hope to inform, thank you!)

Build Settings > Packaging > Wrapper Extension = framework

7. Modify the output path


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

7.2 Then, the output path needs to be modified:

Build Settings > Per-configuration Build Products Path = $(SRCROOT)/build/$(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 generated by Device and the other generated by Simulator, which store the corresponding framework.

9, merging,


At this point, you have two frameworks for devices and emulators, and now you need to combine them so that they work for both devices and emulators.

9.1 The two frameworks are not merged, but their respective binaries, such as the JJFramework in the figure below.

9.2 So how to merge? First, open the terminal, CD into the build folder; Then type the command:

Lipo-create device binary emulator binary-output synthesized file name;

Note :(1) Pay attention to Spaces. (2) The name of the synthesized file should be the same as the name before the synthesized file, otherwise the framework will report an error.

As shown in the figure above, merge two JJFramework and enter the following command:

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

The JJFramework in the Build folder is the synthesized binary.

9.3 Remove the framework generated by device or simulator operation and replace the original binary file with the synthesized binary file:

10, Delete Info.plist


And you’re pretty much done.

Also, if you don’t use Info. plist in the framework, you can remove it to avoid conflicts. (I’ve been in this situation once.)

OK, the 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 to do it, and I’ll make up for it later if I have time.

The second article uses bundles to manage resources

In the previous post, we created the framework using bundles. This post is much easier to implement directly using the iOS framework.

The version of Xcode used for this article is 7.2.1.

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

The name of the project should be the same as what you would expect from the SDK. Use ExpeSDK as the project name here.

After the project is created, delete the expesdk. h and expesdktests.m files. If you don’t need them, move them to the wastepaper basket.

3. Change some configuration in Build Settings

3.1 Architectures default to ARMv7 and ARM64. ARMV7S architecture can be added, mainly to be compatible with 5C. If 5C is not considered, you can ignore this step.

3.2 Change the output path: create a build directory in the project root directory, change the following configuration, the output file will be under the build file, this step is just for the convenience of finding the output file.

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

3.3 The following Settings are recommended:

Mach-O Type > Static Library; (Static libraries, if you need to review the AppStore, do not allow the use of dynamic libraries)

Dead Code Stripping > NO; Whether to eliminate invalid code

Link With Standard Libraries is YES by default, but if you don’t have a specific requirement, the default is OK.

Setting to NO is also packable, but Other Linker Flags must be configured when using the framework.

Enable Bitcode > NO; (Support old libraries)

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

Build Phases -> HEADERS:

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

Six, compile,

Simulator compilation:

Compile the Device:

Merge binaries

After the compilation is successful, the framework of the emulator and device will be generated in the build directory, and their binaries will be merged to make the framework common to the device and the emulator.

Device framework:

The simulator framework:

7.1 Open terminal, CD to build directory:

CD build file path

7.2 Enter the synthesize command :(lipo-create device binary emulator binary-output synthesize file name)

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

When the composition is complete, a new binary file will be generated in the build directory:

7.3 Replace binaries

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

Move out of the framework.

OK, the framework is finished!


A lot of times, we need to use resources like images, or XIBs, or whatever, and we need bundles to manage them.

The easiest way to create a Bundle is to create a new file and name it “XXX”. The Bundle is OK.

Here, I create a new tuxiang. Bundle, then right-click to show the contents of the package and put in 2 images tx_1.jpg and tx_2.png.

1. Create a new APP project, ShowApp

Add the expesdk. framework and tuxiang. Bundle above to your project, so that when the program runs, Xcode will automatically copy tuxiang. Bundle to the app mainBundle.

In the config.m of ExpeSDK. Framework, I have already written the method to get the image in tuxiang. Bundle. The code is 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); /* Get tuxiang. Bundle from mainBundle */ // Method 1 // NSString * Component = [NSString stringWithFormat:@"%@.bundle",_bundle_name]; // NSString * bundlePath = [[NSBundle mainBundle].resourcePath stringByAppendingPathComponent:component]; // method 2 NSString * BundlePath = [[NSBundle mainBundle] PathForResource: _Bundle_Name ofType:@"bundle"]; NSBundle * bundle = [NSBundle bundleWithPath:bundlePath]; return bundle; }

img点击并拖拽以移动

Provide external methods in the config.h file:

- (UIView*)configUI;

img点击并拖拽以移动

ConfigUI = showApp ();

Lead into the header file

#import "ExpeSDK/config.h"

img点击并拖拽以移动

And then call the function in viewDidLoad

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

img点击并拖拽以移动

4. Operation:

It is indeed the intended effect.

In the third part, the framework is directly produced in the project

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

1. Create project, project name showLog

2. Create a new class LogMessage in showLog, and write a function here. The final purpose is to package the function method into the framework and share it.

LogMessage.h

@interface LogMessage : NSObject + (void)logInfo; // Shared method @end

img点击并拖拽以移动

LogMessage.m

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

img点击并拖拽以移动

3. Next, build the framework in the project

You’ll see the new project screen, and select Cocoa Touch Framework. It’s called LogSDK.

After the new target is built, you can see that there are 1 or 2 more files in the project. Delete the native.h and.m files:

Select new target: LogSDK, General > Deployment Info > Deployment target select lowest;

Modify the configuration according to the following figure:

Drag. M files to Compile Sources, Drag. H files that need to be public to Headers > Pulic, Drag.

6. Change 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:

$(SRCROOT)/build/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

7. Compile:

You need to select the LogSDK:

Then we compile the simulator and the Device respectively.

8. After the compilation is successful, follow Step 7 of the previous article to merge.