动态库下(5)
XCFramework
XCFramework: 是苹果官方推荐的, 支持的, 可以更方便的表示一个多个平台和架构的分发二进制库的格式.
需要Xcode11以上支持.
是为更好的支持Mac Catalyst和ARM芯片的macOS.专门在2019年提出的framework的另一种先进格式.
平时开发中会设计到的一些架构
- iOS/iPad: arm64
- iOS/iPad Simulator: x86_64 arm64
- Mac Catalyst: x86_64 arm64
- Mac: x86_64 arm64
和传统的framework相比
- 可以用单个.xcframework文件提供多个平台的分发二进制文件.
- 与Fat Header相比, 可以按照平台划分, 可以包含相同架构的不同平台文件.
- 在使用时, 不需要再通过脚本去剥离不需要的架构体系.
多架构合并
1. SYTimer -> 编译生成几个不同的需要的架构 2. xcodebuild archive -project 'SYTimer.xcodeproj' \ //指定project-scheme 'SYTimer' \ //指定scheme-configuration Release \ //指定编译的环境-destination 'generic/platform=iOS Simulator' //指定分发的架构平台-archivePath '../archives/SYTimer.framework-iphonesimulator.xcarchive' //指定输出路径SIKP_INSTALL=NO //只有指定为NO的时候才会进行拷贝,方便我们查看最终的编译产物 1. xcodebuild -> 正常开发过程中使用的构建 2. archive -> 代表打包 3. 进行真机的架构打包 1. xcodebuild archive -project 'SYTimer.xcodeproj' -scheme 'SYTimer' -configuration Release -destination 'generic/platform=iOS' -archivePath '../archives/SYTimer.framework-iphoneos.xcarchive' SKIP_INSTALL=NO 2. SYTimer 4. 通过lipo命令合并 1. 注意库文件的合并,支持放在一起,进行压缩,并不是真正意义上的合并 2. lipo命令最大的问题就是相同的架构不能合并. 例如:两个库都有同一种架构 3. lipo 5. xcFramework 1. xcframework 6. xcFramework的使用 1. 直接将生产的xcframework拖拽到 -> targets/general/frameworks 2. 引入头文件 #import <SYTimer/SYTimer.h> 3. XCode编译器,会根据你的程序编译对象,自动选择相应的架构
动静态实战
weak_import
- 项目链接SYTimer
// 2. -F: frmaework 所在的目录 FRAMEWORK_SEARCH_PATHS = $(inherited) ${SRCROOT} // 1. -I :头文件 HEADER_SEARCH_PATHS = $(inherited) ${SRCROOT}/SYTimer.framework/Headers // 路径 // "/Users/ws/Desktop/VIP课程/第五节、动态库与静态库实战/完成代码/动态库与静态库实战/weak_import/LGApp" LD_RUNPATH_SEARCH_PATHS = $(inherited) // 3. 名称 // null -》 runtime -〉 nil // weak_import // library OTHER_LDFLAGS = $(inherited) -Xlinker -weak_framework -Xlinker "SYTimer"
静态库冲突
- APP 链接 AFNetworking静态库
//-I HEADER_SEARCH_PATHS = $(inherited) "${SRCROOT}/AFNetworking" "${SRCROOT}/AFNetworking2" //-L LIBRARY_SEARCH_PATHS = $(inherited) "${SRCROOT}/AFNetworking" "${SRCROOT}/AFNetworking2" //-l // 冲突 // all_load // -ObjC // 两个静态库 -》 库 OTHER_LDFLAGS = $(inherited) -l"AFNetworking" -l"AFNetworking2" -Xlinker -force_load -Xlinker "${SRCROOT}/AFNetworking/libAFNetworking.a"
- 编译的时候并没有冲突, 是因为专门为静态库设计的 -noall_load
1.这时使用all_load,以及-ObjC都不行, 都会将冲突暴露出来
2.使用-force_load 来只链接其中一个
3.将其中一个链接生成为动态库.也可以解决
SDK建议:
- 一个成熟的SDK,没有理由用了一堆其他的SDK
- SDK -> 基本上都是动态库
动动
- App -> 使用自己的动态库 -> 自己的动态库使用了其他的动态库.例:AFNetworking
- 两种解决方案
1.脚本copy,参考cocoapods的sh脚本
1.注意,cocoapods提供动态库的时候,支持提供了链接参数,并没有将动态库copy,只不过最后通过脚本进行了copy
2.cocoapods, 重新引入其他的动态库到APP
image.png
- 反依赖的情况, 动态库 -> APP
1. 需要APP将需要的头文件暴露出来 1. Build Phases -> Headers -> project -> 添加需要暴露的头文件 -> 移动到Public 2. xcconfig -> HEADER_SEARCH_PATH 的头文件暴露 3. 导入头文件 4. 编译报错 -> 让APP运行起来,dyld就能找到 -> -undefined 1. OTHER_LDFLAGS = ... -Xlinker -undefined -Xlinker dynamic_lookup -> 这种写法风险比较大,不建议 2. OTHER_LDFLAGS = ... -Xlinker -U -Xlinker OBJC_CLASS_LGAppObject为动态库查找的符号 3. 此时已经反依赖成功.
动静
- 关闭cocoapods的user_frameworks! -> 表明引入的是静态库
image.png
- 动态库会将所引用的静态库代码链接
- 静态库所有的导出符号相对于动态库来说,还全是导出符号
1.问题: 给别人提供动态库的时候,不想暴露静态库
2.
OTHER_LDFLAGS = $(inherited) -ObjC -Xlinker -hidden-l "AFNetworking" -> 可以达到符号的可见性
静静
1. 关闭 use_framerworks -> 表明拉取的是静态库 2. app + 静态库 没问题 1. 组件静态库 + 组件链接的静态库 -> 有问题,组件链接的静态库相对于APP没有告诉APP链接的三要素 2. 手动配置三要素,头文件不用了, 需要配置静态库路径,以及静态库名称
静动
1. APP = APP + 静态库 -> 相当于APP直接使用动态库 1. 静态库 -> 动态库 2. 配置framework路径 3. 进行一个跟上面一样的动动配置.脚本直接使用cocoapods提供的动态库的脚本就可以 1. APP -> Build Phases -> Run Script -> 执行脚本就可以 2. 执行脚本的作用就是,进行framework的拷贝
cocoapods即导入静态库又导入动态库
- use_frameworks! -> 来控制动静态库
- 以下代码达成的效果, 数组里面的都是静态库,不包含的还是默认动态库
target :'LGNetworkManager' do use_frameworks! # 静态库、动态库 # 指定需要被编译成static_framework的库 $static_framework = ['AFNetworking'] pre_install do |installer| installer.pod_targets.each do |pod| if $static_framework.include?(pod.name) def pod.build_type; Pod::Target::BuildType.static_framework end end end end pod 'SDWebImage' end
cocoapod 往不同的workspace以及target里面导入动态库的写法
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
总结
- XCFramerwork的优点
1.解决头文件问题
2.解决调试符号问题
3.解决相同架构的处理
- 实战
1. weak_import: 动态库 运行时不知道这个动态库是否存在 -> 可以使用weak_import来声明一下 2. 静态库冲突 -> APP -> 不存在二级命名空间,并且all_load/-ObjC 3. APP -> 动 动2 -> pod/脚本复制(比较推荐) 1. reexport重新暴露动2的符号 2. APP反向依赖 4. APP -> 动 静 -> 静态库不想暴露 -> hidden-l 5. APP -> 静 静2 -> 不知道静2的所在位置 6. APP -> 静 动 -> 编辑就会报错 -> 不知道动态库的位置 1. 运行时也会报错 -> 动rpath -> pod/脚本复制(比较推荐)
- 组件/库 -> 依赖不要太多,最好一个都没有 -> AFN做个封装