SDK开发-类库嵌套

优质
小牛编辑
128浏览
2023-12-01

SDK开发-类库嵌套

此篇文章仅限于SDK开发中的嵌套场景汇总, 不包含具体问题的解决方案

简要总结:

静态库:
1. framework嵌套framework, 不会被包含, 项目仍需导入被嵌套的framework
2. framework嵌套.a库, 可以, 如果项目也导入了.a库, 会符号表冲突, 处理方案: 加前缀
3. .a嵌套.a, 可以
4. .a嵌套framework, 不会将framework内容link到.a中, 项目仍需导入framework
动态库:
1. framework嵌套.a, 可以, .a的内容会被link到framework中
2. framework嵌套静态framework, 可以, 会将静态的framework内容link到动态framework中
3. framwrokd嵌套动态framework, 不会被包含, 项目仍需导入依赖的framework

准备测试工程

  • 利用pod lib快速准备6个SDK工程

    • .a静态库1: LibStaticA
    • .a静态库2: LibStaticB
    • Framework静态库1: LibStaticFrameworkA
    • Framework静态库2: LibStaticFrameworkB
    • Framework动态库1: LibDynamicFrameworkA
    • Framework动态库2: LibDynamicFrameworkB
    • 用来继承调试最终SDKDemo: SDKIntegratedDemo
  • 如果是自己新建的工程, 使用Target依赖的方式, 编译好类库后, 将生成的类库直接拖入另外的类库Target下即可
  • 如果是pod lib, 注意.podspec文件配置的资源路径, 导入后在Example下执行pod install完成依赖
  • 实际开发中如果.a支持git,可以通过subspec实现,依赖集成会相对简单, 我这里都是本地.a依赖, 无法执行lint操作, 也不支持cocoapods-package

1. .a嵌套.a

准备阶段:

编译生成LibStaticA库后, 将.h.a二进制文件导入到LibStaticB静态库内, 为了结构清晰, 存放到文件夹LibStaticA

目录结构:

.
├── Example                        ~> 调试demo
│   ├── LibStaticB
│   │   ├── ...
│   │   ├── LViewController.h
│   │   ├── LViewController.m
│   │   └── ...
│   └── ...
│           
├── LibStaticB                    ~>  .a 静态库B
│   ├── Assets
│   └── Classes
│       ├── LibStaticA            ~>  嵌套的.a 静态库A
│       │   ├── LibStaticA.h
│       │   └── libLibStaticA.a
│       ├── LibStaticB.h
│       └── LibStaticB.m
├── LibStaticB.podspec
└── _Pods.xcodeproj

结论:

.a能够嵌套.a库, 项目集成后不需要重复导入

2. .a嵌套Framework静态库

准备阶段:

利用刚刚的firstStaticLib项目, 再新建一个Framework静态库项目, 名称firstStaticFramework

目录结构:

.
├── FirstStaticLibDemo      ->    [Demo Target]
│   ├── 省略不相关文件...
│   ├── ViewController.h
│   └── ViewController.m
├── firstStaticLib          ->    [.a static library Target]
│   ├── FirstStaticLib.h
│   ├── FirstStaticLib.m
│   └── firstStaticFramework.framework  ->    [嵌套的framework静态库]
│       ├── Headers
│       │   └── FirstStaticFrameworkLib.h
│       └── firstStaticFramework
└── firstStaticLib.xcodeproj
    └── 省略不相关文件...

firstStaticLib中使用Framework的接口

#import "FirstStaticLib.h"
#import <firstStaticFramework/FirstStaticFrameworkLib.h>

@implementation FirstStaticLib

+ (void)firstStaticLib {
    NSLog(@"%s", __func__);
    // Framework接口
    [FirstStaticFrameworkLib firstStaticFrameworkLib];
}

@end

编译报错, 找不到被嵌套的Framework

