美文网首页
2024-03-15

2024-03-15

作者: 蛋Dan | 来源:发表于2025-10-16 14:10 被阅读0次

    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化

    相关文章

      网友评论

          本文标题:2024-03-15

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