iOS CocoaPods组件化
这篇帖子自己也在构思需要如何去写,就像现在,我自己也还在想,尽管已经实现了通过pod来管理项目中的组件,但是思绪比较乱的是,到底如何去构造一个项目的结构,从而实现组件化。本文并不是深入的介绍每一种方式,但是总结了常见的知识点,总之看这里就对了。其中有一些大体上在亲手操作时候会遇到的一些问题。通过pod管理私有库这种形式也是我们比较常见的,常见的有AFNetworking,MJRefresh等等第三方,甚至是一些业务上的SDK(静态库)。
制作基础组件,并上传到pod管理
创建前必须弄清楚三个库,下文会做出分析
-
本地代码
-
git管理的代码
-
pod管理的代码
1.在创建组件之前,不妨先来个pod search
例如,今天我需要创建的项目名叫SYLibHelper,如果没search到就安心开始吧,找到已存在的库建议换名,免得后面麻烦。
pod search SYLibHelper
2.创建本地私有库
cd Desktop
pod lib create SYLibHelper
1555856339225.jpg
按照个人的需求选择性输入。创建完毕后桌面已经多了一个SYLibHelper文件了。
3.将自己封装的组件替换replace.m文件
1555856790655.jpg把replace.m从项目中删除,进入文件夹SYLibHelper/classes,把需要上传的组件,例如DBManager放到此路径中。
WechatIMG212.jpeg
然后
cd Example
pod install
此时已经能看到SYLibHelper中有DBManager了,如果没有,请关闭项目重新打开就会出来了。
4.在Git中创建代码仓库,并将SYLibHelper上传
先设置本地的git仓库,一顿常规操作后,必须设置tag:
- 进入私有库根目录
git init
git add .
git commit -m "first commit"
git remote add origin 项目地址
git push origin master -f
git tag 0.0.1
git push --tag
此时,git中的项目已经由
1555858145889.jpg
变成了
1555858168770.jpg
5.修改项目中.podspec(SYLibHelper.podspec),并且检测是否能上传至pod
修改项目中.podspec
1555858349422.jpg- 修改s.version为git设置的tag
- 修改s.homepage和s.source为git仓库项目的路径
在SYLibHelper的根目录下,检测是否能上传至pod
pod lib lint --verbose
这时有可能会出现
[!] SYLibHelper did not pass validation, due to 2 warnings (but you can use `--allow-warnings` to ignore them).
You can use the `--no-clean` option to inspect any issue.
添加
pod lib lint --verbose --allow-warnings //允许警告
当出现
1555858940403.jpg
恭喜你 检测通过了,接下来就是上传了。
6.上传到pod
在SYLibHelper的根目录
pod trunk push --verbose
这时有可能会出现并未有cocoapod的账号,需要设置账号,傻瓜式的操作完毕后,在执行上面的trunk push过去就行了。
1555897667268.jpg
出现上图,则表示已经上传到pod中,可以到实际项目中pod下来使用了。
7.将组建pod到实际项目中
- 如果组件需要开源使用直接
pod 'SYLibHelper'
- 如果组件是内部项目使用
pod 'SYLibHelper',git=>'https://gitee.com/#####/SYLibHelper.git',:tag=>'0.0.1'
8.更新
- 这就需要根据自己需求,看是需要更新pod中的仓库还是自己git中的仓库了。当需要迭代更新,需要设置新的tag值。
制作静态库,并上传至pod管理
先了解静态库和动态库:
-
需要弄明白,由我们自行制作的库都是静态库(.a和.framework)
-
系统库包含framework和.tbd(之前叫.dylib),都是动态库,如果有自制的动态库,无法上架
-
静态库:不同的程序运行一次,生成一份
-
动态库:各程序共用一份
-
静态库在程序编译时会被链接到目标代码中,程序运行时将不再需要改静态库;而动态库在程序编译时并不会被链接到目标代码中,只是在程序运行时才被载入,因为在程序运行期间还需要动态库的存在
-
framework为什么既是静态库又是动态库?
-
系统的.framework是动态库,我们自己建立的.framework是静态库。
静态库开发两种形式
有了上面组件的制作的基础,静态库上传到pod中就明朗多了。
-
1)创建Project,在Project中开发库(最好不要,雅蠛蝶)
此方式一方面不开发起来不方便管理,并且project中demo与真实项目可能有一定的差别。所以此处基础创建就不介绍了。
-
2)直接在项目中创建新的Project,项目和静态库同时开发
在已经有的项目中添加新项目,选择
此时项目目录中多了一个项目文件夹。
在文件夹内创建文件,并进行开发。
写完自己的代码逻辑。
-
配置静态库
1.Build Setting 搜索linking 设置Dead Code Stripping 为NO是编译选项优化,包瘦身,(可不改) Mach-O Type 选中StaticLibrary (静态库) Xcode默认是动态库.
1555898474360.jpg
-
设置framework最低支持的版本
1555898531969.jpg
3.设置架构
Build Active Architecture Only 设置为NO
打包出来的.framework支持所有此类型设备的所有架构.否则打包时只有当前设备运行的架构。
上面的类型指的是真的和模拟器两种类型。
先了解真机和模拟器架构:
-
armv7|armv7s|arm64都是ARM处理器的指令集
-
i386|x86_64 是Mac处理器的指令集
-
arm64:iPhone5S以上
-
armv7s:iPhone5|iPhone5C
-
armv7:iPhone4|iPhone4S
简单点来说:模拟器 32/64 位处理器分别需要 i386/x86_64 架构,真机 32/64 位处理器分别需要 armv7(armv7s)/arm64 架构。
所以,如果你构建的静态库只需要支持 iPhone 5S 及以上(或 iPad mini2 及以上)的真机和模拟器,那么你的静态库将只需支持 arm64 和 x86_64 架构。
为什么需要获取不同的架构?
很多公司上线的静态库都不包含模拟器架构,这样可以减小库的大小,此文是测试,将两种设备(真机和模拟器)的架构都合并。
选择真机和模拟器分别跑一次,获得模拟器和真机两种架构的静态库。
1555861687999.jpg可以看到,原本在下图中的.framework文件名由红色变成白色了,然后找到.framework所在位置 1555899538363.jpg
由于我们选这的是Build Active Architecture Only 设置为了NO,所以我们尝试分别查看模拟器和真机的.framework的架构
1555899728269.jpg
注意,是查看上图红框文件
lipo -info 拖文件到终端中
1555899998213.jpg
可以看到,只要一种类型的设备跑了project后,同一种类型的设备的所有架构都出来了。没出来的估计是苹果已经将其放弃了。
设置打包后可见文件
1555902143976.jpg需要看到头文件的放到public,不需要看到的文件放到project,没什么事就别放到private了。
合并两种设备的架构(两种方式)
1.手动合并方式
cd /........./........./........./........Products(自己拖)
lipo -create [真机中查看架构的文件拖进来] [模拟器中查看架构的文件] -output [与.framework同名]
在Products找到合并后的文件,替换
1555901574337.jpg
然后此framework已经可以使用了。
2.添加java script自动合成方式
1555901833358.jpg把脚本加入
if [ "${ACTION}" = "build" ]
then
INSTALL_DIR=${SRCROOT}/Products/LYTestFramework.framework(合并后需要导出的路径) //请自己填写
DEVICE_DIR = 真机设备下LYTestFramework.framework的绝对路径 //请自己填写
SIMULATOR_DIR = 模拟器设备下LYTestFramework.framework的绝对路径 //请自己填写
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
#ditto "${DEVICE_DIR}/Headers" "${INSTALL_DIR}/Headers"
lipo -create "${DEVICE_DIR}" "${SIMULATOR_DIR}" -output "${INSTALL_DIR}}"
#open "${DEVICE_DIR}"
open "${SRCROOT}/Products"
fi
这样,每次run了之后,framework就自动合并到了自己指定的路径中了。
最后上传到pod中
跟上面制作基础组件差不多,把处理好的.framework替换replaceme.m,然后一顿操作,需要注意的是 1555902499793.jpg如果设置了s.source.files,pod的时候会把.framework中的一些不需要用到的文件都展示在项目,所以最好注释掉,不过还是看自己的需求。
如果静态库中需要用到例如一些AFNetworking第三方的话,需要s.dependency 'AFNetworking','MJFresh'等,以逗号隔开。如果用到系统的库,则使用s.frameworks。
然后按照制作基础组件上传就可以了。
最后
在蘑菇街组件化的文章中,通过MGJRouter和Class-Protocol进行模块间的调用。接着Casa提出了不同意见,于是有了target-action模式来通过中间件来管理模块间的调用。后来Limboy在Casa反馈之上对自己方案做了进一步优化。
网上比较多对于组件化的文章分为
- 通过pod来管理组件
- 还有就是蘑菇街以及蘑菇街衍生出来的方案的组件化思维。
个人感觉,蘑菇街和蘑菇街衍生出来的方案更偏向业务模块化的管理。组件化需要深究的毕竟是思维。所以需要认知和学习的还有非常多。
感觉编辑了两天,还是有点浅出不深入。
希望有iOS的小伙伴能一起探讨一下。
秋秋951513592
就这样结束吧~