Undefined symbols for architecture x86_64:
  "_OBJC_CLASS_$_FirstStaticFrameworkLib", referenced from:
      objc-class-ref in libfirstStaticLib.a(FirstStaticLib.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

firstStaticLib这个Target中虽然包含了Framework静态库, 但在调试项目FirstStaticLibDemo这个Target下并没有包含 在项目FirstStaticLibDemo这个Target再导入一次Framework就可以正常运行了

结论:

.a可以依赖并使用Framework静态库,但编译后的.a静态库中不会包含Framework静态库, 也就是编译期间不会链接Framework静态库中的内容到.a
最终的项目中集成了.a库后, 还需要导入被依赖的Framework静态库

有点类似于三方库的使用场景, 在使用时要求我们导入那些依赖库(苹果自己的动态库除外)

3. .a嵌套.Framework动态库

准备阶段:

生成动态库firstDynamicFramework, 导入firstStaticLib这个静态库的Target

目录结构:

.
├── FirstStaticLibDemo
│   ├── 省略不相关文件...
│   ├── ViewController.h
│   └── ViewController.m
├── firstStaticLib
│   ├── FirstStaticLib.h
│   ├── FirstStaticLib.m
│   └── firstDynamicFramework.framework
│       ├── Headers
│       │   ├── FirstDynamicFrameworkLib.h
│       │   └── firstDynamicFramework-umbrella.h
│       └── firstDynamicFramework
└── firstStaticLib.xcodeproj
    ├── project.pbxproj
    ├── project.xcworkspace
    └── 省略不相关文件...

编译报错:

Showing Recent Messages
Ld /Users/shenyj/Library/Developer/Xcode/DerivedData/firstStaticLib-ggyjdbctoktoasennbwcjushjdsm/Build/Products/Debug-iphonesimulator/FirstStaticLibDemo.app/FirstStaticLibDemo normal (in target 'FirstStaticLibDemo' from project 'firstStaticLib')
    cd /Users/shenyj/Desktop/nestification/firstStaticLib
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -target x86_64-apple-ios14.3-simulator -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.3.sdk -L/Users/shenyj/Library/Developer/Xcode/DerivedData/firstStaticLib-ggyjdbctoktoasennbwcjushjdsm/Build/Products/Debug-iphonesimulator -F/Users/shenyj/Library/Developer/Xcode/DerivedData/firstStaticLib-ggyjdbctoktoasennbwcjushjdsm/Build/Products/Debug-iphonesimulator -F/Users/shenyj/Desktop/nestification/firstStaticLib/FirstStaticLibDemo -filelist /Users/shenyj/Library/Developer/Xcode/DerivedData/firstStaticLib-ggyjdbctoktoasennbwcjushjdsm/Build/Intermediates.noindex/firstStaticLib.build/Debug-iphonesimulator/FirstStaticLibDemo.build/Objects-normal/x86_64/FirstStaticLibDemo.LinkFileList -Xlinker -rpath -Xlinker @executable_path/Frameworks -dead_strip -Xlinker -object_path_lto -Xlinker /Users/shenyj/Library/Developer/Xcode/DerivedData/firstStaticLib-ggyjdbctoktoasennbwcjushjdsm/Build/Intermediates.noindex/firstStaticLib.build/Debug-iphonesimulator/FirstStaticLibDemo.build/Objects-normal/x86_64/FirstStaticLibDemo_lto.o -Xlinker -export_dynamic -Xlinker -no_deduplicate -Xlinker -objc_abi_version -Xlinker 2 -fobjc-arc -fobjc-link-runtime -Xlinker -sectcreate -Xlinker __TEXT -Xlinker __entitlements -Xlinker /Users/shenyj/Library/Developer/Xcode/DerivedData/firstStaticLib-ggyjdbctoktoasennbwcjushjdsm/Build/Intermediates.noindex/firstStaticLib.build/Debug-iphonesimulator/FirstStaticLibDemo.build/FirstStaticLibDemo.app-Simulated.xcent -lfirstStaticLib -Xlinker -no_adhoc_codesign -Xlinker -dependency_info -Xlinker /Users/shenyj/Library/Developer/Xcode/DerivedData/firstStaticLib-ggyjdbctoktoasennbwcjushjdsm/Build/Intermediates.noindex/firstStaticLib.build/Debug-iphonesimulator/FirstStaticLibDemo.build/Objects-normal/x86_64/FirstStaticLibDemo_dependency_info.dat -o /Users/shenyj/Library/Developer/Xcode/DerivedData/firstStaticLib-ggyjdbctoktoasennbwcjushjdsm/Build/Products/Debug-iphonesimulator/FirstStaticLibDemo.app/FirstStaticLibDemo

Undefined symbols for architecture x86_64:
  "_OBJC_CLASS_$_FirstDynamicFrameworkLib", referenced from:
      objc-class-ref in libfirstStaticLib.a(FirstStaticLib.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

可见FirstStaticLibDemo这个TargetLink的时候找不到.a依赖的那个firstDynamicFramework动态库

此时按照.a嵌套Framework静态库那样, 在DemoTarget中导入Framework动态库, 编译会通过, 但是运行后仍然会Crash

dyld: Library not loaded: @rpath/firstDynamicFramework.framework/firstDynamicFramework
  Referenced from: /Users/shenyj/Library/Developer/CoreSimulator/Devices/B0EBE6CE-9AE5-4449-8371-143BE02D8EDD/data/Containers/Bundle/Application/7125645D-43C1-499D-B479-8281D0F2C015/FirstStaticLibDemo.app/FirstStaticLibDemo
  Reason: image not found
dyld: launch, loading dependent libraries
DYLD_SHARED_CACHE_DIR=/Users/shenyj/Library/Developer/CoreSimulator/Caches/dyld/20C69/com.apple.CoreSimulator.SimRuntime.iOS-14-3.18C61
DYLD_ROOT_PATH=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot
DYLD_LIBRARY_PATH=/Users/shenyj/Library/Developer/Xcode/DerivedData/firstStaticLib-ggyjdbctoktoasennbwcjushjdsm/Build/Products/Debug-iphonesimulator:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/system/introspection
DYLD_INSERT_LIBRARIES=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/libBacktraceRecording.dylib:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/Core

结论:

.a嵌套Framework动态库, Framework不会被Link.a