美文网首页
XCFramework

XCFramework

作者: 浅墨入画 | 来源:发表于2021-02-16 16:54 被阅读0次

前言

XCFramework:是苹果官方推荐的,支持的,可以更方便的表示一个多个平台结构的分发二进制的格式。
需要Xcode 11以上支持,
是为更好的支持Mac Catalyst和ARM芯片的macOS。 专⻔在2019年提出的framework的另一种先进格式。
平时开发涉及到的一些架构:
iOS/iPad:arm64
iOS/iPad Simulator:x86_64 arm64
Mac Catalyst: x86_64 arm64 跨平台
Mac: x86_64 arm64
XCFramework的好处:
多架构合并,模拟器,真机可以通用
上架AppStore,不需要将xcframework中的真机架构分离,.framework还需要用脚本分离

一. archive打包

1.1 archive打包命令原理
准备SYTimer工程如下

image.png
// 编译模拟器产物
$ xcodebuild archive -project 'SYTimer.xcodeproj' \
-scheme 'SYTimer' \
-configuration Release \
-destination 'generic/platform=iOS Simulator' \
-archivePath '../archives/SYTimer.framework-iphonesimulator.xcarchive' \
SKIP_INSTALL=NO
// 编译真机产物
$ xcodebuild archive -project 'SYTimer.xcodeproj' \
-scheme 'SYTimer' \
-configuration Release \
-destination 'generic/platform=iOS' \
-archivePath '../archives/SYTimer.framework-iphoneos.xcarchive' \
SKIP_INSTALL=NO

SKIP_INSTALL只有设置成NO,才会把我们的编译产物SYTimer.framework放到Products下。

image.png dSYMs文件:当应用发生崩溃时,可以根据dSYMs文件和崩溃文件,把调用栈恢复出来,所以SDK工程师需要提供dSYMs文件
BCSymbolMaps文件: 打开了bitcode会生成,用于bitcode调试
1.2 合并上面生成的两个framework
$ 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
报错:两个framework都包含arm64架构,相同架构的二进制文件不能打包成胖二进制文件 image.png

解决办法:把模拟器中相同架构删除

// 删除模拟器中arm64架构,输出到SYTimer-x86_64
$ lipo -output SYTimer-x86_64 -extract x86_64 ../archives/SYTimer.framework-iphonesimulator.xcarchive/Products/Library/Frameworks/SYTimer.framework/SYTimer
// 合并真机架构与刚才生成的SYTimer-x86_64架构文件到 SYTimer
$ lipo -output SYTimer -create ../archives/SYTimer.framework-iphoneos.xcarchive/Products/Library/Frameworks/SYTimer.framework/SYTimer  SYTimer-x86_64
合并完成如下图所示 image.png

二. XCFramework

XCFramework的出现就是为了解决上面合并报错,和传统的framework相比:

  1. 可以用单个.xcframework文件提供多个平台的分发二进制文件;
  2. 与Fat Header相比,可以按照平台划分,可以包含相同架构的不同平 台的文件;
  3. 在使用时,不需要再通过脚本去剥离不需要的架构体系。
    查看SYTimer二进制文件架构如下 image.png 当应用上架的时候,x86_64模拟器架构还需要手动剥离,XCFramework的出现就解决了上面剥离的繁琐操作
    2.1 XCFramework初探
    既然XCFramework有那么多优势,接下来就让我们一起探讨
// 进入xcframework文件夹,使用xcframework合并上面两个framework
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'
一个文件就可以包含多个架构,并且架构是按照传递顺序来生成 image.png

2.2 合并framework完成发现并没有symbols调试符号,接下来继续探讨
注意⚠️ 传递调试符号必须是绝对路径

xcodebuild -create-xcframework \
-framework '../archives/SYTimer.framework-iphoneos.xcarchive/Products/Library/Frameworks/SYTimer.framework' \
-debug-symbols '/Users/wangning/Documents/资料/1:25/第五节、动态库 与静态库实战/上课代码/多架构合并/archives/SYTimer.framework-iphoneos.xcarchive/BCSymbolMaps/1FE90BC9-7791-32D3-B864-ACFAC9DD7069.bcsymbolmap' \
-debug-symbols '/Users/wangning/Documents/资料/1:25/第五节、动态库与静态库实战/上课代码/多架构合并/archives/SYTimer.framework-iphoneos.xcarchive/BCSymbolMaps/366D557B-B19A-3DB8-9A3F-E932BCE58BBB.bcsymbolmap' \
-debug-symbols '/Users/wangning/Documents/资料/1:25/第五节、动态库与静态库实战/上课代码/多架构合并/archives/SYTimer.framework-iphoneos.xcarchive/dSYMs/SYTimer.framework.dSYM' \
-framework '../archives/SYTimer.framework-iphonesimulator.xcarchive/Products/Library/Frameworks/SYTimer.framework' \
-debug-symbols '/Users/wangning/Documents/资料/1:25/第五节、动态库与静态库实战/上课代码/多架构合并/archives/SYTimer.framework-iphonesimulator.xcarchive/dSYMs/SYTimer.framework.dSYM' \
-output 'SYTimer.xcframework'
合并之后查看如下图所示 image.png 接下来使用xcframework,如下图所示 image.png 编译完成,查看LGApp中ipa包下的frameworks文件夹,发现在使用的时候会动态的只加载当前需要的架构。

