弱引用动态库
弱引用动态库:标记
-weak_framework
参数,允许在运行时不链接该动态库
正常情况下,运行时找不到动态库所在位置,程序崩溃并提示
image not found
搭建
LGApp
项目,将动态库SYTimer.framework
拷贝到项目根目录
打开
LGApp
项目,创建xcconfig
文件,并配置到Tatget
上,写入以下代码:HEADER_SEARCH_PATHS = $(inherited) ${SRCROOT}/SYTimer.framework/Headers FRAMEWORK_SEARCH_PATHS = $(inherited) ${SRCROOT} OTHER_LDFLAGS = $(inherited) -framework "SYTimer"
- 指定头文件路径
Header Search Paths
- 指定
Framework
所在目录Framework Search Paths
- 指定链接
Framework
的名称Other Linker Flags -framework SYTimer
配置链接
Framework
三要素,编译可以成功。但运行时,程序崩溃dyld: Library not loaded: @rpath/SYTimer.framework/SYTimer Referenced from: /Users/zang/Library/Developer/CoreSimulator/Devices/BC871859-6A76-4967-A245-287615D883E6/data/Containers/Bundle/Application/BF848C5E-4E7E-440C-B266-6FEAD05BB6B2/LGApp.app/LGApp Reason: image not found
使用
-weak-l<library name>
或-weak_framework <framework name>
指定动态库为weak imports
。如果在运行时找不到该库,会自动将该库的地址及内容返回NULL
使用
man ld
查看ld
命令,找到-weak_framework
参数
-weak_framework
:标记为弱引用动态库。运行时找不到地址不会报错,而是返回一个NULL
打开
xcconfig
文件,修改OTHER_LDFLAGS
配置项:OTHER_LDFLAGS = $(inherited) -Xlinker -weak_framework -Xlinker "SYTimer"
项目运行成功,输出内容如下:
2021-03-08 17:46:30.286532+0800 LGApp[3397:9187180] (null)
使用
-weak_framework
标记为弱引用动态库,Mach-O
中记录的Load Command
名称不再是LC_LOAD_DYLIB
,变为LC_LOAD_WEAK_DYLIB
使用
otool -l test | grep 'DYLIB' -A 2
命令,查看Mach-O
中动态库的路径cmd LC_LOAD_WEAK_DYLIB cmdsize 64 name @rpath/SYTimer.framework/SYTimer (offset 24) -- cmd LC_LOAD_DYLIB cmdsize 88 name /System/Library/Frameworks/Foundation.framework/Foundation (offset 24)
静态库代码冲突
搭建
LGApp
项目,将静态库AFNetworking
代码,在项目根目录下拷贝两份
。将静态库目录,分别命名为AFNetworking
和AFNetworking2
打开
AFNetworking2
目录,将libAFNetworking.a
文件,重命名为libAFNetworking2.a
打开
LGApp
项目,创建xcconfig
文件,并配置到Tatget
上,写入以下代码:HEADER_SEARCH_PATHS = $(inherited) "${SRCROOT}/AFNetworking" "${SRCROOT}/AFNetworking2" LIBRARY_SEARCH_PATHS = $(inherited) "${SRCROOT}/AFNetworking" "${SRCROOT}/AFNetworking2" OTHER_LDFLAGS = $(inherited) -l"AFNetworking" -l"AFNetworking2"
此时编译可以通过,因为链接静态库默认使用
-noall_load
参数。当链接静态库AFNetworking
找到代码后,就不会链接静态库AFNetworking2
但真实项目中,我们使用
Pods
导入的三方库,大部分使用-all_load
或-ObjC
参数,此时问题出现了打开
xcconfig
文件,修改OTHER_LDFLAGS
配置项:OTHER_LDFLAGS = $(inherited) -ObjC -l"AFNetworking" -l"AFNetworking2"
编译报错,出现大量的重复符号
ld: 223 duplicate symbols for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)
尝试解决:
打开
xcconfig
文件,修改OTHER_LDFLAGS
配置项:OTHER_LDFLAGS = $(inherited) -ObjC -l"AFNetworking" -l"AFNetworking2" -Xlinker -force_load -Xlinker "${SRCROOT}/AFNetworking/libAFNetworking.a" -Xlinker -load_hidden -Xlinker "${SRCROOT}/AFNetworking2/libAFNetworking2.a"
- 使用
-force_load
参数,强制链接的静态库AFNetworking
- 使用
-load_hidden
参数,将静态库AFNetworking2
的所有符号设置为隐藏编译报错,依然提示重复符号
ld: 223 duplicate symbols for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)
结论:如果导入相同静态库,又指定了
-all_load
或-ObjC
参数,建议对静态库重新打包,删除重复的Symbol
动态库链接动态库
搭建
LGFramework
项目
LGFramework
是一个动态库项目,项目中使用Pods
导入动态库AFNetworking
使用
Pods
向一个Framework
中导入三方库,Pods
只会配置链接参数,不会将三方库拷贝到指定位置,也不会生成.sh
脚本
打开
LGOneObject.h
文件,写入以下代码:#import <Foundation/Foundation.h> @interface LGOneObject : NSObject - (void)testOneObject; @end
打开
LGOneObject.m
文件,写入以下代码:#ifndef AFN_HEADER_PATH #define AFN_HEADER_PATH <AFNetworking/AFNetworking.h> #endif #ifndef AFN #define AFN __has_include(AFN_HEADER_PATH) #endif #if AFN #import AFN_HEADER_PATH #endif #import "LGOneObject.h" @implementation LGOneObject - (void)testOneObject { #if AFN AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager manager]; NSLog(@"LGFramework-----LGOneObject-----AFN: %@", manager); #else NSLog(@"LGFramework-----LGOneObject-----NO AFN"); #endif } @end
AFN_HEADER_PATH
:表示<AFNetworking/AFNetworking.h>
头文件AFN
:表示是否存在头文件- 导入头文件:判断
AFN
,如果存在,执行#import AFN_HEADER_PATH
代码testOneObject
方法:判断AFN
,如果存在,初始化AFNetworkReachabilityManager
实例对象,并打印manager
对象。否则打印NO AFN
打开
LGFramework.h
文件,写入以下代码:#import <LGFramework/LGOneObject.h>
搭建
LGApp
项目
LGApp
是一个App
项目
创建
MulitProject.xcworkspace
,加入LGFramework
动态库和Pods
项目。LGApp
链接LGFramework
动态库
- 项目结构:
LGApp(App) -> LGFramework(动态库A) -> AFNetworking(动态库B)
在
LGApp
项目中,打开ViewController
文件,写入以下代码:#import "ViewController.h" #import <LGFramework/LGFramework.h> @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; LGOneObject *object = [LGOneObject new]; [object testOneObject]; } @end
运行项目后,程序直接崩溃
dyld: Library not loaded: @rpath/AFNetworking.framework/AFNetworking Referenced from: /Users/zang/Library/Developer/Xcode/DerivedData/MulitProject-dfauhknlvaapxgbchtdxxhwuixsn/Build/Products/Debug-iphonesimulator/LGFramework.framework/LGFramework Reason: image not found
在
LGFramework
项目中,打开Pods-LGFramework.debug.xcconfig
文件,查看LD_RUNPATH_SEARCH_PATHS
配置项LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' '@executable_path/../../Frameworks'
来到项目编译后的目录,
AFNetworking.framework
存放在AFNetworking
目录下,而AFNetworking
和LGApp.app
平级。所以按照LD_RUNPATH_SEARCH_PATHS
配置项,无法找到AFNetworking.framework
介绍以下三种解决办法:
【方式一】
修改
LGFramework
提供的@rpath
路径(仅适用于模拟器
)在
LGFramework
项目中,创建xcconfig
文件,并配置到Tatget
上,写入以下代码:#include "Pods/Target Support Files/Pods-LGFramework/Pods-LGFramework.debug.xcconfig" LD_RUNPATH_SEARCH_PATHS = $(inherited) ${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking
- 导入
Pods
生成的xcconfig
- 按照
AFNetworking.framework
所在路径,修改@rpath
路径选择模拟器,运行项目,输出内容如下:
2021-03-09 16:05:33.972325+0800 LGApp[10862:9536454] LGFramework-----LGOneObject-----AFN: <AFNetworkReachabilityManager: 0x600000856920>
选择真机,运行项目,程序崩溃:
dyld: Library not loaded: @rpath/AFNetworking.framework/AFNetworking Referenced from: /private/var/containers/Bundle/Application/BCCBC8EC-0333-4C46-B2E1-E024C4030916/LGApp.app/Frameworks/LGFramework.framework/LGFramework Reason: image not found
- 在设备上运行
App
,需要将链接的动态库拷贝到App
包内
【方式二】
使用
Pods
向LGApp
项目中导入动态库AFNetworking
在
Pods
项目中,打开Podfile
文件,写入以下代码:platform :ios, '9.0' workspace '../MulitProject.xcworkspace' target 'LGFramework' do use_frameworks! pod 'AFNetworking' end target 'LGApp' do project '../LGApp/LGApp.xcodeproj' use_frameworks! pod 'AFNetworking' end
选择真机,运行项目,输出内容如下:
2021-03-09 16:18:57.810101+0800 LGApp[1471:289515] LGFramework-----LGOneObject-----AFN: <AFNetworkReachabilityManager: 0x280d231c0>
使用
Pods
向App
中导入三方库,会生成一个.sh
脚本。它的作用就是将.framework
拷贝到App
中的Frameworks
目录
【方式三】
通过脚本,将
AFNetworking.framework
拷贝到App
中的Frameworks
目录将
方式二
中,Pods
生成的Pods-LGApp-frameworks.sh
脚本,拷贝到LGApp
项目的根目录
在
Pods
项目中,打开Podfile
文件,恢复初始代码:platform :ios, '9.0' target 'LGFramework' do use_frameworks! pod 'AFNetworking' end
在
LGApp
项目中,创建xcconfig
文件,并配置到Tatget
上,写入以下代码:SCRIPT_DIR = ${SRCROOT}/Pods-LGApp-frameworks.sh
- 定义
SCRIPT_DIR
变量,存储.sh
脚本路径在
LGApp
项目中,选择Build Phases
,在Run Script
中写入脚本:"${SCRIPT_DIR}"
选择真机,运行项目,输出内容如下:
2021-03-09 17:51:16.113484+0800 LGApp[1556:311935] LGFramework-----LGOneObject-----AFN: <AFNetworkReachabilityManager: 0x2831fa2c0>
此时
LGApp
项目不再使用Pods
导入AFNetworking
动态库,而是通过脚本,将AFNetworking.framework
拷贝到App
中的Frameworks
目录
App想使用动态库B的方法
基于上述案例:
LGApp(App) -> LGFramework(动态库A) -> AFNetworking(动态库B)
如果
App
想使用动态库B
的方法,也就是让LGApp
直接调用AFNetworking
的方法在
LGApp
项目中,打开ViewController.m
文件,写入以下代码:#import "ViewController.h" #import <LGFramework/LGFramework.h> #import <AFNetworking/AFNetworking.h> @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; LGOneObject *object = [LGOneObject new]; [object testOneObject]; AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager manager]; NSLog(@"App使用动态库B的方法:%@", manager); } @end
编译失败,提示错误信息:找不到头文件
'AFNetworking/AFNetworking.h' file not found
介绍以下两种解决办法:
【方式一】
使用
Pods
向LGApp
项目中导入动态库AFNetworking
在
Pods
项目中,打开Podfile
文件,写入以下代码:platform :ios, '9.0' workspace '../MulitProject.xcworkspace' target 'LGFramework' do use_frameworks! pod 'AFNetworking' end target 'LGApp' do project '../LGApp/LGApp.xcodeproj' use_frameworks! pod 'AFNetworking' end
在
LGApp
项目中,打开xcconfig
文件,写入以下代码:#include "Pods/Target Support Files/Pods-LGFramework/Pods-LGFramework.debug.xcconfig"
- 导入
Pods
生成的xcconfig
选择真机,运行项目,输出内容如下:
2021-03-09 18:32:15.142101+0800 LGApp[1583:320382] LGFramework-----LGOneObject-----AFN: <AFNetworkReachabilityManager: 0x283afa7a0> 2021-03-09 18:32:15.142263+0800 LGApp[1583:320382] App使用动态库B的方法:<AFNetworkReachabilityManager: 0x283afac60>
【方式二】
标记
-reexport_framework
或-reexport_l
参数,重新将AFNetworking
通过动态库LGFramework
导出给LGApp
在
Pods
项目中,打开Podfile
文件,恢复初始代码:platform :ios, '9.0' target 'LGFramework' do use_frameworks! pod 'AFNetworking' end
在
LGFramework
项目中,打开xcconfig
文件,写入以下代码:#include "Pods/Target Support Files/Pods-LGFramework/Pods-LGFramework.debug.xcconfig" OTHER_LDFLAGS = -Xlinker -reexport_framework -Xlinker AFNetworking $(inherited)
- 因为
Cocoapods
生成的xcconfig
文件包含了-framework AFNetworking
参数,想要将AFNetworking
指定为-reexport_framework
,需将其放在$(inherited)
前面在
LGApp
项目中,打开xcconfig
文件,写入以下代码:SCRIPT_DIR = ${SRCROOT}/Pods-LGApp-frameworks.sh HEADER_SEARCH_PATHS = $(inherited) "${BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/AFNetworking/AFNetworking.framework/Headers" FRAMEWORK_SEARCH_PATHS = $(inherited) "${BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/AFNetworking"
选择真机,运行项目,输出内容如下:
2021-03-09 18:32:15.142101+0800 LGApp[1583:320382] LGFramework-----LGOneObject-----AFN: <AFNetworkReachabilityManager: 0x283afa7a0> 2021-03-09 18:32:15.142263+0800 LGApp[1583:320382] App使用动态库B的方法:<AFNetworkReachabilityManager: 0x283afac60>
动态库的反向依赖
动态库的反向依赖,由于符合的作用空间,在运行时,动态库可以动态找到
App
的符号。所以只要在编译期间,绕过符号未定义的错误即可在
LGApp
项目中,打开LGAppObject.h
文件,写入以下代码:#import <Foundation/Foundation.h> @interface LGAppObject : NSObject - (void)test_app; @end
在
LGApp
项目中,打开LGAppObject.m
文件,写入以下代码:#import "LGAppObject.h" @implementation LGAppObject - (void)test_app { NSLog(@"test_app"); } @end
在
LGFramework
项目中,打开LGOneObject
文件,写入以下代码:#ifndef AFN_HEADER_PATH #define AFN_HEADER_PATH <AFNetworking/AFNetworking.h> #endif #ifndef AFN #define AFN __has_include(AFN_HEADER_PATH) #endif #if AFN #import AFN_HEADER_PATH #endif #import "LGOneObject.h" #import "LGAppObject.h" @implementation LGOneObject - (void)testOneObject { [[LGAppObject new] test_app]; #if AFN AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager manager]; NSLog(@"LGFramework-----LGOneObject-----AFN: %@", manager); #else NSLog(@"LGFramework-----LGOneObject-----NO AFN"); #endif } @end
- 导入
LGApp
项目中的LGAppObject.h
头文件- 调用了
LGAppObject
的test_app
方法在
LGFramework
项目中,打开xcconfig
文件,写入以下代码:#include "Pods/Target Support Files/Pods-LGFramework/Pods-LGFramework.debug.xcconfig" HEADER_SEARCH_PATHS = $(inherited) "${SRCROOT}/../LGApp/LGApp"
- 导入
LGApp
项目中的头文件编译报错,提示错误信息:
_OBJC_CLASS_$_LGAppObject
符号未定义Undefined symbols for architecture arm64: "_OBJC_CLASS_$_LGAppObject", referenced from: objc-class-ref in LGOneObject.o
介绍以下两种解决办法:
【方式一】
使用
-U
参数,标记某个符号为动态查找符号在
LGFramework
项目中,打开xcconfig
文件,写入以下代码:#include "Pods/Target Support Files/Pods-LGFramework/Pods-LGFramework.debug.xcconfig" HEADER_SEARCH_PATHS = $(inherited) "${SRCROOT}/../LGApp/LGApp" OTHER_LDFLAGS = -Xlinker -U -Xlinker _OBJC_CLASS_$_LGAppObject
- 使用
-U
参数,标记符号_OBJC_CLASS_$_LGAppObject
为动态查找符号选择真机,运行项目,输出内容如下:
2021-03-09 19:29:53.986715+0800 LGApp[1611:332497] test_app 2021-03-09 19:29:53.987340+0800 LGApp[1611:332497] LGFramework-----LGOneObject-----AFN: <AFNetworkReachabilityManager: 0x282785a60>
【方式二】
使用
-undefined
参数,将动态库中的符号全部标记为动态查找符号。配置后动态库中可以使用任意符号,这样风险较高,不建议使用在
LGFramework
项目中,打开xcconfig
文件,写入以下代码:#include "Pods/Target Support Files/Pods-LGFramework/Pods-LGFramework.debug.xcconfig" HEADER_SEARCH_PATHS = $(inherited) "${SRCROOT}/../LGApp/LGApp" OTHER_LDFLAGS = -Xlinker -undefined -Xlinker dynamic_lookup
- 使用
-undefined
参数,将整个LGFramework
动态库中的符号,都标记为动态查找符号选择真机,运行项目,输出内容如下:
2021-03-10 09:34:26.692354+0800 LGApp[2143:427804] test_app 2021-03-10 09:34:26.693179+0800 LGApp[2143:427804] LGFramework-----LGOneObject-----AFN: <AFNetworkReachabilityManager: 0x2828047a0>
动态库链接静态库
搭建
LGFramework
项目
LGFramework
是一个动态库项目,项目中使用Pods
导入静态库AFNetworking
打开
LGOneObject.h
文件,写入以下代码:#import <Foundation/Foundation.h> @interface LGOneObject : NSObject - (void)testOneObject; @end
打开
LGOneObject.m
文件,写入以下代码:#ifndef AFN_HEADER_PATH #define AFN_HEADER_PATH <AFNetworking/AFNetworking.h> #endif #ifndef AFN #define AFN __has_include(AFN_HEADER_PATH) #endif #if AFN #import AFN_HEADER_PATH #endif #import "LGOneObject.h" @implementation LGOneObject - (void)testOneObject { #if AFN AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager manager]; NSLog(@"LGFramework-----LGOneObject-----AFN: %@", manager); #else NSLog(@"LGFramework-----LGOneObject-----NO AFN"); #endif } @end
打开
LGFramework.h
文件,写入以下代码:#import <LGFramework/LGOneObject.h>
搭建
LGApp
项目
LGApp
是一个App
项目
创建
MulitProject.xcworkspace
,加入LGFramework
动态库和Pods
项目。LGApp
链接LGFramework
动态库
- 项目结构:
LGApp(App) -> LGFramework(动态库A) -> AFNetworking(静态库A)
在
LGApp
项目中,打开ViewController
文件,写入以下代码:#import "ViewController.h" #import <LGFramework/LGFramework.h> @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; LGOneObject *object = [LGOneObject new]; [object testOneObject]; } @end
选择真机,运行项目,输出内容如下:
2021-03-10 10:16:12.781430+0800 LGApp[2185:436467] LGFramework-----LGOneObject-----AFN: <AFNetworkReachabilityManager: 0x280dc7a60>
- 动态库
LGFramework
生成的过程中,链接静态库AFNetworking
时,会把静态库AFNetworking
所有代码都链接进去。所以编译链接都不会报错
App
想使用静态库AFNetworking
的方法在
LGApp
项目中,创建xcconfig
文件,并配置到Tatget
上,写入以下代码:HEADER_SEARCH_PATHS = "${SRCROOT}/../LGFramework/Pods/Headers/Public/AFNetworking" $(inherited)
- 指定
AFNetworking
头文件路径在
LGApp
项目中,打开ViewController.m
文件,写入以下代码:#import "ViewController.h" #import <LGFramework/LGFramework.h> #import <AFNetworking.h> @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; LGOneObject *object = [LGOneObject new]; [object testOneObject]; AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager manager]; NSLog(@"App使用静态库AFNetworking的方法:%@", manager); } @end
选择真机,运行项目,输出内容如下:
2021-03-10 10:20:52.143445+0800 LGApp[2189:437620] LGFramework-----LGOneObject-----AFN: <AFNetworkReachabilityManager: 0x281490760> 2021-03-10 10:20:52.143627+0800 LGApp[2189:437620] App使用静态库AFNetworking的方法:<AFNetworkReachabilityManager: 0x281493d20>
- 动态库链接静态库时,会把静态库所有代码都链接进去。静态库的导出符号,在动态库中依然是导出符号。所以
App
可以直接使用
隐藏静态库
AFNetworking
的全局符号如果动态库
LGFramework
不想把静态库AFNetworking
的全局符号(导出符号)暴露出去,可以通过-hidden-l<libraryname>
参数隐藏静态库的全局符号使用
man ld
查看ld
命令,找到-hidden-l<libraryname>
参数
在
LGFramework
项目中,创建xcconfig
文件,并配置到Tatget
上,写入以下代码:#include "Pods/Target Support Files/Pods-LGFramework/Pods-LGFramework.debug.xcconfig" OTHER_LDFLAGS = -Xlinker -hidden-l"AFNetworking" $(inherited)
- 导入
Pods
生成的xcconfig
- 因为
Cocoapods
生成的xcconfig
文件包含了-framework AFNetworking
参数,想要将AFNetworking
指定为-hidden-l
,需将其放在$(inherited)
前面编译报错,提示错误信息:
_OBJC_CLASS_$_AFNetworkReachabilityManager
符号未定义Undefined symbols for architecture arm64: "_OBJC_CLASS_$_AFNetworkReachabilityManager", referenced from: objc-class-ref in ViewController.o
静态库链接静态库
搭建
LGFramework
项目
LGFramework
是一个静态库项目,项目中使用Pods
导入静态库AFNetworking
打开
LGOneObject.h
文件,写入以下代码:#import <Foundation/Foundation.h> @interface LGOneObject : NSObject - (void)testOneObject; @end
打开
LGOneObject.m
文件,写入以下代码:#ifndef AFN_HEADER_PATH #define AFN_HEADER_PATH <AFNetworking/AFNetworking.h> #endif #ifndef AFN #define AFN __has_include(AFN_HEADER_PATH) #endif #if AFN #import AFN_HEADER_PATH #endif #import "LGOneObject.h" @implementation LGOneObject - (void)testOneObject { #if AFN AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager manager]; NSLog(@"LGFramework-----LGOneObject-----AFN: %@", manager); #else NSLog(@"LGFramework-----LGOneObject-----NO AFN"); #endif } @end
打开
LGFramework.h
文件,写入以下代码:#import <LGFramework/LGOneObject.h>
搭建
LGApp
项目
LGApp
是一个App
项目
创建
MulitProject.xcworkspace
,加入LGFramework
静态库和Pods
项目。LGApp
链接LGFramework
静态库
- 项目结构:
LGApp(App) -> LGFramework(静态库A) -> AFNetworking(静态库B)
在
LGApp
项目中,打开ViewController
文件,写入以下代码:#import "ViewController.h" #import <LGFramework/LGFramework.h> @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; LGOneObject *object = [LGOneObject new]; [object testOneObject]; } @end
编译报错,提示错误信息:
_OBJC_CLASS_$_AFNetworkReachabilityManager
符号未定义Undefined symbols for architecture arm64: "_OBJC_CLASS_$_AFNetworkReachabilityManager", referenced from: objc-class-ref in LGFramework(LGOneObject.o)
- 静态库
LGFramework
生成时,只保存了静态库AFNetworking
的头文件信息或静态库AFNetworking
的名称(Auto-Link
)。App
链接静态库LGFramework
后,会把静态库LGFramework
所有代码都链接进去。但是并不知道静态库AFNetworking
的位置和名称。所以编译报错
介绍以下两种解决办法:
【方式一】
使用
Pods
向LGApp
项目中导入静态库AFNetworking
在
Pods
项目中,打开Podfile
文件,写入以下代码:platform :ios, '9.0' workspace '../MulitProject.xcworkspace' target 'LGFramework' do # use_frameworks! pod 'AFNetworking' end target 'LGApp' do project '../LGApp/LGApp.xcodeproj' # use_frameworks! pod 'AFNetworking' end
选择真机,运行项目,输出内容如下:
2021-03-10 11:33:33.533189+0800 LGApp[2257:453229] LGFramework-----LGOneObject-----AFN: <AFNetworkReachabilityManager: 0x28164b920>
【方式二】
手动配置静态库
AFNetworking
的路径和名称在
LGApp
项目中,创建xcconfig
文件,并配置到Tatget
上,写入以下代码:LIBRARY_SEARCH_PATHS = $(inherited) "${BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/AFNetworking" OTHER_LDFLAGS = $(inherited) -ObjC -l"AFNetworking"
选择真机,运行项目,输出内容如下:
2021-03-10 11:37:57.163689+0800 LGApp[2275:454837] LGFramework-----LGOneObject-----AFN: <AFNetworkReachabilityManager: 0x28232b040>
静态库链接动态库
搭建
LGFramework
项目
LGFramework
是一个静态库项目,项目中使用Pods
导入动态库AFNetworking
打开
LGOneObject.h
文件,写入以下代码:#import <Foundation/Foundation.h> @interface LGOneObject : NSObject - (void)testOneObject; @end
打开
LGOneObject.m
文件,写入以下代码:#ifndef AFN_HEADER_PATH #define AFN_HEADER_PATH <AFNetworking/AFNetworking.h> #endif #ifndef AFN #define AFN __has_include(AFN_HEADER_PATH) #endif #if AFN #import AFN_HEADER_PATH #endif #import "LGOneObject.h" @implementation LGOneObject - (void)testOneObject { #if AFN AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager manager]; NSLog(@"LGFramework-----LGOneObject-----AFN: %@", manager); #else NSLog(@"LGFramework-----LGOneObject-----NO AFN"); #endif } @end
打开
LGFramework.h
文件,写入以下代码:#import <LGFramework/LGOneObject.h>
搭建
LGApp
项目
LGApp
是一个App
项目
创建
MulitProject.xcworkspace
,加入LGFramework
静态库和Pods
项目。LGApp
链接LGFramework
静态库
- 项目结构:
LGApp(App) -> LGFramework(静态库A) -> AFNetworking(动态库A)
在
LGApp
项目中,打开ViewController
文件,写入以下代码:#import "ViewController.h" #import <LGFramework/LGFramework.h> @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; LGOneObject *object = [LGOneObject new]; [object testOneObject]; } @end
编译报错,提示错误信息:
_OBJC_CLASS_$_AFNetworkReachabilityManager
符号未定义Undefined symbols for architecture arm64: "_OBJC_CLASS_$_AFNetworkReachabilityManager", referenced from: objc-class-ref in LGFramework(LGOneObject.o)
- 静态库
LGFramework
生成时,只保存了动态库AFNetworking
的名称(Auto-Link
)。App
链接静态库LGFramework
后,会把静态库LGFramework
所有代码都链接进去。但是并不知道动态库AFNetworking
的位置,也没有提供@rpath
路径。所以编译报错
介绍以下两种解决办法:
【方式一】
使用
Pods
向LGApp
项目中导入动态库AFNetworking
在
Pods
项目中,打开Podfile
文件,写入以下代码:platform :ios, '9.0' workspace '../MulitProject.xcworkspace' target 'LGFramework' do use_frameworks! pod 'AFNetworking' end target 'LGApp' do project '../LGApp/LGApp.xcodeproj' use_frameworks! pod 'AFNetworking' end
选择真机,运行项目,输出内容如下:
2021-03-10 13:35:10.416174+0800 LGApp[2380:479215] LGFramework-----LGOneObject-----AFN: <AFNetworkReachabilityManager: 0x282363440>
【方式二】
指定头文件路径、
Framework
所在目录、@rpath
路径。通过脚本,将AFNetworking.framework
拷贝到App
中的Frameworks
目录将
方式一
中,Pods
生成的Pods-LGApp-frameworks.sh
脚本,拷贝到LGApp
项目的根目录
在
Pods
项目中,打开Podfile
文件,恢复初始代码:platform :ios, '9.0' target 'LGFramework' do use_frameworks! pod 'AFNetworking' end
在
LGApp
项目中,创建xcconfig
文件,并配置到Tatget
上,写入以下代码:HEADER_SEARCH_PATHS = $(inherited) "${BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/AFNetworking/AFNetworking.framework/Headers" FRAMEWORK_SEARCH_PATHS = $(inherited) "${BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/AFNetworking" LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' '@executable_path/../../Frameworks' SCRIPT_DIR = ${SRCROOT}/../LGApp/Pods-LGApp-frameworks.sh
- 指定头文件路径
Header Search Paths
- 指定
Framework
所在目录Framework Search Paths
- 指定
@rpath
路径- 定义
SCRIPT_DIR
变量,存储.sh
脚本路径在
LGApp
项目中,选择Build Phases
,在Run Script
中写入脚本:"${SCRIPT_DIR}"
选择真机,运行项目,输出内容如下:
2021-03-10 13:46:27.990741+0800 LGApp[2393:481513] LGFramework-----LGOneObject-----AFN: <AFNetworkReachabilityManager: 0x282a61360>
配置Cocoapods
指定动态库+静态库
Cocoapods
导入三方库,有些场景下,需要指定某些库为动态库、某些库为静态库。此时配置use_frameworks!
无法满足需求,可以使用以下代码:
platform :ios, '9.0'
target 'LGFramework' do
use_frameworks!
pod 'AFNetworking'
pod 'SDWebImage'
end
#指定需要被编译成static_framework的库
$static_framework = ['SDWebImage']
pre_install do |installer|
installer.pod_targets.each do |pod|
if $static_framework.include?(pod.name)
def pod.build_type;
Pod::BuildType.static_framework
end
end
end
end
自定义xcworkspace
有些复杂项目,使用的并不是
Cocoapods
提供xcworkspace
最上层是自定义的
MulitProject.xcworkspace
,包含LGApp
和LGFramework
两个Project
。而Cocoapods
提供xcworkspace
在LGFramework
目录中
此时往
MulitProject.xcworkspace
中的LGApp
导入三方库,可以使用以下代码:platform :ios, '9.0' workspace '../MulitProject.xcworkspace' target 'LGFramework' do use_frameworks! pod 'AFNetworking' end target 'LGApp' do project '../LGApp/LGApp.xcodeproj' use_frameworks! pod 'AFNetworking' end
- 指定
MulitProject.xcworkspace
路径- 往
LGApp
中导入三方库,指定Project
路径
总结
弱引用动态库
- 标记
-weak_framework
参数,允许在运行时不链接该动态库- 标记为弱引用动态库,运行时找不到地址不会报错,而是返回一个
NULL
静态库代码冲突
- 使用
-force_load
参数,强制链接指定静态库- 使用
-load_hidden
参数,将指定静态库的所有符号设置为隐藏- 指定
-all_load
或-ObjC
参数,建议对静态库重新打包,删除重复的Symbol
App -> 动态库A -> 动态库B
- 使用
Pods
向App
项目中导入动态库B
- 通过脚本,将
动态库B
拷贝到App
中的Frameworks
目录
App
想使用动态库B
的方法
- 使用
Pods
向App
项目中导入动态库B
- 标记
-reexport_framework
或-reexport_l
参数,重新将动态库B
通过动态库A
导出给App
动态库的反向依赖
- 使用
-U
参数,标记某个符号为动态查找符号- 使用
-undefined
参数,将动态库中的符号全部标记为动态查找符号。配置后动态库中可以使用任意符号,这样风险较高,不建议使用
App -> 动态库A -> 静态库A
App
可以直接使用静态库A
的导出符号- 使用
-hidden-l<libraryname>
参数,隐藏静态库A
的全局符号(导出符号)
App -> 静态库A -> 静态库B
- 使用
Pods
向App
项目中导入静态库B
- 手动配置
静态库B
的路径和名称
App -> 静态库A -> 动态库A
- 使用
Pods
向App
项目中导入动态库A
- 指定头文件路径、
Framework
所在目录、@rpath
路径。通过脚本,将动态库A
拷贝到App
中的Frameworks
目录