目录
看了众多的组件化方案后,我选择了Casa Taloyum 的 CTMediator 的组件化方案。没有别的原因,就因为耦合度低,而且维护成本低。感谢作者的启发。
创建步骤如下:
1.创建私有 Spec Repo
什么是Spec Repo?它是所有Pod的一个索引,就是一个容器,所有公开的Pods都放在这里面。我的理解是:他是一个仓库,我们自己创建的库可以从这里查找到,别人没有引用这个这个仓库,他就找不到我们私有的组件。
pod repo add [私有Pod源仓库名字] [私有Pod源的repo地址]
例如:pod repo add SASpecs http://***/***/SASpecs.git
如果成功创建了,我们就可以在~/.cocoapods/repo目录下看到 SASpecs这个目录了
2.新建工程(New Project)
创建你需要的组件模块,然后 git clone 到本地,完成你需要的功能,然后提交
3.你需要创建podspec文件
pod spec create iOS_aaa
4.设置podspec文件
#
# Be sure to run `pod spec lint TestSpec_color.podspec' to ensure this is a
# valid spec and to remove all comments including this before submitting the spec.
#
# To learn more about Podspec attributes see https://guides.cocoapods.org/syntax/podspec.html
# To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
#
Pod::Spec.new do |spec|
# ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# These will help people to find your library, and whilst it
# can feel like a chore to fill in it's definitely to your advantage. The
# summary should be tweet-length, and the description more in depth.
#
spec.name = "TestSpec_color" #工程名
spec.version = "0.0.8" #版本号,每次发版都需要修改
spec.summary = "A short description of TestSpec_color. aaa "
# This description is used to generate tags and improve search results.
# * Think: What does it do? Why did you write it? What is the focus?
# * Try to keep it short, snappy and to the point.
# * Write the description between the DESC delimiters below.
# * Finally, don't worry about the indent, CocoaPods strips it!
spec.description = <<-DESC
this is A #这里最好写点东西
DESC
spec.homepage = "https://github.com/fn512613/TestSpec_color"#主页
# spec.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif"
# ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# Licensing your code is important. See https://choosealicense.com for more info.
# CocoaPods will detect a license file if there is a named LICENSE*
# Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'.
#
spec.license = { :type => "MIT", :file => "FILE_LICENSE" }#框架遵守的开源协议
# spec.license = { :type => "MIT", :file => "FILE_LICENSE" }
# ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# Specify the authors of the library, with email addresses. Email addresses
# of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also
# accepts just a name if you'd rather not provide an email address.
#
# Specify a social_media_url where others can refer to, for example a twitter
# profile URL.
#
spec.author = { "QPP" => "[email protected]" }#作者
# Or just: spec.author = "钱盼盼"
# spec.authors = { "钱盼盼" => "[email protected]" }
# spec.social_media_url = "https://twitter.com/钱盼盼"
# ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# If this Pod runs only on iOS or OS X, then specify the platform and
# the deployment target. You can optionally include the target after the platform.
#
# spec.platform = :ios
spec.platform = :ios, "9.0"#最低支持版本
# When using multiple platforms
# spec.ios.deployment_target = "5.0"
# spec.osx.deployment_target = "10.7"
# spec.watchos.deployment_target = "2.0"
# spec.tvos.deployment_target = "9.0"
# ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# Specify the location from where the source should be retrieved.
# Supports git, hg, bzr, svn and HTTP.
#
spec.source = { :git => "https://github.com/fn512613/TestSpec_color.git", :tag => "#{spec.version}" }
# ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# CocoaPods is smart about how it includes source code. For source files
# giving a folder will include any swift, h, m, mm, c & cpp files.
# For header files it will include any header in the folder.
# Not including the public_header_files will make all headers public.
#
spec.source_files = "TestSpec_color/TestSpec_color/*.{h,m}"#本地框架文件索引,相对TestSpec_color文件的目录
#重要的提醒:
#当你的库中有子目录的时候
#spec.subspec 'Base' do |ss|
#ss.source_files = "SchoolAppNotification/SchoolAppNotification/Base/*.{h,m}"
#end
#spec.subspec 'Notification' do |ss|
#ss.source_files = "SchoolAppNotification/SchoolAppNotification/Notification/*.{h,m}"
#ss.subspec 'ViewModel' do |sss|
#sss.source_files = "SchoolAppNotification/SchoolAppNotification/Notification/ViewModel/*.{h,m}"
#end
#ss.dependency 'SchoolAppNotification/Base'#一些共用的文件都放在这个文件夹里,防止出现相互引用报错
#end
#spec.resources = 'SchoolAppNotification/SchoolAppNotification/Resources/SchoolAppNotification.bundle' #资源文件
# spec.exclude_files = "Classes/Exclude"
# spec.public_header_files = "Classes/**/*.h"
# ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# A list of resources included with the Pod. These are copied into the
# target bundle with a build phase script. Anything else will be cleaned.
# You can preserve files from being cleaned, please don't preserve
# non-essential files like tests, examples and documentation.
#
# spec.resource = "icon.png"
# spec.resources = "Resources/*.png"
# spec.preserve_paths = "FilesToSave", "MoreFilesToSave"
# ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# Link your library with frameworks, or libraries. Libraries do not include
# the lib prefix of their name.
#
# spec.framework = "SomeFramework"
# spec.frameworks = "SomeFramework", "AnotherFramework"
# spec.library = "iconv"
# spec.libraries = "iconv", "xml2"
# ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# If your library depends on compiler flags you can set them in the xcconfig hash
# where they will only apply to your library. If you depend on other Podspecs
# you can include multiple dependencies to ensure it works.
spec.requires_arc = true
#当你需要依赖第三方库的时候
#spec.dependency "DZNEmptyDataSet"
# spec.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
# spec.dependency "JSONKit", "~> 1.4"
end
重要:你还需要创建一个FILE_LICENSE文件,里面写MIT
5.创建提交update.sh脚本
VersionString=`grep -E 'spec.version.*=' TestSpec_color.podspec`
arr=(${VersionString//\"/ })
version=${arr[2]}
echo "准备提交 ${version}版本"
git add .
git ci -m "${version}"
git push
git tag -a "${version}" -m "${version}版本"
git push --tags
pod repo push TestSpecs TestSpec_color.podspec --allow-warnings
pod repo update ~/.cocoapods/repos/TestSpecs/
注意:pod repo push SASpecs SchoolAppNotification.podspec --allow-warnings --use-libraries #发版本 --allow-warnings是有警告也可以编译通过 --use-libraries有第三方库的时候需要添加这个参数
pod repo update ~/.cocoapods/repos/TestSpecs/ #更新本地库,如果不更新,pod search是搜不到最新的版本
6.CTMediator组件化需要创建的几个类
1.首先在VC目录下创建Target_XXX文件继承NSObject
2.在Target_XXX文件里实现创建VC对象方法,可以接受参数
3.新建另一个工程,pod 引入CTMediator,工程里创建CTMediator Category分类
4.在CTMediator分类中实现创建VC的方法
Target_TimeLine.m
- (UIViewController *)Action_ViewController:(NSDictionary *)params{
typedef void (^CallbackType)(id);
CallbackType callback = params[@"callback"];
CourseTableDetailViewController *vc = [[CourseTableDetailViewController alloc] init];
vc.callback = callback;
vc.data = params[@"data"];
return vc;
}
//创建Target文件是为了实现VC的创建,以及传参数
CTMediator+CourseTable.m
- (UIViewController *)TimeLine_ViewControllerWithCallback:(void(^)(NSString *result))callback{
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
params[@"callback"] = callback;
return [self performTarget:@"TimeLine" action:@"ViewController" params:params shouldCacheTarget:NO];
}
//创建CTMediator是为了解耦,不引入VC头文件,还有确定实现VC的方法和所传的参数
//需要跳转只要使用CTMediator的分类就可以。从而隔绝了VC与VC之间的引用关系
- Target_AA文件是创建UIViewController对象,方法可以实现接参,和一些简单的逻辑处理,这个文件是用来封装ViewController
- Category文件target参数是Target_AA文件中的AA、
- action是- (UIViewController *)Action_ViewController:(NSDictionary *)params中的Action_后面的“ViewController”
- param参数是你需要传入的参数
- Category文件需要单独创建一个工程、因为这样可以防止提交版本的时候互相包含
- 调用者不需要关心ViewController需要做什么操作,只需要按照暴露出来的接口初始化就可以了
- Category可以实例化多个方法
- 每个有改动需要先上传版本,然后在工程中删除Podfile.lock文件,再运行pod install
附上自己创建工程的目录:
每个模块都可以独立运行
总结
1、这个组件化方案的hard code仅存在于Target对象和Category方法中,影响面极小,并不会泄漏到主工程的业务代码中,也不会泄漏到业务线的业务代码中。
2、而且在实际组件化的实施中,也是依据category去做业务线的组件化的。所以先写category里的target名字,action名字,param参数,到后面在业务线组件中创建Target的时候,照着category里面已经写好的内容直接copy到Target对象中就肯定不会出错(仅Target对象,并不会牵扯到业务线本身原有的对象)。
3、在这个实践中,响应者的命名域并没有泄漏到除了响应者以外的任何地方,这就带来一个好处,迁移非常方便。
4、实施组件的时候不能使用xib和storyboard文件,需要手写布局
5、缺点是有的大模块打包时间较长
6、每次pod install前 ,先pod repo update ~/.cocoapods/repos/*私有库*/更新一下repo 删除pod.lock文件
遇到的问题
1.报错RuntimeError
RuntimeError - [!] Xcodeproj doesn't know about the following attributes {"inputFileListPaths"=>[], "outputFileListPaths"=>[]} for the 'PBXShellScriptBuildPhase' isa.
报这个错是因为旧版本的 CocoaPods 无法解析运行一下 sudo gem install cocoapods --pre
2.引用自己或者三方framework或者a文件时候
在podsepc中应该这样写:
s.ios.vendored_frameworks = "xxx/**/*.framework"
s.ios.vendored_libraries = "xxx/**/*.a”
3、The 'Pods' target has transitive dependencies错误
如果私有库添加了静态库或者dependency用了静态库
那么执行pod lib lint还有pod spec lint时候需要加上—user-libraries选项
4、私有库已经通过验证并传到私有repo也能通过pod search,但是就是pod install失败。
这时候只要执行pod update 然后去喝杯水就好了。。。
5、[iOS] unknown: Encountered an unknown error (/usr/bin/xcrun simctl list -j devices
错误的原因:XCode未设置Command line tools 解决方法:在XCode -> Preferences -> Locations中设置Command line tools。
6、[!]Unable to find the 'TestSpec' repo. If it has not yet been cloned,add it via 'pod repo add'.
看一下你的私有Specs库的名字是不是写错了,我就是少写了一个s
7、[!] The `TestSpec_color.podspec` specification does not validate.
出现这个问题,是podspec文件哪里设置的有问题,根据上面的error一步步解决问题,这个也是出现最多的问题。
例如:ERROR | description: The description is empty.
这个需要在description写点东西