XCFramework  (framework的增强版)
说明:

1. 苹果官方推荐,支持的,可以更加方便多个平台和架构的分发二进制库的格式。

2. 需要xcode11以上支持

3. 在2019年提出的framework的另一种先进格式。

多架构合并
架构打包命令:

// 打包成模拟器架构
xcodebuild archive -project ‘SYTimer.xcodeproj’ \
-scheme ‘SYTimer’ \
-configuration Release \
-destination ‘generic/platform=iOS Simulator’ \
-archivePath ‘../archives/SYTimer.framework-iphonesimulator.xcarchive’ \
SKIP_INSTALL=NO

// 打包成iOS真机架构
xcodebuild archive -project ‘SYTimer.xcodeproj’ \
-scheme ‘SYTimer’ \
-configuration Release \
-destination ‘generic/platform=iOS’ \
-archivePath ‘../archives/SYTimer.framework-iphoneos.xcarchive’ \
SKIP_INSTALL=NO
胖二进制: 多个架构将库文件压缩放在一起,并不是合并。

通过lipo 命令进行将动态库进行合并。

格式 : lipo -output 合并后输出的名称 -create  架构路径1 架构路径2

lipo -output SYTimer -create ../archives/SYTimer.framework-iphoneos.xcarchive/Products/Library/Frameworks/SYTimer.framework/SYTimer ../archives/SYTimer.framework-iphonesimulator.xcarchive/Products/Library/Frameworks/SYTimer.framework/SYTimer
遇到问题;

相同的架构合并,会出现冲突

解决方法:

去除相同的架构,只留一个架构,相关命令如下:

lipo -output SYTimer -create ../archives/SYTimer.framework-iphoneos.xcarchive/Products/Library/Frameworks/SYTimer.framework/SYTimer ../archives/SYTimer.framework-iphonesimulator.xcarchive/Products/Library/Frameworks/SYTimer.framework/SYTimer

//提取 x86_64架构
lipo -output SYTimer-x86_64 -extract x86_64 ../archives/SYTimer.framework-iphonesimulator.xcarchive/Products/Library/Frameworks/SYTimer.framework/SYTimer

lipo -output SYTimer -create ../archives/SYTimer.framework-iphoneos.xcarchive/Products/Library/Frameworks/SYTimer.framework/SYTimer SYTimer-x86_64
苹果为了解决这个问题,所以引进了XCFramework ,优点相比于 lipo

1.  不用处理头文件

2. 会自动处理重复的架构

3. 会自动产生调试符号

4. 会根据运行的架构自动选择对应的架构 。

 

制作一个XCFramework:
xcodebuild -create-xcframework \
-framework ‘../archives/SYTimer.framework-iphoneos.xcarchive/Products/Library/Frameworks/SYTimer.framework’ \
-framework ‘../archives/SYTimer.framework-iphonesimulator.xcarchive/Products/Library/Frameworks/SYTimer.framework’ \
-output ‘SYTimer.xcframework’ 需要改xcframework放的路径
xcodebuild -create-xcframework \
-framework ‘../archives/SYTimer.framework-iphoneos.xcarchive/Products/Library/Frameworks/SYTimer.framework’ \
-debug-symbols ‘架构1 – bcsymbolmap – 的*对路径’ \
-debug-symbols ‘架构2 – bcsymbolmap – 的*对路径’ \
-debug-symbols ‘架构1 – dsym – 的相对路径’ \
-framework ‘架构2 -framework – 的相对路径’ \
-debug-symbols ‘架构2 – dysm – 的相对路径’ \
-output ‘SYTimer.xcframework’
weak import
1. 弱引用的作用 ,就是当动态库被引入但没有使用的话,会自动置为nil ,不会让程序崩溃,编译通过,一个符号找不到,不会强制找到为止。 在xcconfig文件中格式为:

OTHER_LDFLAGS = $(inherited) -Xlinker -weak_framework -Xlinker “第三方库或动态库名称”
相同静态库的重复引入,符号冲突的解决方法:

通过链接器的 force_load 引入其中一个静态库, 另外一个静态库的符号通过 load_hidden 去隐藏。

命令如下:

OTHER_LDFLAGS = $(inherited) -l”*个静态库名” -l”第二个静态库名” -Xlinker -force_load -Xlinker “*个静态库路径.a” -Xlinker -load_hidden -Xliner “第二个静态库路径.a”
动态库 、静态库的实战
动态库与动态库的链接实战:

思路:  自己的framework,通过pod导入一个第三方,然后自己的项目,导入自己的framework并使用 ,反向使用等。

实现步骤:

1 .创建一个自己的framework (创建方法见 : framework制作)

2. 在framework,通过cocoapods导入一个第三方库。 (pods 只会生成链接器的参数,并不会把库文件放到framework下,pods是通过脚本是复制到指定目录,方式二:再使用的工程中,通过pods的配置文件,再指定加载的第三方库。)

3. 打开我们自己的framework ,添加一个target,模拟成app,进行使用。

4. 现在的流程就是 app -> 自己的动态库  -> 第三方动态库 (AFNetworking) , 大致的动态库与动态库的模型就出来了。

后期上传demo.

主要出现的问题:

