iOS成长之路

Cocoapods组件私有库创建Framework

2022-08-10  本文已影响0人  AdamShi

公司有个新的项目A,项目A的需求是: 把已有的项目B中的某些页面及功能封装成SDK,涉及到的场景和技术点是:
1.依赖了cocoapods三方库,比如AFNetworking, SDWebImage等,所以要解决三方库依赖
2.项目主要是OC,但是也有一些Swift类做的混编,所以Framework里面要考虑混编的问题
3.项目有多语言国际化,需要考虑bundle切换
4.测试工程要能源码断点调试,最好也能jenkins自动打包
5.能脚本自动化出包
6.后期做组件化,技术方案最好能低成本切换到组件化


先做技术调研评估和选型,封装Framework有如下方式:

1.Framework的project工程

目前网上大部分文章都是这个方案,我做了下总结:
网址: iOS SDK Framework封装
优点:文档比较全,工程独立,代码逻辑清晰
缺点:代码同步问题,如果项目B中的代码或资源有改动,需要手动将改动复制到SDK中

2.已有项目直接添加target

已有项目要打包成Framework,可以试试在已有项目中添加target,target的类型是Framework
优点:直接复用项目B中代码,不需要同步代码,复制改动
缺点:项目B中需要添加SDK逻辑,后面逻辑会越来越混乱,难以维护
具体参考: iOS封装framework

3.cocoapods组件私有库创建Framework

创建cocoapods私有库,方便调试,可以用cocoapods的package工具打包
优点:工程独立,代码逻辑清晰; 跟方案1比较的话,cocoapods三方库依赖管理更简单.附带demo.有专门的打包工具package
缺点:代码同步问题,如果项目B中的代码或资源有改动,需要手动将改动复制到SDK中

最终觉得方案3比较合适,做过组件化的都很熟悉


关于动态库和静态库

关于动态库和静态库网上讲的很多了.网上大部分还是说用static打包成静态库. 但是自从iOS8开始,已经允许动态库上架了, 而且动态库获取资源bundle和资源文件更为简单,所以推荐打成动态库
【iOS】使用workspace搭建SDK开发框架
iOS 最全动态库/静态库制作 Framework/.a
iOS之深入解析静态库和动态库

一.创建私有库组件

二.导入类

最耗时间的工作,抽丝剥茧,把页面依赖的类都抽出来
导入头文件,可以用@class?

三.导入资源文件

最好全局搜索bundle,image,nib,xib,html,js或其他资源关键字,修改所有涉及到的资源等等

获取资源文件方式, 基本都是先拿到bundle包路径,然后再通过bundle加载资源

框架和业务分离
iOS:NSBundle的一些理解
iOS SDK(二):Bundle 创建 & 使用
NSBundle使用
注意: 动态库和静态库获取资源的方式是不一样的
【iOS】使用workspace搭建SDK开发框架

1.image

2.xib

3.多语言

4.字体

一般加载字体都是静态加载,需要在info.plist提前声明用了什么字体; 私有库中一般不会要求集成方做这个设置,所以一般用动态加载字体方式:
如何向 Cocoapod 添加自定义字体?
iOS动态字体加载及坑
iOS 动态加载字体
iOS 组件化实战篇(私有库)
cocoapods 管理图片资源和字体库
iOS中使用自定义字体, 动态下载字体

5.bundle的管理

a.如果封装的是动态库,那么不需要对bundle做特殊处理,cocoapods会自动链接并把bundle打包到framework里面
b.如果封装的是静态库framework,那么bundle的管理会很麻烦.组件打包时,需要在pod-sdk'starget-Build Phases-Copy Bundle Resources中,手动链接bundle文件,而且SDK使用方需要添加个脚本,把静态bundle拷贝到APP中,才能寻找到bundle文件

四.修改podspec文件

官网: cocoapods官网podspec文档
CocoPods之.podspec语法参考
s.source源应该改为本地路径?

///保持路径?
spec.header_mappings_dir = 'XXXSDK/Classes/**'

五.OC和Swift混编

