Cocoapods 本地私有库和远程私有库的使用

本地私有库和远程私有库的使用

  • 一 本地私有库
    • 1.1 创建本地 git仓库
    • 1.2 创建库描述文件
    • 1.3 导入本地私有库
  • 二 本地私有库 - 单独测试
    • 方案一
    • 方案二
    • 方案三(推荐)
  • 三 远程私有库
    • SSH 授权
    • 添加私有远程索引库
    • 上传源码到 Git
    • 上传 Spec 到远程索引库
  • CocoaPods 库升级
  • CocoaPods 库依赖
  • CocoaPods 子库
  • CocoaPods 资源依赖
  • CocoaPods 图片依赖

一 本地私有库

本地私有库就是创建一个仓库,将其存储在本地,在本地的其他工程中直接使用。首先在桌面新建一个库,路径如下:

BaseTool/Classes/Network.h
BaseTool/Classes/Network.m

接着创建一个壳工程,现在你的目标是使用 pod 的方式,将 NetWork 这个库集成到壳工程中。

1.1 创建本地 git仓库

git init
git add.
git commit -m 'x'

1.2 创建库描述文件

和公开库一样,我们需要先创建一个 spec 文件,命令如下:

pod spec create Network
  • 编辑 Network.podspec 文件
Pod::Spec.new do |s|
  s.name          = "Network"
  s.version       = "0.0.1"
  s.summary       = "Network."
  s.homepage      = ""
  s.license       = 'MIT'
  s.author        = { "goodswifter" => "[email protected]" }
  s.source        = { :git => "", :tag => "#{s.version}" }
  s.source_files    = "Classes/**/*.{h,m}"
  s.platform      = :ios, "9.0" #平台及支持的最低版本
end

现在你的本地库已经准备完毕了,下面就可以使用这个库了。

1.3 导入本地私有库

现在进入到壳工程目录下,执行命令:

pod init

编辑 Podfile 文件,如下:

platform :ios, '9.0'

target 'TestLocalPod' do
  use_frameworks!

  pod 'Network', :path => '../Network'
end

这里有一个 path 关键字,它表示在 pod install 执行时,在指定的路径下寻找 Network.podspec 文件。

下面执行 pod install 命令,提示信息如下:

Analyzing dependencies
Downloading dependencies
Installing Network (0.0.1)
Generating Pods project
Integrating client project
Pod installation complete! There is 1 dependency from the Podfile and 1 total pod installed.

现在 Network 这个库就集成到了壳工程中。
与使用远程库不同,本地库的源文件会在 Development Pods 这个目录下,而不是 Pods 目录,顺便一提,CocoaPods 的库开发,一般也是这样搭建环境的,开发完成后再修改 spec 文件,将其 pull request 到远程索引库。

二 本地私有库 - 单独测试

方案一

首先在 LocalLib/Network/ 路径下创建一个测试工程 Example,然后将 Classes 拖到这个测试工程中,这里需要注意的是,ExampleClasses 是引用关系,不要 Copy
简单粗暴的拖拽,现在 Example 工程就可以使用 Network 库了。

方案二

Network 通过 CocoaPods 安装在 Example 中,和安装在壳工程一样。

方案三(推荐)

看到这里,是不是感觉很烦?就是想做个测试而已,还要拖来拖去,那么繁琐。

不要着急下面来介绍一种更快捷高效的方式,执行下面的命令:

pod lib create ADFMBase
----------------------------
What platform do you want to use?? [ iOS / macOS ]  # 平台
 > ios

What language do you want to use?? [ Swift / ObjC ] # 语言
 > objc

Would you like to include a demo application with your library? [ Yes / No ] # 是否需要包含一个Demo
 > yes

Which testing frameworks will you use? [ Specta / Kiwi / None ]
 > none

Would you like to do view based testing? [ Yes / No ]
 > no

What is your class prefix?
 > AD

现在我们就有了一个 CocoaPods 的模板工程,它的结构是这样的:

~/Desktop/本地私有库 » tree ADFMBase -L 2                                                                           jingshi@goodswifter
ADFMBase
├── ADFMBase
│   ├── Assets
│   └── Classes
│       └── ReplaceMe.m
├── ADFMBase.podspec
├── Example
│   ├── ADFMBase
│   ├── ADFMBase.xcodeproj
│   ├── ADFMBase.xcworkspace
│   ├── Podfile
│   ├── Podfile.lock
│   ├── Pods
│   └── Tests
├── LICENSE
├── README.md
└── _Pods.xcodeproj -> Example/Pods/Pods.xcodeproj

