动态库下(5)

动态库下(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相比

  1. 可以用单个.xcframework文件提供多个平台的分发二进制文件.
  2. 与Fat Header相比, 可以按照平台划分, 可以包含相同架构的不同平台文件.
  3. 在使用时, 不需要再通过脚本去剥离不需要的架构体系.

多架构合并

  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
    3. XCode编译器,会根据你的程序编译对象,自动选择相应的架构

动静态实战

weak_import

  1. 项目链接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"

静态库冲突

  1. 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"
  1. 编译的时候并没有冲突, 是因为专门为静态库设计的 -noall_load
    1. 这时使用all_load,以及-ObjC都不行, 都会将冲突暴露出来
    2. 使用-force_load 来只链接其中一个
    3. 将其中一个链接生成为动态库.也可以解决

SDK建议:

  1. 一个成熟的SDK,没有理由用了一堆其他的SDK
  2. SDK -> 基本上都是动态库

动动

  1. App -> 使用自己的动态库 -> 自己的动态库使用了其他的动态库.例:AFNetworking
  2. 两种解决方案
    1. 脚本copy,参考cocoapods的sh脚本
      1. 注意,cocoapods提供动态库的时候,支持提供了链接参数,并没有将动态库copy,只不过最后通过脚本进行了copy
    2. cocoapods, 重新引入其他的动态库到APP


      image.png
  1. 反依赖的情况, 动态库 -> 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. 此时已经反依赖成功.

动静

  1. 关闭cocoapods的user_frameworks! -> 表明引入的是静态库


    image.png
  1. 动态库会将所引用的静态库代码链接
  2. 静态库所有的导出符号相对于动态库来说,还全是导出符号
    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即导入静态库又导入动态库

  1. use_frameworks! -> 来控制动静态库
  2. 以下代码达成的效果, 数组里面的都是静态库,不包含的还是默认动态库
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

总结

  1. XCFramerwork的优点
    1. 解决头文件问题
    2. 解决调试符号问题
    3. 解决相同架构的处理
  2. 实战
    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/脚本复制(比较推荐)
  3. 组件/库 -> 依赖不要太多,最好一个都没有 -> AFN做个封装

实战配置参考

实战配置

你可能感兴趣的:(动态库下(5))