私有库中混编:

1.OC调用Swift:

swift添加public关键字,如果不行,就添加open关键字; 查文档说最好用open,public的话,有可能出现找不到类或者方法等等问题
如果这个swift类还调用了其他的swift三方库,会崩溃,查了很久发现需要在podspec添加配置s.swift_version = '5.0'指定swift版本就行了

引用swift头文件方式
#import <XXXSDK/XXXSDK-Swift.h>
2.Swift调用OC

系统自动生成XXX-umbrella.h

参考:
CocoaPods 制作私有库 Swift/OC 过程、注意点和错误总结
进阶-Swift和OC混编生成 swift pod私有库
OC和Swift混编, 在Cocoapods私有库中的用法
Swift/Objective-C-使用Cocoapods创建/管理私有库(高级用法)
OC和Swift混合开发(Pod私有库的相互引用)
组件化开发之-如何解决Swift/OC-Framenwork/Library混合创建pod问题
制作Swift和Objective-C Mixed的Pod
如何在模块化/组件化项目中实现 ObjC-Swift 混编?
CocoaPods组件化之OC与Swift混编问题
iOS组件化 pod命令创建私有库详解【引用其他私有库、oc、Swift混编】
Swift和OC在同一个库中如何实现混编?
iOS Swift 创建的私有库与oc混编报错"#import <xxx/xxx.h> file not found"
iOS使用Cocoapods对Swift和OC进行混编
Swift和Objective-C混编在有赞移动的实践

六.出包

两种方式,推荐第二种方式

1.安装cocoapods package插件,专用于打包.

这种方式不太推荐,因为这个插件已经很久不更新了,直接用的话还有问题, 而且好像不支持最新的xcframework格式的包
【cocoapods】-cocoapods-packager打包静态库
iOS开发之CocoaPods:插件篇一 CocoaPods Packager
IOS pod package 报错:Pods/build/package.a and Pods/build-sim/package.a have the same architectures
使用cocoapods package打包

package打包命令,好像都可以:
1.
//打包静态framework 用这个
pod package xxx.podspec --force --no-mangle --embedded
//打包静态.a 用这个
pod package xxx.podspec --library --force

2.
pod package xxx.podspec --force --no-mangle --exclude-deps
2.xcodebuild命令

推荐用这种方式生成XCFramework
使用 Xcode 制作 Framework 与 XCFramework
iOS开发进阶六:lipo指令和XCFramework

#脚本需要放到工程目录里
scheme_name="XXX"
workspace_file_path="Example/YYY.xcworkspace"
configuration_type="Release"
result_folder_path="../SDKArchive/${scheme_name}"
archive_folder_path="${result_folder_path}/Archives"
xcframework_file_path="${result_folder_path}/${scheme_name}.xcframework"
 
rm -rf ${archive_folder_path}
rm -rf ${xcframework_file_path}

# clean
xcodebuild clean -workspace ${workspace_file_path} \
                 -scheme ${scheme_name} \
                 -configuration ${configuration_type}

# iOS devices
xcodebuild archive -workspace ${workspace_file_path}\
                   -scheme ${scheme_name} \
                   -configuration ${configuration_type} \
                   -archivePath "${archive_folder_path}/${scheme_name}-iOS.xcarchive" \
                   -destination "generic/platform=iOS" \
                   -sdk iphoneos \
                   SKIP_INSTALL=NO \
                   BUILD_LIBRARY_FOR_DISTRIBUTION=YES

# iOS simulators
xcodebuild archive -workspace ${workspace_file_path}\
                   -scheme ${scheme_name} \
                   -configuration ${configuration_type} \
                   -archivePath "${archive_folder_path}/${scheme_name}-iOS-simulator.xcarchive" \
                   -destination "generic/platform=iOS Simulator" \
                   -sdk iphonesimulator \
                   SKIP_INSTALL=NO \
                   BUILD_LIBRARY_FOR_DISTRIBUTION=YES