10 directories, 5 files

看吧,把源码拖到 ReplaceMe.m 的同级目录,执行 pod install,就完成了本地私有库和其测试工程。
Cocoapods 本地私有库和远程私有库的使用_第1张图片

三 远程私有库

Cocoapods 本地私有库和远程私有库的使用_第2张图片

现在使用 pod lib create 就可以方便的生成一个本地私有库了,但是本地私有库有一定的局限性,例如:

  • 需要在 Podfile 文件中主动指明路径;
  • 版本升级不容易维护;
  • 多人开发时,不方便进行合作;

远程私有库就可以方便的解决以上的问题,`制作远程私有库分为以下几个步骤

  1. 创建私有 git远程仓库;
  2. 创建私有 CocoaPods 远程索引库;
  3. 创建 Pod 所需要的项目工程文件,并上传到 git 远程私有库;
  4. 验证 podspec 描述文件;
  5. 向私有 CocoaPods 远程索引库提交 podspec 描述文件;
  6. 使用 Pod 库;

git 仓库的创建在此就不在赘述了,本文中我使用 github 做示例,私有 CocoaPods 远程索引库实际上也是一个 git 仓库,现在我们有两个私有库,一个用来存放 Pod 库的源码,一个用来存放 Pod 库的描述文件。

SSH 授权

添加私有索引库需要使用 SSH 授权,也是和 Git 仓库一样的,了解的同学可以跳过这一步骤,首先创建公钥:

ssh-keygen

然后找到下面的文件:

~/.ssh/id_rsa.pub

里面存放的字符就是公钥了,然后将公钥添加 github,链接如下:

https://github.com/settings/keys

添加私有远程索引库

现在执行 pod repo,可以看到下面的信息:

master
- Type: git (master)
- URL:  https://github.com/CocoaPods/Specs.git
- Path: /Users/jingshi/.cocoapods/repos/master

现在我们只有一个 CocoaPods 远程索引库,也是官方的索引库,下面执行:

  • 注意 : 创建私有库的时候一定要创建 .gitignore 文件
pod repo add ADFMSpecs https://github.com/goodswifter/ADFMSpecs.git

此时我们的 CocoaPods 远程索引库就安装好了,到下面的路径去看一下:

~/.cocoapods/repos

上传源码到 Git

还记得 pod lib create 命令吗?前面我们使用它来制作了本地私有库,现在它又排上用场了,执行:

pod lib create ADFMBase

源码拖到 ReplaceMe.m 的同级目录,它现在看起来应该是这个样子:

.
├── Assets
└── Classes
    └── Category
        ├── CALayer+PauseAimate.h
        ├── CALayer+PauseAimate.m
        ├── UIImage+XMGImage.h
        ├── UIImage+XMGImage.m
        ├── UIView+XMGLayout.h
        └── UIView+XMGLayout.m

3 directories, 6 files

执行 pod install,就完成了本地私有库和其测试工程,通过测试之后,我们就可以把这个本地私有库制作成远程私有库了。

首先修改 ADFMBase.podspec 文件:

Pod::Spec.new do |s|
  s.name                  = 'ADFMBase'
  s.version               = '0.0.1'
  s.summary               = 'ADFMBase.'
  s.homepage              = 'https://github.com/goodswifter/ADFMBase'
  s.license               = { :type => 'MIT', :file => 'LICENSE' }
  s.author                = { 'goodswifter' => '[email protected]' }
  s.source                = { :git => 'https://github.com/goodswifter/ADFMBase.git', :tag => s.version.to_s }
  s.ios.deployment_target = '9.0'
  s.source_files          = 'ADFMBase/Classes/**/*'
end

然后使用质量检查工具验证一下,保证在 ADFMBase.podspec 路径下,执行:

pod lib lint

根据提示修复就好了

 -> ADFMBase (0.0.1)
 
ADFMBase passed validation.

下面执行:

git add .
git commit -m x

然后和远程仓库进行关联:

git remote add origin https://github.com/goodswifter/ADFMBase.git
git pull origin master
git push origin master

最后打标签

git tag 0.0.1
git push --tags

上传 Spec 到远程索引库

首先执行下面的命令:

pod spec lint

检验通过后,提示如下:

ADFMBase.podspec passed validation.

然后将 podspec 文件推到远程私有索引库:

pod repo push ADFMSpecs ADFMBase.podspec
  • 上传报错
pod repo push ADFMSpecs ADFMBase.podspec --allow-warnings

Validating spec
 -> ADFMBase (0.0.1)
    - WARN  | url: The URL (https://github.com/goodswifter/ADFMBasic) is not reachable.
    - NOTE  | xcodebuild:  note: Using new build system
    - NOTE  | [iOS] xcodebuild:  note: Planning build
    - NOTE  | [iOS] xcodebuild:  note: Constructing build description

Updating the `ADFMSpecs' repo

