iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

时间:2024-08-23 22:03:26

修改于2017.1.25 使用Xcode Version 8.2.1

1.怎么创建.framework?

打开Xcode, 选择File ----> New ---> Project

选择iOS ----> Framework & Library ---> Cocoa Touch Framework。

点击Next ,按照流程一步一步的创建工程。

工程如下:我把昨天创建的.a库的文件拿过来用一下yooweiSDK.h和yooweiSDK.m。

一般系统自动生成的头文件我们可以将其他公开的头文件全部放在这里面

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

2.为.framework添加公开的头文件,如下图进行操作。

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

系统默认生成的头文件yooweiFramework.h默认在public里面,我们自己创建的默认在project里面,我们如果要公开的话,需要将其拖拽到public里面去。

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

show in finder

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

3.测试.framework

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

注意测试.framework时候 导入头文件的时候如下。

#import <yooweiFramework/yooweiFramework.h>

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

但是会报错:运行报错(Reason: Image Not Found)

为什么?因为.framework 创建后默认是动态库,在使用的时候需要额外加一个步骤,要把Framework同时添加到‘Embedded Binaries’中

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

添加成功后,测试成功

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

4、真机测试

ld: warning: ignoring file /Users/galahad/Desktop/yooweiTest/yooweiTestDemo/yooweiTest/yooweiFramework.framework/yooweiFramework, missing required architecture arm64 in file /Users/galahad/Desktop/yooweiTest/yooweiTestDemo/yooweiTest/yooweiFramework.framework/yooweiFramework (2 slices)

Undefined symbols for architecture arm64:

"_OBJC_CLASS_$_yooweiSDK", referenced from:

objc-class-ref in AppDelegate.o

ld: symbol(s) not found for architecture arm64

clang: error: linker command failed with exit code 1 (use -v to see invocation)

检测该framework支持什么架构:

模拟器上面打包的:

$ lipo -info /Users/galahad/Library/Developer/Xcode/DerivedData/yooweiFramework-fcezdhngqanqgjetshvbgtrhjoxp/Build/Products/Debug-iphonesimulator/yooweiFramework.framework/yooweiFramework

Architectures in the fat file: /Users/galahad/Library/Developer/Xcode/DerivedData/yooweiFramework-fcezdhngqanqgjetshvbgtrhjoxp/Build/Products/Debug-iphonesimulator/yooweiFramework.framework/yooweiFramework are: i386 x86_64

注意2点:命令依然使用的是lipo -info,但是一定要具体到yooweiFramework.framework/yooweiFramework文件。

真机上面打包的:

$ lipo -info /Users/galahad/Library/Developer/Xcode/DerivedData/yooweiFramework-fcezdhngqanqgjetshvbgtrhjoxp/Build/Products/Debug-iphoneos/yooweiFramework.framework/yooweiFramework

Architectures in the fat file: /Users/galahad/Library/Developer/Xcode/DerivedData/yooweiFramework-fcezdhngqanqgjetshvbgtrhjoxp/Build/Products/Debug-iphoneos/yooweiFramework.framework/yooweiFramework are: armv7 arm64

手动合并:

注意还是具体到yooweiFramework.framework里面的yooweiFramework文件

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

$ lipo -create /Users/galahad/Desktop/合并/真机/yooweiFramework.framework/yooweiFramework /Users/galahad/Desktop/合并/模拟器/yooweiFramework.framework/yooweiFramework -output /Users/galahad/Desktop/合并/yooweiFramework

$ lipo -info /Users/galahad/Desktop/合并/yooweiFramework

Architectures in the fat file: /Users/galahad/Desktop/合并/yooweiFramework are: i386 x86_64 armv7 arm64

注意:1、合成后将原来的无论是模拟器的还是真机的随便一个的该文件替换掉就可以了,其他的文件保留。