三. 弱引用

3.1创建项目如下

image.png
#import "ViewController.h"
#import <SYTimer.h>

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    SYTimer *timer = [SYTimer new];
    NSLog(@"%@", timer);
}

@end
//xcconfig文件配置如下
FRAMEWORK_SEARCH_PATHS = $(inherited) ${SRCROOT}
HEADER_SEARCH_PATHS = $(inherited) '${SRCROOT}/SYTimer.framework/Headers' 
LD_RUNPATH_SEARCH_PATHS = $(inherited) 
OTHER_LDFLAGS = $(inherited) -framework "SYTimer" 

编译成功,运行时候报错,找不到动态库SYTimer
dyld: Library not loaded: @rpath/SYTimer.framework/SYTimer
Referenced from: /Users/wangning/Library/Developer/CoreSimulator/Devices/C53887CF-B3AC-4677-B6FD-DD090CC6D346/data/Containers/Bundle/Application/651CC63E-F724-4A4E-BE71-51BF0470B945/LGApp.app/LGApp
Reason: image not found
3.2 修改xcconfig文件如下

FRAMEWORK_SEARCH_PATHS = $(inherited) ${SRCROOT}
HEADER_SEARCH_PATHS = $(inherited) '${SRCROOT}/SYTimer.framework/Headers' 
LD_RUNPATH_SEARCH_PATHS = $(inherited) 
// weak:允许该库在运行时消失。
OTHER_LDFLAGS = $(inherited) -Xlinker -weak_framework -Xlinker "SYTimer"

运行成功,打印null
查看ipa包LGApp文件

$ otool -l /Users/wangning/Library/Developer/Xcode/DerivedData/LGApp-adhpusbeokaxbtazgqzkquzynndv/Build/Products/Debug-iphonesimulator/LGApp.app/LGApp
可以看出来 cmd LC_LOAD_WEAK_DYLIB 弱引用 image.png

四. 静态库冲突

4.1创建项目如下,其中两个AFNetworking文件只是名称不同

image.png
4.2配置xcconfig文件如下
//-I
HEADER_SEARCH_PATHS = $(inherited) "${SRCROOT}/AFNetworking" "${SRCROOT}/AFNetworking2"
//-L
LIBRARY_SEARCH_PATHS = $(inherited) "${SRCROOT}/AFNetworking" "${SRCROOT}/AFNetworking2"
OTHER_LDFLAGS = $(inherited) -all_load -l"AFNetworking" -l"AFNetworking2"
此时编译工程会报符号冲突 image.png

修改xcconfig文件如下,避免oc文件全部加载导致符号冲突

//-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"

五. 动态库与静态库相互链接

5.1动态库链接动态库
首先创建动态库LGNetworkManager,内容如下

// LGAFNetworkingManager.h文件
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface LGAFNetworkingManager : NSObject
+ (instancetype)manager;
@end

NS_ASSUME_NONNULL_END
//LGAFNetworkingManager.m文件
#import "LGAFNetworkingManager.h"
#import <AFNetworking/AFNetworking.h> 

@implementation LGAFNetworkingManager
+ (instancetype)manager {
    
    NSLog(@"%@", [AFNetworkReachabilityManager manager]);
    return [LGAFNetworkingManager new];
}
@end
// 使用use_frameworks 说明引用的动态库
platform :ios, '14.1'
target :'LGNetworkManager' do
   use_frameworks!
  pod 'AFNetworking'
end

工程引用动态库LGNetworkManager,LGNetworkManager引用AFNetworking
编译成功,运行报错 image not found,LGNetworkManager使用的动态库AFNetworking找不到
解决办法1:

// 参考cocoapods中脚本,动态的把AFNetworking复制到frameworks目录下
if [[ "$CONFIGURATION" == "Release" ]]; then
  install_framework "${BUILT_PRODUCTS_DIR}/AFNetworking/AFNetworking.framework"
fi

解决办法2:

// 修改podfile文件,把AFNetworking复制到工程frameworks目录下
platform :ios, '14.1'
target :'LGNetworkManager' do
   use_frameworks!
  pod 'AFNetworking'
end
//LGNetworkManagerTests 工程名,这里使用的单元测试工程
target :'LGNetworkManagerTests' do
   use_frameworks!
  pod 'AFNetworking'
end

现在有一个问题,如果动态库LGNetworkManager要引用LGNetworkManagerTests中内容,该怎么解决?
首先在LGNetworkManagerTests中创建类LGAppObject,里面添加一个测试方法test_app,然后在动态库LGNetworkManager中引用LGAppObject,如下所示

#import "LGAFNetworkingManager.h"
#import <AFNetworking/AFNetworking.h> 
#import "LGAppObject.h"