[!] /usr/bin/git -C /Users/jingshi/.cocoapods/repos/ADFMSpecs pull

Your configuration specifies to merge with the ref 'refs/heads/master'
from the remote, but no such ref was fetched.
  • 原因 : 创建私有库的时候没有创建 .gitignore 文件
  • 解决办法 : 添加 .gitignore 文件即可

现在看一下本地索引库中是否已经添加成功:

~/.cocoapods/repos

再看一看你的远程索引库中是否添加成功,现在搜索一下本地索引文件试试:

-> ADFMBase (0.0.1)
   ADFMBase.
   pod 'ADFMBase', '~> 0.0.1'
   - Homepage: https://github.com/goodswifter/ADFMBase
   - Source:   https://github.com/goodswifter/ADFMBase.git
   - Versions: 0.0.1 [ADFMSpecs repo]

现在我们可以找到自己的远程私有库了,下面将 Podfile 文件改成这样:

source 'https://github.com/goodswifter/ADPodSpecs.git'
source 'https://github.com/goodswifter/ADFMSpecs.git'

platform :ios, '9.0'

target 'Test01' do
  use_frameworks!
  
  pod 'ADCategories'
  pod 'ADFMBase'

end

执行 pod install,整个远程私有库的搭建和使用就完成了。

CocoaPods 库升级

我们使用远程私有库的目的就是为了版本升级和多人开发,那么远程私有库如何进行升级,升级后其他人又如何使用呢?现在我们给 ADFMBase 进行升级,给它再增加一些功能:

.
ADFMBase
│   ├── Assets
│   └── Classes
│       ├── Base
│       │   ├── Base.h
│       │   ├── Sington.h
│       │   ├── XMGConst.h
│       │   └── XMGConst.m
│       ├── Category
│       │   ├── CALayer+PauseAimate.h
│       │   ├── CALayer+PauseAimate.m
│       │   ├── UIImage+XMGImage.h
│       │   ├── UIImage+XMGImage.m
│       │   ├── UIView+XMGLayout.h
│       │   └── UIView+XMGLayout.m
│       └── Tool
│           ├── XMGAlertTool.h
│           ├── XMGAlertTool.m
│           ├── XMGCacheTool.h
│           ├── XMGCacheTool.m
│           ├── XMGDeviceMessage.h
│           ├── XMGDeviceMessage.m
│           ├── XMGNoticeLocal.h
│           └── XMGNoticeLocal.m
├── ADFMBase.podspec
├── Example
├── LICENSE
├── README.md
└── _Pods.xcodeproj -> Example/Pods/Pods.xcodeproj

ADFMBase 的测试工程中测试无误后,将 ADFMBase.podspecversion 修改一下:

Pod::Spec.new do |s|
  s.name          = "ADFMBase"
  s.version       = "0.1.0"
  s.summary       = "ADFMBase."
  s.homepage      = "https://github.com/goodswifter/ADFMBase"
  s.license       = 'MIT'
  s.author        = { "goodswifter" => "[email protected]" }
  s.source        = { :git => "https://github.com/goodswifter/ADFMBase.git", :tag => "#{s.version}" }
  s.source_files    = "ADFMBase/Classes/**/*.{h,m}"
  s.platform      = :ios, "9.0" #平台及支持的最低版本
end

现在检查一下私有库是否有错误:

pod lib lint

检查通过后就可以将 ADFMBase0.1.0 版本推到远程私有库中,同时建立 0.1.0 的 Tag。

然后检查一下 spec 文件:

pod spec lint

检查通过后,执行:

pod repo push ADFMSpecs ADFMBase.podspec

如果存在警告,可以执行:

pod repo push ADFMSpecs ADFMBase.podspec --allow-warnings

远程私有库和远程私有索引库全部更新完毕,现在我们回到使用者的视角,这个库可以使用了吗?还不行。

因为本地的索引文件还没有更新,这个源还找不到,现在进入壳工程,执行:

pod update --no-repo-update

ADFMBase 的 0.1.0 版本就乖乖的进入了壳工程。

CocoaPods 库依赖

