1 什么是xcframework 以及 为什么要使用xcframwork
XCFramework (framework的增强版)
-
- 苹果官方推荐,支持的,可以更加方便多个平台和架构的分发二进制库的格式。
-
- 需要xcode11以上支持
-
- 在2019年提出的framework的另一种先进格式。
-
4 不用剥离架构
-
5 m1的电脑 framework 模拟和真机不能合并,只能使用XCFramework
-
XCFrameworks 和之前 Framework 对比 : :juejin.cn/post/684490…
2 怎么生成xcframwork(源码/framework/.a)
-
源码:
- 直接用xcode或xcodebuild命令
-
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 组件化混编之路(二)- 工程化 : xie.infoq.cn/article/7e2…
使用自定义 Module 解决 Objective-C 库的引用 : chaosky.tech/2020/08/03/…
Swift与Objective-C混编时,我们是如何将编译时间优化了35%?:blog.csdn.net/csdnnews/ar…
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: (github.com/chaoskyx/De…. , 文章: github.com/xwal/xwal.g… chaosky.tech/2020/08/03/… ),; GDTMobSDK是 .a 静态库,GDTPackage对GDTMobSDK封装之后,可以直接在Swift文件中 import GDTMobSDK
方法3:
把 .a 静态库转换为framework,然后进行module化,可行; 还可以进一步把module后的framework转为xcframework. 转化方法参见:www.cnblogs.com/yunteng/p/8… 或自行搜索;
注意:去掉.a后缀的时候,要右击显示间接中去掉
参见demo: 点a静态库转framework
方法4:
.a静态库 难道不能直接 module化?module化之后,直接在swift文件中 import ,可行
参见demo: 点a静态库直接module化, 这里最坑的地方在于, 自定义的modulemap要通过s.source_files引入,通过s.module_map 无法引入,
// modulemap要配置在source_files中,配置在module_map中不起作用

因为这个问题花费了 我两天时间,直到看到这篇文章: 制作自己的CocoaPods公开库(涉及modulemap) www.jianshu.com/p/88ff2e01d…
期间,在stackoverflow 上找了很久,也没找到解决办法:
找过的资料:
```
How to import Objective C static library to Swift Framework? (stackoverflow.com/questions/3…)
```
资料都说了怎么定义modulemap,但是都没有说,怎么通过pod引入自定义的modulemap,
后来在官方资料上看到对module_map的解释,之前没仔细看:

guides.cocoapods.org/syntax/pods…
也就是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 方式引入,也可以正常使用,编程通过。 为什么?为什么?

如果删除同目录下的libNvPhotoAlbumHelper.framework,就会报错;但是只保留libNvPhotoAlbumHelper.framework中的Modules也不会报错。
1. 如果libNvPhotoAlbumHelper.xcframework 同目录下,不存在同名的framework libNvPhotoAlbumHelper.framework ,podspec中这么写也不会报错:

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

哪怕删除Lottie.modulemap 文件中的所有内容,也不影响;但是不通过source_files引入Lottie.modulemap就不会生成自动NvPhotoAlbumH.modulemap;
也就是只要通过 s.source_files 引入xx.modulemap 文件,就会触发自动生成的功能。
1. 如果在上面的基础上传加了 s.module_map,podsepc如下:

这时也会自动生成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上会报一下错误:



注意需要设置embed值如下:

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

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

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

调用的地方如下:

可以看到只有动态库才会调用
对于静态库.a 或 静态库framework, 即使是模拟器和真机合在一起也是可以直接运行的,

比如 libNvPhotoAlbumHelper.framework 直接拖入主工程是可以运行的
对于没有modulemap的framework, 可以自己添加一个,进行module化,参见:Swift:巧用module.modulemap,告别Bridging-Header.h
XCFrameworks 和之前 Framework 对比 : juejin.cn/post/684490…
5 参考:
iOS 中的库与框架:kingcos.me/posts/2019/…
理解Objective-C的Modules : www.getit01.com/p2019010125…
整理一下脑子里混乱的Architectures : juejin.cn/post/703478…
iOS静态库和动态库的底层原理 : www.jianshu.com/p/d34081fa0…
使用 Xcode 制作 Framework 与 XCFramework : www.jianshu.com/p/14f2e2236…
细说iOS静态库和动态库: juejin.cn/post/684490…
iOS开发进阶八:Module(模块) : www.jianshu.com/p/d7c99187d…
Swift和Objective-C混编在有赞移动的实践 原创 : blog.51cto.com/u_15127581/…
从零开始编写iOS混编SDK(下) : www.jianshu.com/p/436869f54…
百度 App Objective-C/Swift 组件化混编之路(二)- 工程化 : xie.infoq.cn/article/7e2…
使用自定义 Module 解决 Objective-C 库的引用 : chaosky.tech/2020/08/03/…
understand-ios-library-and-framework : chuquan.me/2021/02/14/…
京东App Swift 混编及组件化落地 : developer.jdcloud.com/article/196…
Swift 关于 module.modulemap 使用 : www.jianshu.com/p/ce49d8f32…
Swift Framework 自定义 Module : www.jianshu.com/p/b4f88651f…
modulemap : www.jianshu.com/p/22f6c23c3…
```
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
链接:www.jianshu.com/p/22f6c23c3…
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
```
#
各种各样的modulemap(modulemap language:swift) github.com/search?utf8…
6 私有库打包怎么自动生成xcframework
1 自己写脚本 2 修改pod package 3基于carthage 4 基于SPM
基于carthage:
1. 用carthage,如果库本身就支持carthage,可以直接用carthage 命令直接生成
2. 如果不支持carthage,只支持pod, 可以用:
1. 直接用pod, 以SDWebImage为例
新建工程SDWebImageDemo, podfile 如下

然后执行命令
```
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,

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

怎么让pod库,默认生成1呢?
在 podfile中加入 use_frameworks! 就可以了

加入之后,pod install 之后

发现已经变了,
这时 在执行命令
```
carthage build --platform iOS --no-skip-current --use-xcframeworks
```
发现还是报错
```
Dependency "SDWebImageDemo的" has no shared framework schemes for any of the platforms: iOS
```
需要点击 Manage Schemes...

选中Shared

然后就可以。
但是还有个问题,这么编译出来的xcframework是动态库,
怎么编译为静态库呢;
有三种方法:
1 手动修改 ,然后编译

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 : github.com/TyrantDante…
可能存在的问题
swift oc库混合编译问题
7 私有库规范
pod子spec的问题,依赖问题,怎么生成xcframework
第三方sdk不支持arm64模拟器,podsepc需要加,但是自己的源码的pod spec可以不加
最小app
1 业务库之间不能有依赖
2 不能有子podspec
3要能@import 也就是能module化