1. 运行app,找不到第三方库文件(因为这个第三方库,是动态库中所引用的第三方库),报错信息:

Undefined symbols for architecture x86_64:
“_OBJC_CLASS_$_ZGRAppObject”, referenced from:
objc-class-ref in ZGRAFNetworkingManager.o
解决方法是:在pod 文件中为这个target也加入pod 第三方库的方法,Podfile 代码如下:

platform :ios, ‘14.1’

#自己做的framework ,动态库
target :’ZGRNetworkManager’ do
use_frameworks!
pod ‘AFNetworking’
end

#比喻App
target :’ZGRNetworkManagerTests’ do
use_frameworks!
pod ‘AFNetworking’
end
2. 找不到对应的符号_OBJC_CLASS_$_ZGRAppObject ,  修改pod的配置文件,创建的target 和 动态库对应的配置文件都加上这句话。

OTHER_LDFLAGS = $(inherited) -framework “AFNetworking” -Xlinker -U -Xlinker _OBJC_CLASS_$_ZGRAppObject
动态库与静态库的链接实战:

思路:  自己的framework,通过pod导入一个第三方静态库 AFNetworking.a ,在framework 中添加一个target,模拟app来使用 。

实现步骤:

1 .创建一个自己的framework (创建方法见 : framework制作)

2. 在framework,通过cocoapods导入一个第三方库。 (pods 只会生成链接器的参数,并不会把库文件放到framework下,pods是通过脚本是复制到指定目录,方式二:再使用的工程中,通过pods的配置文件,再指定加载的第三方库。)

3. 打开我们自己的framework ,添加一个target,模拟成app,进行使用。

4. 现在的流程就是 app -> 自己的动态库  -> 第三方静态库 (AFNetworking.a) , 大致的动态库与静态库的模型就出来了。

 

注:

动态库链接静态库,会链接所有的静态库符号, 所以当app去编译动态库的时候,并不会报错。

静态库的导出符号,也会出现在动态库符号里面,所以可以在app中直接使用,导入头文件即可。   (搜索不到,需要设置 header search paths路径 ${SRCROOT}/Pods/Headers/Public)

后期上传demo.

关于静态库的符号隐藏,通过在pod的配置文件加入如下代码:

OTHER_LDFLAGS = $(inherited) -Xlinker -hidden-l “AFNetworking”
 

静态库与静态库的链接实战:

思路:  自己的framework静态库组件,通过pod导入一个第三方静态库 AFNetworking.a ,在framework 中添加一个target,模拟app来使用 。

实现步骤:

1 .创建一个自己的framework (静态库) (创建方法见 : framework制作)

2. 在framework,通过cocoapods导入一个第三方库静态库。

3. 打开我们自己的framework ,添加一个target,模拟成app,进行使用。

4. 现在的流程就是 app -> 自己的静态库组件  -> 第三方静态库 (AFNetworking.a) 。

 

操作记录:

1. 在静态库组件首先要设置 library search path ,  例如 : “${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking”

2. 设置Other Linker Flags , -lAFNetworking

 

原理就是: app去链接静态库组件, 但静态库组件所链接的静态库并没有路径链接到app,所以需要在组件中手动设置下所链接的静态库的路径与头文件。

 

静态库与动态库的链接实战:

公式:  app = app + 静态库 (所有的符号都是可见的)

思路:  自己的framework静态库,通过pod导入一个第三方动态库 AFNetworking ,在framework 中添加一个target,模拟app来使用 。

实现步骤:

1 .创建一个自己的framework ,静态库(创建方法见 : framework制作)

2. 在framework,通过cocoapods导入一个第三方库AFNetworking。

3. 打开我们自己的framework ,添加一个target,模拟成app,进行使用。

4. 现在的流程就是 app -> 自己的静态库  -> 第三方动态库 (AFNetworking) , 大致的静态库与动态库的模型就出来了。

 

Cocoapods 拷贝动态库脚本的用法。

首先,把脚本拷贝到工程根目录下,脚本文件,可以在任意cocoapods的工程中去找,  然后在项目中,在build phase 添加一个脚本,输入:

“${SRCROOT}/Pods-LGNetworkManagerTests-frameworks.sh”
这样在运行项目的时候,脚本会自动将动态库拷贝到product目录中。

 

总结:

1. XCFramework  – sdk开发,组件开发

解决了:

1.头文件的处理

2. 调试符号的保存

3. 相同架构的处理

4.2019年才出。

 

2.  实战

1. weak_import

使用场景:  动态库 运行时 -》 不能确认到指定位置,所以用到了弱引用,当找不到动态库的时候,项目不会报错的作用

2. 静态库冲突 -》 app -> all_load\-Objc

3. app – 动态库 – 动态库链接  ,app不知道所以需要以下操作

方式一: 通过cocoapod脚本复制

方式二: 通过cocoapod 加载第三方库,并不会加载两次。 不用担心

 

动态库 – 静态库

存在问题:

静态库不想暴露到处符号,需要用到 -hidden -l静态库

 

app – 静态库 – 静态库

1. 名称  知道。

2 不知道所在位置: 所以只需要告诉位置

 

app – 静态库 – 动态库

1. 编译报错:  不知道动态库的路径

2. 运行报错: 不知道动态库的rpath