目录
1、创建远程库
2、提交项目代码并打好tag标签
3、创建并编辑.podspec索引文件
4、把.podspec提交到Cocoapods trunk
5、可能会遇到的问题
6、组件库与私有化
1、创建远程库
登录自己的github账号(其他平台类似),创建一个新的repository, 添加README、.gitignore和license,点击下方的绿色按钮创建远程仓库
如果要删除某个库,找到这个库的Settings,删除库的入口在最底部。
2、提交项目代码并打好tag标签
远程库与本地项目关联有两种方法:
第一种,在本地新建文件夹TestKit,使用git clone
命令把远程库clone到本地,在文件夹下创建或添加项目。
//终端切换到文件夹TestKit目录下
cd /Users/userName/Desktop/TestKit
//clone远程库
git clone https://github.com/XXX/TestKit.git
//把项目文件放到新建的文件夹TestKit下
...
//提交当前文件夹下的所有文件到暂存区
git add .
//提交
git commit -m "提交说明"
//上传远程库,master是远程分支名称
git push origin master
第二种,在项目根目录下使用git remote add
命令把远程库和本地项目关联起来。
//初始化git仓库
git init
//提交当前文件夹下的所有文件到暂存区
git add .
//提交
git commit -m "提交说明"
//关联远程库
git remote add origin https://github.com/XXX/TestKit.git
//指定origin为默认主机,如果加了这一步,上传远程库可以不带-u参数
git remote
//上传远程库,master是远程分支名称
//本地分支推送到origin主机,同时指定origin为默认主机,
//后面就可以不加任何参数使用git push,
//也可解决git建立远程关联时出现fatal ... upstram的问题
git push -u origin master
git仓库是隐藏文件,如果创建后项目根目录下看不到,使用快捷键shift+cmd+.
可显示或隐藏文件,或使用命令
//显示
defaults write com.apple.finder AppleShowAllFiles -boolean true; killall Finder
//隐藏
defaults write com.apple.finder AppleShowAllFiles -boolean false; killall Finder
打tag标签,标签要与后面的podspec文件里的version参数一致
//打本地标签
git tag v1.0.0
//提交标签到远程
git push --tags
-
附常用的git命令汇总:
//初始化git仓库
git init
//添加当前文件夹下的所有文件到暂存区
git add .
//查看状态,红色字体表示本地改动没有提交,绿色字体表示已提交到了暂存区没有commit
git status
//提交
git commit
//提交带提交说明,如果第一次使用,会提示输入github的账号密码
git commit -m ‘注释’
//查看提交日志
git log
//更新remote索引
git fetch
//推送
git push
//推送到远程master分支
git push origin master
//本地分支推送到origin主机,同时指定origin为默认主机,
//后面就可以不加任何参数使用git push,
//也可解决git建立远程关联时出现fatal ... upstram的问题
git push -u origin master
//按标签推送到远程
git push origin ‘标签,比如v1.0.0’
//关联远程仓库
git remote add origin <URL>
//打标签
git tag '版本'
//打标签带描述
git tag -a '版本' -m '描述'
//标签提交到远程
git push --tags
//删除本地标签
git tag -d v0.0.1
//远程删除标签
git push origin :v0.0.1
//查看当前所有分支
git branch
//创建分支
git branch dev
//检出分支
git checkout dev
//创建并检出分支
git checkout -b dev
//查看分支及hash值和提交信息
git branch -v
//把dev分支合并到当前分支
git merge dev
//删除分支dev
git branch -d dev
//强制删除分支dev,若没有其他分支合并就删除,-d会有提示 -D不会提示
git branch -D dev
//修改分支,分支dev改为kdev
git branch -m dev kdev
//强制修改分支,与其他分支有冲突也会创建
git branch -M dev kdev
3、创建并编辑.podspec索引文件
podspec官方语法说明 Podspec Syntax Reference
在项目根目录下创建podspec索引文件,文件名与项目名一致
//比如现有项目TestKit
pod spec create TestKit
或
pod spec create TestKit.podspec
然后编辑这个文件
Pod::Spec.new do |spec|
# ――― 基本信息 ――― #
#spec文件名,也是使用pod搜索或安装时用的名字
spec.name = "TestKit"
# spec版本号
spec.version = "1.0.0"
# 简介
spec.summary = "常用组件"
# 描述,description内容比summary要长一些,否则会有警告
spec.description = "常用组件和扩展"
# 主页
spec.homepage = "https://github.com/huhansan/TestKit"
# spec.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif"
# ――― 开源协议 ―――#
# spec.license = "MIT"
spec.license = { :type => "MIT", :file => "LICENSE" }
# ――― 作者信息 ―――#
spec.author = { "huhansan" => "123456789@gmail.com" }
# Or just: spec.author = "huhansan"
# spec.authors = { "huhansan" => "123456789@gmail.com" }
# spec.social_media_url = "http://twitter.com/huhansan"
# ――― 平台信息 ―――#
# spec.platform = :ios
# 平台及使用版本,ios平台,系统版本11.0及以上
spec.platform = :ios, "11.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"
# ――― git源信息 ―――#
# 下面几种写法都可以,注意tag值,要保证与项目提交的tag一致:
//指定tag值
# spec.source = { :git => "https://github.com/huhansan/TestKit.git", :tag => 1.0.0 }
//取spec.version
# spec.source = { :git => "https://github.com/huhansan/TestKit.git", :tag => spec.version }
//tag带有前缀 "v"
spec.source = { :git => "https://github.com/huhansan/TestKit.git", :tag => "v#{spec.version}" }
//版本hash值
# spec.source = { :git => "https://github.com/huhansan/TestKit.git", :commit => "c8706d6" }
# ――― 资源管理 ―――#
# 代码文件
// “*” 表示匹配所有文件
// “*.{h,m}” 表示匹配所有以.h和.m结尾的文件
// “**” 表示匹配所有子目录
spec.source_files = "TestKit/Classes/**/*.{h,m,swift,xib,xcassets}"
# ――― 资源信息 ―――#
# spec.resource = "icon.png"
# spec.resources = "Resources/*.png"
# spec.preserve_paths = "FilesToSave", "MoreFilesToSave"
# 使用resources方式引用资源文件
spec.resources = ['Assets/Images/*.png', 'Assets/Resource/*']
# 使用spec.resources方式是将资源文件copy到目标工程(Example工程)
# 最后和目标工程的图片文件以及其他同样使用resources的Pod的图片文件,统一打包为一个Assets.car
# 优点:可以使用 .xcassets 指定资源文件、不需要用硬编码方式获取图片
# 缺点:可能会导致每个库和主工程之间的同名资源冲突
# 硬编码方式:[NSBundle bundleForClass:[self class] compatibleWithTraitCollection:nil];
# 资源文件打包成bundle,避免资源文件冲突
spec.resource_bundles = {
'TestKitBundle' => ['TestKit/Classes/**/*.storyboard'],
'TestKitImgBundle' => ['Assets/Images/*.png']
}
# 使用spec.resource_bundles方式是会为指定的资源打一个.bundle,.bundle包含一个Assets.car,
# 获取图片的时候要严格指定.bundle的位置,很好的隔离了各个库或者一个库下的资源包。避免资源同名冲突。
# 优点:可以使用.xcassets指定资源文件、可以避免每个库和主工程之间的同名资源冲突
# 缺点:获取图片时可能需要使用硬编码的形式来获取,比如想访问TestResourceBundle的资源:
# [NSBundle bundleForClass:[self class].resourcePath stringByAppendingPathComponent:@"/TestResourceBundle.bundle"]
# 不包含资源
spec.exclude_files = "Classes/Exclude"
# 对外开放的头文件地址,如果不指定会默认加载源代码所有头文件
spec.public_header_files = "AFNetworking/*.h" #静态库时必须有
# ――― 工程链接库 ―――#
# 引用系统公有framework,用“,”分割,去掉后缀 .framework
spec.framework = "UIKit"
spec.frameworks = "UIKit", "AnotherFramework"
# 引用系统静态库,去掉头尾的lib,用“,”分割
spec.library = "z"
spec.libraries = "iconv", "xml2"
# 引用自己生成的framework,用“,”分割
# 路径写从.podspec所在目录为根目录的相对路径,带后缀 .framework
spec.vendored_frameworks = 'TestKit/Frameworks/*.framework'
# 引用自己生成的.a静态库(必须以lib打头)
spec.vendored_libraries = "TestKit/Libraries/libTestKit.a"
# ――― 工程配置 ――― #
# 是否是arc模式
spec.requires_arc = true
# spec.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
# 依赖的第三方类库
# spec.dependency "JSONKit", "~> 1.4"
spec.dependency "RxSwift"
spec.dependency "RxCocoa"
...
# 配置xcode的other flag
spec.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '$(inherited) -undefined dynamic_lookup' }
# spec.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-lObjC' }
# 指定SDK为静态库
spec.static_framework = true
# ――― 类库依赖 ――― #
# 将单独的功能拆分为一个子模块,只想用子模块功能的时候只需在pod中引入子模块,不需要引入库的所有文件
//子模块Reachability
spec.subspec 'Reachability' do |ss|
ss.source_files = 'TestKit/Classes/Reachability/**/*.{h,m,swift}'
ss.dependency "AFNetworking/Reachability", '~> 3.0'
end
//子模块Downloader
spec.subspec 'Downloader' do |down|
down.source_files = 'TestKit/Classes/DownLoader/**/*'
down.dependency "AFNetworking"
end
# Podfile中配置:
# pod 'TestKit', '~> 1.0.0', :subspecs => ["Reachability", "Downloader"]
# 或
# pod 'TestKit/Reachability', '~> 1.0.0'
# pod 'TestKit/Downloader', '~> 1.0.0'
end
提交前验证.podspec文件的合法性,也可以跳过验证环节直接提交,提交时会先验证本地.podspec文件的合法性再上传到trunk,最后会将上传的.podpec文件转换为需要的json文件。
# 无需联网
pod lib lint TestKit.podspec
或
# 联网检查sepc repo并关联tag
pod spec lint TestKit.podspec
--verbose
:有些非语法错误是不会给出错误原因的,这个时候可以使用--verbose来查看详细的验证过程来帮助定位错误。
--use-libraries
:表示使用静态库或者是framework,这里主要是解决当我们依赖一些framework库后校验提示找不到库的时候用到。
--allow-warnings
:表示允许警告。
--sources=‘master,privateSpecs'
:指定源,比如你的私有pod同时依赖了公有库和私有库,你必须指定源才行,因为默认只会去公有源中查找对应的依赖
如果依赖了其他的第三方库
pod spec lint TestKit.podspec --verbose --allow-warnings --sources="cocoapods库地址,私有库远程地址"
如果其他第三方私有库又依赖了其他的库,需增加--use-libraries
pod spec lint TestKit.podspec --verbose --use-libraries --allow-warnings --sources="cocoapods库地址,私有库远程地址"
显示绿色的TestKit.podspec passed validation.
表示校验通过。
XXX.podspec应该在没有任何错误或警告的情况下通过验证。若验证过程中有错误,验证失败,修改后再次验证,直到通过验证。
-
附.podspec验证时的参数:
Usage:
$ pod lib lint [PODSPEC_PATHS ...]
Validates the Pod using the files in the working directory.
Options:
--quick Lint skips checks that would require to
download and build the spec
--allow-warnings Lint validates even if warnings are
present
--subspec=NAME Lint validates only the given subspec
--no-subspecs Lint skips validation of subspecs
--no-clean Lint leaves the build directory intact
for inspection
--fail-fast Lint stops on the first failing platform
or subspec
--use-libraries Lint uses static libraries to install the
spec
--use-modular-headers Lint uses modular headers during
installation
--use-static-frameworks Lint uses static frameworks during
installation
--sources=https://cdn.cocoapods.org/ The sources from which to pull dependent
pods (defaults to
https://cdn.cocoapods.org/). Multiple
sources must be comma-delimited
--platforms=ios,macos Lint against specific platforms (defaults
to all platforms supported by the
podspec). Multiple platforms must be
comma-delimited
--private Lint skips checks that apply only to
public specs
--swift-version=VERSION The `SWIFT_VERSION` that should be used
to lint the spec. This takes precedence
over the Swift versions specified by the
spec or a `.swift-version` file
--include-podspecs=**/*.podspec Additional ancillary podspecs which are
used for linting via :path
--external-podspecs=**/*.podspec Additional ancillary podspecs which are
used for linting via :podspec. If there
are --include-podspecs, then these are
removed from them
--skip-import-validation Lint skips validating that the pod can be
imported
--skip-tests Lint skips building and running tests
during validation
--test-specs=test-spec1,test-spec2,etc List of test specs to run
--analyze Validate with the Xcode Static Analysis
tool
--configuration=CONFIGURATION Build using the given configuration
(defaults to Release)
--allow-root Allows CocoaPods to run as root
--silent Show nothing
--verbose Show more debugging information
--no-ansi Show output without ANSI codes
--help Show help banner of specified command
4、把.podspec提交到Cocoapods trunk
注册CocoaPods trunk账户,需要一个真实可用的邮箱用于邮件验证
pod trunk register 123456789@gmail.com 'huhansan'
也可在用户名后面跟描述信息
pod trunk register 123456789@gmail.com 'huhansan' --description='huhansan的trunk' --verbose
注册命令执行后会在对应邮箱收到验证邮件,点击验证链接完成验证,提交.podspec文件到trunk
pod trunk push TestKit.podspec
使用--allow-warnings
忽略警告
pod trunk push TestKit.podspec --allow-warnings
如果使用了静态库或私有库中有.a文件,必须加上--use-libraries
pod trunk push TestKit.podspec --use-libraries --allow-warnings
提交成功后更新下本地cocoapods再使用pod search
命令搜索
pod setup
...
pod search TestKit
如果搜索不到就清理下cocoapods的搜索索引文件search_index.json的本地缓存,然后再搜索
rm ~/Library/Caches/CocoaPods/search_index.json
...
pod search TestKit
-
附pod trunk命令汇总:
# 注册trunk - pod trunk register [EMAIL] [USERNAME]
$pod trunk register 123456789@gmail.com 'huhansan'
# 查看已注册信息 - pod trunk me
# 包含账号的Name、Email、Since、Pods、Sessions,其中Pods为该账号向CocoaPods提交的所有的库
$pod trunk me
- Name: huhansan
- Email: 123456789@gmail.com
- Since: February 8th, 02:15
- Pods:
- HHSKit
- HHSUIKit
- HHSComKit
- HHSActionSheet
- HHSProgressHUD
- HHSDownloadManager
- HHSNavigationController
- HHSTabBarController
- Sessions:
- April 1st, 05:09 - August 7th, xx:22. IP: xxx.xxx.xx.xxx
- April 4th, 20:44 - August 10th, xx:58. IP: xxx.xxx.xx.xxx
- April 4th, 21:37 - August 12th, xx:33. IP: xxx.xxx.xx.xxx
Description: huhansan的trunk
# 查看账号下某个库的信息 - pod trunk info [POD REP NAME]
$pod trunk info HHSUIKit
HHSUIKit
- Versions:
- 1.0.1 (2015-11-09 05:43:23 UTC)
- 1.0.2 (2016-03-12 12:08:47 UTC)
- 1.0.5 (2017-10-18 08:14:53 UTC)
- 1.0.6 (2018-11-25 16:28:27 UTC)
- 1.1.0 (2019-12-07 04:49:24 UTC)
- 1.1.1 (2020-12-09 11:12:05 UTC)
- 1.1.3 (2021-12-16 10:18:15 UTC)
- 1.1.5 (2022-02-17 10:59:12 UTC)
- Owners:
- huhansan
# 不管添加还是删除某个库的拥有者,必须`pod trunk register`登录过并且操作的是登录账号所拥有的库
// 添加某个库的拥有者 - pod trunk add-owner [POD REP NAME] [OWNER-EMAIL]
$pod trunk add-owner HHSUIKit 123456789@gmail.com
// 删除某个库的拥有者 - pod trunk remove-owner [POD REP NAME] [OWNER-EMAIL]
$pod trunk remove-owner HHSUIKit 123456789@gmail.com
# 让某个库过期 - pod trunk deprecate [POD REP NAME]
$pod trunk deprecate HHSUIKit
# 删除某个库的某个版本,该命令无法撤回 - pod trunk delete [POD REP NAME] [VERSION]
$pod trunk delete HHSUIKit 1.0.1
# 发布库,path是PodRepName.podspec的路径,若处于同一级目录也可不加path - pod trunk push [PATH]
$pod trunk push HHSUIKit.podspec
...
done
5、可能会遇到的问题
1.关联远程库git remote add
报错
如果报错:fatal: not a git repository (or any of the parent directories): >.git
原因是git没有初始化,先调用命令git init
初始化
2.推送远程git push
报错
如果报错:
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to >'https://github.com/XXX/TestKit.git'
或者
error: src refspec master does not match any.
error: failed to push some refs to >'https://github.com/XXX/TestKit.git'
主要原因都是远程库与本地库不同步,可以通过git pull
命令进行代码合并
git pull origin master
拉取后如果还是会报一些警告⚠️⚠️⚠️
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
这是因为拉取后合并时不知道以谁为基准注:pull = fetch + merge
,拉取时加上rebase
参数
git pull --rebase origin master
还有种简单粗暴的方式:
git push -f origin master
表示强制提交到远程,会覆盖掉远程库,如果远程库是空的这种方式也不是不可以。
3.校验pod spec lint
报错
如果报错:
Cloning into '/var/folders/6p/dkd3r6595633j5fms40_d04h0000gn/T/d20240201-3829-4qf1cn'...
warning: Could not find remote branch 0.2.0 to clone.
fatal: Remote branch 0.2.0 not found in upstream origin
这是因为组件库忘记打tag了,spec里的版本号对应的tag找不到,打好tag后重新校验即可
6、组件库与私有化
6.1.本地组件库的创建与使用
运行pod lib create AppCom
命令创建一个名称为AppCom的组件库,需要关注以下几个问题
#平台
What platform do you want to use?? [ iOS / macOS ]
>
ios
#语言
What language do you want to use?? [ Swift / ObjC ]
>
swift
#是否创建demo工程
Would you like to include a demo application with your library? [ Yes / No ]
>
yes
#是否需要测试框架
Which testing frameworks will you use? [ Quick / None ]
> None
#是否需要视图测试
Would you like to do view based testing? [ Yes / No ]
>
yes
至此,系统会创建一个包含本地私有库的项目
新版本的cocoapod会自动执行 pod install ,模板库加载完成后,会通过命令行打开刚创建的工程
进入到刚创建的项目,可以看到 AppCom 文件夹,这个文件就是用来存储私有库需要的代码文件和资源文件(图片、xib,以及其他资源文件)
替换Classes目录里的文件
回到示例工程pod install
或pod update --no-repo-update
一下,文件才会被真正加载到工程里
至此,我们得到了一个本地组件库,在需要使用这个组件库的BTest工程目录下新建个文件夹LocalLib,把AppCom组件放到新建的目录下
在BTest工程的pod里添加本地组件
运行pod install
把组件加载到工程里
6.2.私有化组件库
私有化组件库需要把组件库与私有的Spec Repo关联起来
什么是 Spec Repo?
它是所有的开源Pods的一个索引容器,实际上就是个remote端在GitHub上的Git仓库,在本地的 ~/.cocoapods/repos 目录下可以看到有一个master文件夹,这个就是clone到本地的官方Spec Repo 。
我们需要创建一个类似 master 的私有 Spec Repo,同理这个私有的Spec Repo也要有一个远程端,我们创建一个Git仓库用来存储.podspec 版本文件。
第一步,组件库上传到远端
在github或其它平台创建一个私有
的远程库AppCom,把本地AppCom组件库代码上传上去并打好tag,上传过程不再赘述。
第二步,回到组件库工程里,配置AppCom.podspec文件
删掉多余的注释后,需要关注以下的内容
Pod::Spec.new do |s|
# 库名
s.name = 'AppCom'
# 版本号
s.version = '0.1.0'
# 概要
s.summary = '公共组件'
# 描述
s.description = '公共类、扩展的公共组件'
s.homepage = 'https://www.chaoren.com'
# 许可证
s.license = { :type => 'MIT', :file => 'LICENSE' }
# 创建用户
s.author = { 'huhansan' => 'huhansan666@timeltd.cn' }
# 远程库地址
s.source = { :git => 'https://github.com/huhansan/AppCom.git', :tag => s.version.to_s }
# 最低的系统支持版本
s.ios.deployment_target = '10.0'
# 源文件路径
s.source_files = 'AppCom/Classes/**/*'
# 库资源文件路径,会打包成bundle
s.resource_bundles = {
'AppCom' => ['AppCom/Assets/*.png']
}
# 头文件路径
s.public_header_files = 'Pod/Classes/**/*.h'
# 需要用到的系统库
s.frameworks = 'UIKit', 'MapKit'
# 依赖的第三方库
s.dependency 'AFNetworking', '~> 2.3'
end
!!!需要特别注意的是AppCom.podspec文件里的版本号要与第一步里打的tag一致!!!
第三步,关联私有Spec Repo
在github或其它平台创建一个私有
的远程库AppSpecs,创建好后需要把AppCom.podspec与AppSpecs做关联,在终端中执行命令:
pod repo add AppSpecs https://github.com/huhansan/AppSpecs.git
关联成功进入到~/.cocoapods/repos 目录,可以看到除了master还多了一个AppSpecs文件夹,里面存储的就是私有库的索引。
注意两点
:
第一点
,私有库AppCom如果是给其他人使用,就需要给这个人AppCom仓库权限
第二点
,他人使用这个私有库AppSpecs索引也需要有AppSpecs仓库的权限,并在本地执行关联命令
第四步,AppCom.podspec推送到远程AppSpecs
与发布库到官方cocoapods类似,需要把索引push到私有的索引库,也是先校验,没问题了再push,运行命令
pod spec lint AppCom.podspec
如果依赖了其他的第三方库
pod spec lint AppCom.podspec --verbose --allow-warnings --sources="cocoapods库地址,私有库远程地址"
如果其他第三方私有库又依赖了其他的库,需增加--use-libraries
pod spec lint AppCom.podspec --verbose --use-libraries --allow-warnings --sources="cocoapods库地址,私有库远程地址"
显示绿色的AppCom.podspec passed validation.
表示校验通过,校验通过后执行命令
pod repo push AppSpecs AppCom.podspec --allow-warnings
...
#当显示如下内容就代表push成功了
Updating the `AppSpecs' repo
Adding the spec to the `AppSpecs' repo
- [Update] AppCom(0.1.0)
Pushing the `AppSpecs' repo
至此,组件库的私有化就制作完成了。
在其他项目里就可以像其他库一样引用
pod 'AppCom'
需要注意的一点,因为是私有库,在Podfile里除了官方的索引源,还需要加上私有库的索引源
source 'https://github.com/CocoaPods/Specs.git'
source 'https://github.com/huhansan/AppSpecs.git'
6.3.组件库间通讯
市面上已经有很多种中间件、路由等方案
CTMediator
HHRouter
MGJRouter
JLRoutes