1 什么是xcframework 以及 为什么要使用xcframwork
XCFramework (framework的增强版)
-
1. 苹果官方推荐,支持的,可以更加方便多个平台和架构的分发二进制库的格式。
-
2. 需要xcode11以上支持
-
3. 在2019年提出的framework的另一种先进格式。
-
4 不用剥离架构
-
5 m1的电脑 framework 模拟和真机不能合并,只能使用XCFramework
-
XCFrameworks 和之前 Framework 对比 : :https://juejin.cn/post/6844904031937101838
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 组件化混编之路(二)- 工程化 : 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)]
可以看到只有动态库才会调用
对于静态库.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化





网友评论