2024-03-15

1 什么是xcframework 以及 为什么要使用xcframwork

XCFramework (framework的增强版)

  1. 1. 苹果官方推荐,支持的,可以更加方便多个平台和架构的分发二进制库的格式。

  2. 2. 需要xcode11以上支持

  3. 3. 在2019年提出的framework的另一种先进格式。

  4. 4 不用剥离架构

  5. 5 m1的电脑 framework 模拟和真机不能合并,只能使用XCFramework

  6. XCFrameworks 和之前 Framework 对比 : :https://juejin.cn/post/6844904031937101838

2 怎么生成xcframwork(源码/framework/.a)

  1. 源码:

    直接用xcode或xcodebuild命令
    
  2. Framework

 xcodebuild -create-xcframework -framework iphonesimulator/NvStreamingSdkCore.framework -framework NvStreamingSdkCore.framework -output NvStreamingSdkCore.xcframework
xcodebuild -create-xcframework -library <path> [-headers <path>] [-library <path> [-headers <path>]...] -output <path>

d. 生成带有dsym文件的xcframework. 坑: -debug-symbols 参数需要用全路径,-framework 不用全路径

xcodebuild -create-xcframework -framework iphonesimulator/NvStreamingSdkCore.framework -debug-symbols /Users/shan/Downloads/NvStreamingSdk_IOS_3.8.2.17_20230707_165743/lib/ios/iphonesimulator/NvStreamingSdkCore.dSYM  -framework NvStreamingSdkCore.framework  -debug-symbols /Users/shan/Downloads/NvStreamingSdk_IOS_3.8.2.17_20230707_165743/lib/ios/NvStreamingSdkCore.dSYM -output NvStreamingSdkCore.xcframework

3 组件如何 Module 化(modular)

关于Module的参考:

百度 App Objective-C/Swift 组件化混编之路(二)- 工程化 : https://xie.infoq.cn/article/7e29766cbac9d1d182f5f64c6

使用自定义 Module 解决 Objective-C 库的引用 : https://chaosky.tech/2020/08/03/cocoapods-custom-swift-module/

Swift与Objective-C混编时,我们是如何将编译时间优化了35%?:https://blog.csdn.net/csdnnews/article/details/120139297

1 源码如何 Module 化

2 Framework如何 Module 化

3 .a 如何 Module 化

对应demo 参见目录:/Users/shan/Documents/meipian_f

测试环境:

macOS12.6 Xcode13

SWift类如何引用 .a 静态库:

方法1:

如果是主工程,在xxx-Bridging-Header.h 添加静态库的头文件即可引用;如果是pod库,则可以在和pod库同名的头文件中,添加静态库的头文件即可引用。

方法2:

对静态库进行包装,参见demo: (https://github.com/chaoskyx/Demo/raw/master/GDTPackage.zip. , 文章: https://github.com/xwal/xwal.github.io/issues/19, https://chaosky.tech/2020/08/03/cocoapods-custom-swift-module/ ),; GDTMobSDK是 .a 静态库,GDTPackage对GDTMobSDK封装之后,可以直接在Swift文件中 import GDTMobSDK

方法3:

把 .a 静态库转换为framework,然后进行module化,可行; 还可以进一步把module后的framework转为xcframework. 转化方法参见:https://www.cnblogs.com/yunteng/p/8028142.html 或自行搜索;

注意:去掉.a后缀的时候,要右击显示间接中去掉

[图片上传失败...(image-5034bb-1710488079021)]

参见demo: 点a静态库转framework

方法4:

.a静态库 难道不能直接 module化?module化之后,直接在swift文件中 import ,可行

参见demo: 点a静态库直接module化, 这里最坑的地方在于, 自定义的modulemap要通过s.source_files引入,通过s.module_map 无法引入,

// modulemap要配置在source_files中,配置在module_map中不起作用

[图片上传失败...(image-b96468-1710488111215)]

[图片上传失败...(image-2f1c3f-1710488079021)]

因为这个问题花费了 我两天时间,直到看到这篇文章: 制作自己的CocoaPods公开库(涉及modulemap) https://www.jianshu.com/p/88ff2e01db02

期间,在stackoverflow 上找了很久,也没找到解决办法:

找过的资料:

```

How to import Objective C static library to Swift Framework? (https://stackoverflow.com/questions/31751547/how-to-import-objective-c-static-library-to-swift-framework)

```

资料都说了怎么定义modulemap,但是都没有说,怎么通过pod引入自定义的modulemap,

后来在官方资料上看到对module_map的解释,之前没仔细看:

[图片上传失败...(image-227aa-1710488111216)]

[图片上传失败...(image-be9286-1710488079021)]

https://guides.cocoapods.org/syntax/podspec.html#swift_versions

也就是module_map 只对 framework 才有效,对.a静态库无效,

在官方文档上没有找到,对.a静态库无效 自定义modulemap的说明。

方法5:

 .a静态库直接转为xcframework, 然后module化;可以解决 模拟器arm64架构和真机arm64架构和不能合并的问题; 参见demo: 点a静态库转xcframework的module化,

遇到的奇怪问题:

1\. 如果libNvPhotoAlbumHelper.xcframework 同目录下有同名的framework libNvPhotoAlbumHelper.framework ,并且framework 有Modules/module.modulemap,在podspec中直接这么写,如下图,可以编译通过, 在主工程中直接@libNvPhotoAlbumHelper 方式引入,也可以正常使用,编程通过。 为什么?为什么?

[图片上传失败...(image-580453-1710488079021)]

[图片上传失败...(image-789601-1710488111216)]

如果删除同目录下的libNvPhotoAlbumHelper.framework,就会报错;但是只保留libNvPhotoAlbumHelper.framework中的Modules也不会报错。

1\. 如果libNvPhotoAlbumHelper.xcframework 同目录下,不存在同名的framework libNvPhotoAlbumHelper.framework ,podspec中这么写也不会报错:

[图片上传失败...(image-84e6ff-1710488111216)]

[图片上传失败...(image-a731c9-1710488079021)]

但是,奇怪的是 自定义的"Module/Lottie.modulemap",并没有用,有用的是自动生成的NvPhotoAlbumH.modulemap

[图片上传失败...(image-f88530-1710488111216)]

[图片上传失败...(image-226f65-1710488079021)]

哪怕删除Lottie.modulemap 文件中的所有内容,也不影响;但是不通过source_files引入Lottie.modulemap就不会生成自动NvPhotoAlbumH.modulemap;

也就是只要通过 s.source_files 引入xx.modulemap 文件,就会触发自动生成的功能。

1\. 如果在上面的基础上传加了 s.module_map,podsepc如下:

 [图片上传失败...(image-7b97f0-1710488111216)]

[图片上传失败...(image-72ada6-1710488079021)]

这时也会自动生成NvPhotoAlbumH.modulemap了,但是生成的NvPhotoAlbumH.modulemap中的内容就是引入的Lottie.modulemap的内容;

 如果source_files中不引入modulemap,只在module_map中引入,会发现没有用;

modulemap文件 注意:

module * { export * } 和 export * 的区别

可以发现module * { export * } 会直接把所有 .h 中的方法, 直接导入到当前的 module 中。 另外只有umbrella才可以使用module * { export * }。

4 胖二进制文件和瘦二进制文件

.a库可以把模拟器库和真机库合并为一个库,打包的时候不用做处理理,不论是直接添加到主工程还是通过pod库引用, xcode会自动去掉不需要的架构;

但是m1电脑出现之后,模拟器库也需要arm64, 也就是真机的arm64和模拟器的arm64 不通用,所以需要合并,通过下面命令合并的时候会报错:


lipo -create libNvPhotoAlbumHelper.a iphonesimulator/libNvPhotoAlbumHelper.a -output libNvPhotoAlbumHelper_fat.a


fatal error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: libNvPhotoAlbumHelper.a and iphonesimulator/libNvPhotoAlbumHelper.a have the same architectures (arm64) and can't be in the same fat output file

无法合并,所以如果想提供一份在m1电脑上,即能在模拟器运行,又能在真机运行的.a文件是做不到的。但是在非m1电脑上是可以的。

对与m1电脑上 ,想即能在模拟器运行,有能在真机运行, 只能把.a 转为xcframewwork

由于NvStreamingSdkCore.framework包含模拟器和真机架构,所以直接拖到主工程,在xode13上会报一下错误:

[图片上传失败...(image-b0846a-1710488111216)]

[图片上传失败...(image-e5a68f-1710488079022)]

[图片上传失败...(image-344d4c-1710488079022)]

[图片上传失败...(image-29766b-1710488111216)]

[图片上传失败...(image-30e18e-1710488079022)]

[图片上传失败...(image-61e46b-1710488111216)]

注意需要设置embed值如下:

[图片上传失败...(image-206f82-1710488111216)]

[图片上传失败...(image-3145e3-1710488079022)]

但是上面的错误在xode14上,不会出现,直接可以编译成功,可以直接在真机或模拟器上运行, 但是不能上传AppStore,上传App Store时会报错。

[图片上传失败...(image-15e1c2-1710488111216)]

[图片上传失败...(image-42713e-1710488079022)]

在Xcode13以及一下,用pod引入的时候,为什么动态framework即使包含模拟器和真机架构,也不会报错,这是为什么呢? 因为pod帮你做了这件事,在pod install之后,在工程配置中会生成如下配置:

[图片上传失败...(image-d5b561-1710488111216)]

[图片上传失败...(image-dd7e69-1710488079022)]

这是在编译时会执行的脚本,

找到对应的文件,我们可以看看脚本内容:其中有一个方法,这个方法就是去掉真机架构或模拟器架构的:

[图片上传失败...(image-8dac82-1710488111216)]

[图片上传失败...(image-93b1e9-1710488079022)]

调用的地方如下:

[图片上传失败...(image-14738-1710488111216)]

[图片上传失败...(image-550745-1710488079022)]

可以看到只有动态库才会调用

https://qiyukf.com/docs/guide/ios/2-%E6%8E%A5%E5%85%A5%E8%AF%B4%E6%98%8E.html#%E5%85%B6%E5%AE%83%E8%AF%B4%E6%98%8E

对于静态库.a 或 静态库framework, 即使是模拟器和真机合在一起也是可以直接运行的,

[图片上传失败...(image-a0943a-1710488111216)]

比如 libNvPhotoAlbumHelper.framework 直接拖入主工程是可以运行的

对于没有modulemap的framework, 可以自己添加一个,进行module化,参见:Swift:巧用module.modulemap,告别Bridging-Header.h

https://juejin.cn/post/7139724115157450765

XCFrameworks 和之前 Framework 对比 : https://juejin.cn/post/6844904031937101838

5 参考:

iOS 中的库与框架:https://kingcos.me/posts/2019/libraries_in_ios/

理解Objective-C的Modules : https://www.getit01.com/p20190101251194169/

整理一下脑子里混乱的Architectures : https://juejin.cn/post/7034782069410496542

iOS静态库和动态库的底层原理 : https://www.jianshu.com/p/d34081fa0e31

使用 Xcode 制作 Framework 与 XCFramework : https://www.jianshu.com/p/14f2e2236d34

细说iOS静态库和动态库: https://juejin.cn/post/6844904031937101838

iOS开发进阶八:Module(模块) : https://www.jianshu.com/p/d7c99187de6e

Swift和Objective-C混编在有赞移动的实践 原创 : https://blog.51cto.com/u_15127581/2740945

从零开始编写iOS混编SDK(下) : https://www.jianshu.com/p/436869f54b95

百度 App Objective-C/Swift 组件化混编之路(二)- 工程化 : https://xie.infoq.cn/article/7e29766cbac9d1d182f5f64c6

使用自定义 Module 解决 Objective-C 库的引用 : https://chaosky.tech/2020/08/03/cocoapods-custom-swift-module/

understand-ios-library-and-framework : http://chuquan.me/2021/02/14/understand-ios-library-and-framework/

京东App Swift 混编及组件化落地 : https://developer.jdcloud.com/article/1965

Swift 关于 module.modulemap 使用 : https://www.jianshu.com/p/ce49d8f32f77

Swift Framework 自定义 Module : https://www.jianshu.com/p/b4f88651f069

modulemap : https://www.jianshu.com/p/22f6c23c3ab4


modulemap编译

module中C和OC要分开编译, C++可以和C一起编译, C++也可以和OC一起编译。

当OC 和C 一起需要添加requires objc

module OCTest {

requires objc

header "OCTest.h"

export *

umbrella "Subs/OCSubs" // 单独把 Subs 中的 OC 文件, 单独列出来, 否则会编译失败

module * { export * }

}

由于Swift不能直接调用C++代码, 所以一般会导出C和OC文件。

Swift中不能直接调用C++代码,但是可以调用c代码, 通过void*生成c++对象, 通过c来调用C++

作者:JerrySi

链接:https://www.jianshu.com/p/22f6c23c3ab4

来源:简书

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

各种各样的modulemap(modulemap language:swift) https://github.com/search?utf8=%E2%9C%93&q=modulemap+language%3Aswift&type=

6 私有库打包怎么自动生成xcframework

1 自己写脚本 2 修改pod package 3基于carthage 4 基于SPM

基于carthage:

1. 用carthage,如果库本身就支持carthage,可以直接用carthage 命令直接生成

2. 如果不支持carthage,只支持pod, 可以用:

1. 直接用pod, 以SDWebImage为例

新建工程SDWebImageDemo, podfile 如下

[图片上传失败...(image-8921ee-1710488111216)]

[图片上传失败...(image-970d8e-1710488079021)]

然后执行命令


carthage build --platform iOS --no-skip-current --use-xcframeworks

会报错:


Dependency "SDWebImageDemo" has no shared framework schemes for any of the platforms: iOS

报错的原因是:pod默认生成的是 .a 不是framework,

[图片上传失败...(image-bd373b-1710488111216)]

[图片上传失败...(image-513180-1710488079021)]

也就是默认是下图中的2, 但是我们需要的是1

[图片上传失败...(image-60f038-1710488111216)]

[图片上传失败...(image-afbca3-1710488079021)]

怎么让pod库,默认生成1呢?

在 podfile中加入 use_frameworks! 就可以了

[图片上传失败...(image-9477b8-1710488111216)]

[图片上传失败...(image-bac7ba-1710488079021)]

加入之后,pod install 之后

[图片上传失败...(image-d49538-1710488111216)]

[图片上传失败...(image-9bbe09-1710488079021)]

发现已经变了,

这时 在执行命令


carthage build --platform iOS --no-skip-current --use-xcframeworks

发现还是报错


Dependency "SDWebImageDemo的" has no shared framework schemes for any of the platforms: iOS

需要点击 Manage Schemes...

[图片上传失败...(image-937835-1710488111216)]

[图片上传失败...(image-68aacb-1710488079021)]

选中Shared

[图片上传失败...(image-480eb9-1710488079021)]

[图片上传失败...(image-3a3332-1710488111216)]

然后就可以。

但是还有个问题,这么编译出来的xcframework是动态库,

怎么编译为静态库呢;

有三种方法:

1 手动修改 ,然后编译

[图片上传失败...(image-77d2c1-1710488111216)]

[图片上传失败...(image-c1eb9b-1710488079021)]

2 在podspec 中添加

s.static_framework = true

3 在podfile 文件中添加,把 多有 pod库都修改为静态库


post_install do |installer|

 installer.pods_project.targets.each do |target|

 target.build_configurations.each do |config|

 config.build_settings['MACH_O_TYPE'] = 'staticlib'

 end

 end

end

然后就可以生成静态xcframework 了

除了用carthage生成xcframework外,还可以用脚本生成,网上有很多,感兴趣的可以去看看,

用脚本生成,需要先配置工程,比较麻烦,所以我就不用了

最近发现了可以根据podsepec直接生成xcframework的工具,类似pod package

cocoapods-xcframework : https://github.com/TyrantDante/cocoapods-xcframework

可能存在的问题

swift oc库混合编译问题

7 私有库规范

pod子spec的问题,依赖问题,怎么生成xcframework

第三方sdk不支持arm64模拟器,podsepc需要加,但是自己的源码的pod spec可以不加

最小app

1 业务库之间不能有依赖

2 不能有子podspec

3要能@import 也就是能module化

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • """1.个性化消息: 将用户的姓名存到一个变量中,并向该用户显示一条消息。显示的消息应非常简单,如“Hello ...
    她即我命阅读 8,647评论 0 5
  • 为了让我有一个更快速、更精彩、更辉煌的成长,我将开始这段刻骨铭心的自我蜕变之旅!从今天开始,我将每天坚持阅...
    李薇帆阅读 6,192评论 1 4
  • 似乎最近一直都在路上,每次出来走的时候感受都会很不一样。 1、感恩一直遇到好心人,很幸运。在路上总是...
    时间里的花Lily阅读 5,306评论 0 2
  • 1、expected an indented block 冒号后面是要写上一定的内容的(新手容易遗忘这一点); 缩...
    庵下桃花仙阅读 3,638评论 0 1
  • 一、工具箱(多种工具共用一个快捷键的可同时按【Shift】加此快捷键选取)矩形、椭圆选框工具 【M】移动工具 【V...
    墨雅丫阅读 3,619评论 0 0

友情链接更多精彩内容