xcodebuild -create-xcframework \
           -framework "${archive_folder_path}/${scheme_name}-iOS.xcarchive/Products/Library/Frameworks/${scheme_name}.framework" \
           -framework "${archive_folder_path}/${scheme_name}-iOS-simulator.xcarchive/Products/Library/Frameworks/${scheme_name}.framework" \
           -output ${xcframework_file_path}
    

open ${result_folder_path}

七.集成SDK

1.手动集成

如果framework里有category,集成方需要在other linker flag-添加-ObjC(如果是动态库,好像不加也没事...)

如果手动集成动态库,需要设置: Target-General-Frameworks, Libraries, and Embedded Content,把动态库设置为Embed & Sign

iOS framework之Embed、Signing
Framework 嵌套与依赖

2.发布公有库

这里有个坑,如果是发布的动态库,那么一切好说; 如果发布的是静态库,而且有OC和Swift混编,可能验证一直无法通过,因为必须要所有pod target的BUILD_LIBRARY_FOR_DISTRIBUTION都设置为yes才行,所以只能验证命令添加--skip-import-validation, 跳过验证才能发布成功

//podspec文件添加
  s.vendored_frameworks = 'Frameworks/xxx.xcframework' 
//两个常用验证命令
//如果验证不通过,可以试试pod lib lint --verbose --allow-warnings --skip-import-validation, pod trunk push时,也要添加--skip-import-validation
//cd到podspec目录下
//公有库验证:
pod spec lint --verbose --allow-warnings
pod trunk push XXXSDK.podspec --verbose --allow-warnings

//私有库验证:
pod lib lint  --verbose --allow-warnings --sources="https://github.com/CocoaPods/Specs.git,https://xxx.git"
pod repo push 仓库Name SpecName.podspec --verbose --allow-warnings --sources="https://github.com/CocoaPods/Specs.git,https://xxx.git"

//其他参数
--use-libraries
--use-static-frameworks 
--skip-import-validation
--skip-tests

XCFramework从0到发布到Cocoapod
CocoaPods私有库可能遇到的坑

Xcode12 执行 pod lib lint 报错:building for iOS Simulator, not found for architecture arm64
解决pod lib lint/repo push不支持i386编译&只能真机运行的库
ios Framework静态库以及上传私有库
iOS 私有库中依赖私有库 且有第三方framework的处理
2018-06-24 私有库坑 :Include of non-modular header inside framework module
2019-07-31 记录私有库坑 :Include of non-modular header inside framework module
使用cocoapods打包静态库(依赖私有库,开源库,私有库又包含静态库)
[Cocoapods]使用Cocoapods + Github托管代码
Pod spec私有库集成遇到的错误(一)
Pod spec私有库集成遇到的错误(二)
Pod本地私有库使用图片和XIB资源文件

不管是静态库还是动态库,不管是手动集成还是cocoapods集成,只要有OC和Swift混编,打包出来的XCFramework,集成方都有可能报错,找不到类或者方法,这个问题找了很久,终于在github上看到解决方案:解决办法
//集成方需要在podfile最下面添加设置
post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
    end
  end
end

八.问题以及坑

1.pod install时报很长的警告,解决方式:

install!'cocoapods',:deterministic_uuids=>false
参考: [Xcodeproj] Generated duplicate UUIDs

2.pod spec lint时

--use--modular-headers 干啥的?

3.其他:

Cocoapods打包framework/静态库的注意点
[Cocoapods]项目添加Cocoapods支持遇到的坑
cocoaPods 进行SDK二次包装(cocoapods-packager完成 framework静态库打包,避免第三方库冲突)
关于使用CocoaPods的package打包Framework以及使用注意


参考文章
封装framework 并支持pod 管理 (1)
封装framework 并支持pod 管理 (2)-cocoapods-packager
使用Cocoapods创建SDK,并生成Framework
使用cocoapods创建framework组件
Cocoapods私有库组件创建Framework
坑: iOS打包framework通过pod方式给别人用
iOS Xcode Framework 私有pod
iOS开发之CocoaPods:进阶篇 搭建私有库

上一篇下一篇

猜你喜欢

热点阅读