如果在我们之前的工程中, 大量使用了 ASI 框架, 大家也都知道, ASI 框架不再维护, 需要换成别的网络框架, 例如 AFN, 但是现在要更换框架的话, ASI 框架在我们的项目中已经无处不再, 这样换的话,我们是不是很痛苦呢?
Cocoapods 本地私有库和远程私有库的使用_第3张图片
所以我们一般在开发中都会封装网络请求,做到分层解耦,这样如果换框架,只修改网络请求这层的封装就可以了,那么现在我们需要将 ASI 封装成 Netwok,再把 Netwok 弄到我们的 ADFMBase 里面去,怎么做呢?
Cocoapods 本地私有库和远程私有库的使用_第4张图片
现在先将 Network 拖到 ADFMBase 的 Classes目录中,因为ADFMBase的测试工程没有AFN,所以Network` 肯定是会报错了,不要慌,下面我们修改 spec 文件:

Pod::Spec.new do |s|
  s.name          = "ADFMBase"
  s.version       = "0.3.0"
  s.summary       = "ADFMBase."
  s.homepage      = "https://github.com/goodswifter/ADFMBase"
  s.license       = 'MIT'
  s.author        = { "goodswifter" => "[email protected]" }
  s.source        = { :git => "https://github.com/goodswifter/ADFMBase.git", :tag => "#{s.version}" }
  s.source_files    = "ADFMBase/Classes/**/*.{h,m}"
  s.platform      = :ios, "9.0" #平台及支持的最低版本
  s.dependency 'AFNetworking'
end

dependency 指明了这个库的依赖,改好之后 pod installAFN 就安装到了 ADFMBase 的测试工程中,现在就可以使用 AFN 进行网络请求封装,直接 import 就可以了

现在再进行一次远程私有库升级,整个依赖就做好了

CocoaPods 子库

现在我们实现了一个完整的远程私有库,可以升级,依赖其他的库,提供给其他人使用,但是现在还有一点问题,其他人如果要用我们的库,就需要把 ADFMBase 完整的克隆过来,但是他可能只需要 ADFMBase 里面的 Network,其他的扩展、工具等并不想使用,也不想导入过来,怎么办?有两种方案:

  • Network 剥离出来,再单独建一个远程私有库;
  • 使用子库迁出 Network

第一种方案大家已经知道了,就是上面的一大篇,麻烦不说,而且东西一多起来,这里一个库,那里一个库,也不容易管理,所以,下面就有请子库隆重登场。

注意 Subspecs 这里,它就是本节要讲的东西,首先将 spec 改成下面这样:

Pod::Spec.new do |s|
  s.name          = "ADFMBase"
  s.version       = "0.4.0"
  s.summary       = "ADFMBase."
  s.homepage      = "https://github.com/goodswifter/ADFMBase"
  s.license       = 'MIT'
  s.author        = { "goodswifter" => "[email protected]" }
  s.source        = { :git => "https://github.com/goodswifter/ADFMBase.git", :tag => "#{s.version}" }
  # s.source_files    = "ADFMBase/Classes/**/*.{h,m}"

  # 子库
  s.subspec 'Base' do |b|
    b.source_files = 'ADFMBase/Classes/Base/**/*'
  end

  s.subspec 'Category' do |c|
    c.source_files = 'ADFMBase/Classes/Category/**/*'
  end

  s.subspec 'Network' do |n|
    n.source_files = 'ADFMBase/Classes/Network/**/*'
    n.dependency 'AFNetworking'
  end

  s.subspec 'Tool' do |t|
    t.source_files = 'ADFMBase/Classes/Tool/**/*'
  end

  s.platform      = :ios, "9.0" #平台及支持的最低版本
end

如果依赖的框架只有某一个子库,使用,要将依赖放到子库的spec中
在这里要注意 source_files 和 dependency 以及版本的变化,修改完成推到远程索引库,并打好 0.4.0 的分支,执行:

pod spec lint
pod repo push ADFMSpecs ADFMBase.podspec
pod update --no-repo-update
pod search ADFMBase

CocoaPods 资源依赖

现在我们可以让一个库依赖另外一个库,但是看下面这段代码:

UIView *view = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] firstObject]

这段代码读取了一个 XIB 文件,这个库的结构是这样的:

.
├── Assets
└── Classes
    ├── Controller
    │   ├── ADNavVC.h
    │   ├── ADNavVC.m
    │   ├── ADTabBarVC.h
    │   └── ADTabBarVC.m
    └── View
        ├── ADMiddleView.h
        ├── ADMiddleView.m
        ├── ADMiddleView.xib
        ├── ADNavBar.h
        ├── ADNavBar.m
        ├── ADTabBar.h
        └── ADTabBar.m

们可以成功调用这个方法吗?不能,因为 ADMiddleView.xib 这个文件的 TargetMainModule,使用 CocoaPods 把这个库安装到我们项目后,XIB 文件即使在,也是在 Pods 这个工程里,而我们在壳工程中使用 ADMiddleView.xib,也是必然找不到的。

下面我们把模板库的测试工程编译一下,打开 Products 目录下的 .app 文件,看一下文件结构:

.
├── ADFMMain_Example
├── Assets.car
├── Base.lproj
│   └── LaunchScreen.storyboardc
├── Frameworks
│   ├── ADFMMain.framework
│   │   ├── ADFMMain
│   │   ├── ADFMMain.bundle
│   │   │   ├── Info.plist
│   │   │   ├── _CodeSignature
│   │   │   ├── tabbar_bg@2x.png
│   │   │   ├── tabbar_bg@3x.png
│   │   ├── ADMiddleView.nib
│   │   ├── Info.plist
│   │   └── _CodeSignature
├── Info.plist
├── PkgInfo
├── _CodeSignature
└── en.lproj

通过路径可以看到,ADMiddleView.nib 是在:

mainBundle/Frameworks/ADFMMain.framework/ADMiddleView.nib

这个路径下面,因此 mainBundle 中肯定是找不到资源文件的,那么该如何修改呢?

+ (instancetype)middleView {
    NSBundle *currentBundle = [NSBundle bundleForClass:self];
    
    return [[currentBundle loadNibNamed:NSStringFromClass(self) owner:nil options:nil] firstObject];
}

这部分的重点就是 [NSBundle bundleForClass:self] 这个方法。

CocoaPods 图片依赖

上面我们讲到了怎样使用 Pod 库里面的 XIB 文件,但是还有其他资源文件,例如图片、音频、视频,图片我们一般是放在 Assets.xcassets,但是 Pod 库并没有对应的路径,那么它所需要的图片放在哪里,已经如何使用呢?现在使用 pod lib create 命令创建一个 Pod 库,进入以下路径:

组件名/Assets

把一些图片拖入到 Assets 文件夹内,然后在 podspec 文件中加入以下代码

s.resource_bundles = {
  '组件名' => ['组件名/Assets/*.png'] //只加载 png 文件
  # '组件名' => ['组件名/Assets/*'] //加载所有文件
}

然后执行 pod installPod 库中就出现了之前拖入 Assets 文件夹的图片,但是现在还不能使用,我们先来看一下打包以后这些图片的路径:

.
├── ADFMMain_Example
├── Assets.car
├── Base.lproj
│   └── LaunchScreen.storyboardc
├── Frameworks
│   ├── ADFMMain.framework
│   │   ├── ADFMMain
│   │   ├── ADFMMain.bundle
│   │   │   ├── Info.plist
│   │   │   ├── _CodeSignature
│   │   │   ├── tabbar_bg@2x.png
│   │   │   ├── tabbar_bg@3x.png
│   │   ├── ADMiddleView.nib
│   │   ├── Info.plist
│   │   └── _CodeSignature
├── Info.plist
├── PkgInfo
├── _CodeSignature
└── en.lproj

可以看到,打包后的路径在:

mainBundle/Frameworks/ADFMMain.framework/ADFMMain.bundle

复制代码这个路径下面,而代码中的 [UIImage imageNamed:@"xxx.png"] 读取的是 mainBundle 下的资源文件,因此还是找不到的,那么这时使用图片,应该将代码改成这样:

NSInteger scale = [[UIScreen mainScreen] scale];
NSBundle *currentBundle = [NSBundle bundleForClass:self];
NSString *fullImageName = [NSString stringWithFormat:@"%@@%zdx", imageName, scale];
NSString *currentBundleName = [currentBundle.infoDictionary[@"CFBundleName"] stringByAppendingString:@".bundle"];
NSString *path = [currentBundle pathForResource:fullImageName ofType:@"png" inDirectory:currentBundleName];
path ? [UIImage imageWithContentsOfFile:path] : nil;

这里需要注意的是,文件名需要完整。以上是在代码中加载图片,如果是在 XIB 中加载图片,应该怎样做呢?那么再看一下上面的目录结构,ADFMMain.nibADFMMain.bundle 处于同一个目录,我们可以在 ADFMMain.xib 中通过相对路径,使用 ADFMMain.bundle 里面的图片,因此在 XIB 中,图片名应该是这样的:

ADFMMain.bundle/tabbar_bg@2x.png

你可能感兴趣的:(组件化开发)