@implementation LGAFNetworkingManager
+ (instancetype)manager {
    
    NSLog(@"%@", [AFNetworkReachabilityManager manager]);
    LGAppObject *obj = [LGAppObject new];
    [obj test_app];
    return [LGAFNetworkingManager new];
}
@end

编译之后报错,找不到OBJC_CLASS$_LGAppObject符号
解决办法

// Pods-LGNetworkManager.debug.xcconfig 文件配置如下
// 指定_OBJC_CLASS_$_LGAppObject是动态查找符号
OTHER_LDFLAGS = $(inherited) -framework "AFNetworking" -Xlinker -U -Xlinker _OBJC_CLASS_$_LGAppObject

5.2动态库链接静态库
还是上面例子,此时修改podfile文件即可

// 注释use_frameworks! 即可引用静态库
platform :ios, '14.1'
target :'LGNetworkManager' do
//   use_frameworks!
  pod 'AFNetworking'
end

编译链接不会报错,原因是 编译动态库的时候,会把依赖的静态库代码整个链接到动态库中
现在有一个问题,主工程可以使用静态库中的代码吗?

静态库对动态库来说是导出符号,同样的对主工程来说也是导出符号,所以是可以使用的,需要进行如下配置 image.png 接下来是第二个问题,动态库会把静态库代码全部链接作为导出符号,如果不想把静态库导出提供给外部使用,该怎么解决?
解决办法:把AFNetworking隐藏调即可
// xc文件修改前
OTHER_LDFLAGS = $(inherited) -ObjC -l"AFNetworking"
// xc文件修改后
OTHER_LDFLAGS = $(inherited) -ObjC -Xlinker -hidden-l"AFNetworking"

5.3静态库链接静态库
编译失败分析:app链接组件静态库,组件静态库链接静态库,编译时候会报错,找不到静态库的符号OBJC_CLASS$_AFNetworking?
解决办法1:

//配置路径如下图所示
${BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/AFNetworking
image.png image.png

解决办法2:

// 修改podfile文件,把静态库直接导入主程序
platform :ios, '14.1'
target :'LGNetworkManagerTests' do
  // use_frameworks!
  pod 'AFNetworking'
end

5.4静态库链接动态库
首先我们来分析一下 app链接静态库,会把静态库代码全部链接到app中,静态库链接动态库,需要把动态库链接到app里面,app才能使用动态库
编译失败:找不到动态库符号
解决办法:

// 配置路径如下图所示
"${BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/AFNetworking"
image.png 编译成功,运行失败,动态库找不到 image not found
解决办法:类似于动态库链接动态库 的两种方案
关于第一种解决方案操作
首先把cocoapods中脚本复制到以下目录 image.png 接下来在工程中配置Run Script脚本 image.png 5.5工程中导入静态库与动态库
如果在工程中即导入静态库又导入动态库,该怎么解决?
// podfile文件配置如下
platform :ios, '14.1'
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

另外还有一点:如果有多个xcworkspace文件 cocoapods中podfile文件还可以指定为哪一个xcworkspace文件导入三方库

// 修改podfile文件,把静态库直接导入主程序
platform :ios, '14.1'
// 指定workspace
workspace '../MultiProject.xcworkspace'
target :'LGFramework' do
  use_frameworks!
  pod 'AFNetworking'
end
// 指定app
target :'LGApp' do
  // 指定app路径
  project '../LGApp/LGApp.xcodeproj'
  use_frameworks!
  pod 'AFNetworking'
end

总结:

当一个动态库运行时,不能够保证它永远都在指定的运行位置,就要使用弱引用

相关文章

  • xcframework生成与使用

    xcframework生成与使用 1、XCFramework定义? XCFramework:是苹果官⽅推荐的、⽀持...

  • flutterboost PlatformException(c

    iOS混编flutter项目原因。flutter导出的xcframework。有高德地图.xcframework。...

  • 动态库下(5)

    动态库下(5) XCFramework XCFramework: 是苹果官方推荐的, 支持的, 可以更方便的表示一...

  • iOS XCFramework

    XCFramework XCFramework是苹果官方2019年提出的Framework的另一种先进格式,可以更...

  • XCFramework

    前言 XCFramework:是苹果官方推荐的,支持的,可以更方便的表示一个多个平台结构的分发二进制的格式。需要X...

  • iOS:XCFramework

    1.XCFramework XCFramework:是苹果官方推荐的,支持的,可以更方便的表示一个多个平台结构的分...

  • XCFramework制作

    XCFramework XCFramework是苹果官方推荐的、支持的,可以更方便的表示一个多个平台和架构的分发二...

  • 创建XCFramework

    XCFramework简介 XCFramework是XCode11中提出的一个新特性,是由XCode创建的一个可分...

  • 如何创建XCFrameWork

    xcodebuild -create-xcframework -framework /Users/wangxin/...

  • 打包xcframework

    替换下面的值 WorkSpaceName FrameworkName 路径

网友评论

      本文标题:XCFramework

      本文链接:https://www.haomeiwen.com/subject/mazpxltx.html