2、如果是在其他地方(比如桌面)新建立一个文件夹(比如桌面合并)来存放合并后的静态库文件,那么/Users/galahad/Desktop/桌面合并/yooweiFramework  后面的这个yooweiFramework静态库的名称不能少。

注意这里也是合并模拟器和真机,不是合并debug和relaese。

脚本合成:

1、新建Aggregate Target

Xcode--File--New--Target--cross-platform--Aggregate

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

选择New Run Script Phase

2、将下面脚本添加进去

# Sets the target folders and the final framework product.
# 如果工程名称和Framework的Target名称不一样的话,要自定义FMKNAME
# 例如: FMK_NAME = "MyFramework"
FMK_NAME=${PROJECT_NAME} # Install dir will be the final output to the framework.
# The following line create it in the root folder of the current project.
INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework # Working dir will be deleted after the framework creation.
WRK_DIR=build
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework # -configuration ${CONFIGURATION}
# Clean and Building both architectures.
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos clean build
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator clean build # Cleaning the oldest.
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi mkdir -p "${INSTALL_DIR}" cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/" # Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/${FMK_NAME}" rm -r "${WRK_DIR}" open "${INSTALL_DIR}"

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

scheme选择yooweiFrameworkScript, Run , 如果没有异常的话,会自动弹出生成的Framework文件框

3、检测一下

果然是支持: i386 x86_64 armv7 arm64

制作通用静态库

在ios 8 以前如果我们用了自己的动态库的话,那么是不可能上传appstore上面的。虽然ios8 以后允许使用动态库,但一般情况下还是使用静态库。

只需要修改一个参数即可生成静态库:(在yooweiFramework的build Settings 里面也可以)

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

run:自动弹出下面的内容

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

使用静态库的话,就可以把Framework从‘Embedded Binaries’中删除了

测试一下:

成功。

你可能遇到的问题:

1、如果你用的真机是iPhone5 C,生成的Framework竟然不支持armv7s,默认的Architectures竟然不包含armv7s。 在Architectures下增加armv7s,并选中。将Build Active Architecture Only 设置为NO。

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

手动添加以后,重新生成即可。

2、如果 SDK 有用到 Category,注意项目设置 Other Linker Flags 添加 -ObjC

-ObjC:加了这个参数后,链接器就会把静态库中所有的Objective-C类和分类都加载到最后的可执行文件中。否则可能会出现类似Implicit declaration of function '****' is invalid in C99 等问题。

-all_load:会让链接器把所有找到的目标文件都加载到可执行文件中,但是千万不要随便使用这个参数!假如你使用了不止一个静态库文件,然后又使用了这个参数,那么你很有可能会遇到ld: duplicate symbol错误,因为不同的库文件里面可能会有相同的目标文件,所以建议在遇到-ObjC失效的情况下使用-force_load参数。

-force_load:所做的事情跟-all_load其实是一样的,但是-force_load需要指定要进行全部加载的库文件的路径,这样的话,你就只是完全加载了一个库文件,不影响其余库文件的按需加载。

补充:.bundle文件的使用

有一种情况就是我们静态库里面的图片很可能跟我们项目里面的图片名字一样,就有可能将项目中的图片给覆盖掉,那么冲突就有了,所以静态库就有了存放图片的bundle。

我们需要建立一个bundle来存储文件。其实bundle就是一个特殊的文件夹,只不过是将文件夹命名为后缀为.bundle就行了。点击显示包内容,可以将图片拷贝进去。

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

向项目中拖入静态库的时候一定要将bundle  也拖进去,

这样的话加载图片的时候

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

就不能用

iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

再比如获取静态库里面bundle里面的资源文件

NSString *pathStr = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"AIResource.bundle"];
NSBundle *pathBundle = [NSBundle bundleWithPath:pathStr];
    //获取Bundle里的资源路径
NSString *cacerPath = [pathBundle pathForResource:@"ca" ofType:@"cer"];
NSData *cerDate=[NSData dataWithContentsOfFile:cacerPath];