草庐IT

iOS私有库快速搭建(CocoaPods私有库)

麻辣柠檬 2023-10-22 原文
小镇争夺战(加载图).jpg

补充:

2023-3-27 强制升级 pod 库

一、创建私有 Pod 索引库

  Pod 索引库本质是所有库的podspec文件集合。每次创建新库或更新版本时都会根据版本号上传新的podspec文件,具体可以看cocoaPods索引库

  创建一个索引库,以Gitee举例。创建一个新的私有库,名字建议以PrivatePodspecs结尾,可以加前缀。

创建索引库

  创建后需要初始化仓库,否则在推podspec文件时会出现仓库未初始化导致推送失败的情况。之后打开终端,输入pod repo list会显示目前的repo列表。

pod repo list

---------------------

#这两个是安装完 Cocoapods 之后都会有的。在使用 pod search 时,会从repo列表中取寻找目标的库。
cocoapods
- Type: git (remotes/origin/master)
- URL:  https://github.com/CocoaPods/Specs.git
- Path: /Users/kenan/.cocoapods/repos/cocoapods

trunk
- Type: CDN
- URL:  https://cdn.cocoapods.org/
- Path: /Users/kenan/.cocoapods/repos/trunk

  使用pod repo add [名称] [路径]命令,将刚刚的索引库克隆地址添加到repo列表中,例如:

pod repo add YTPrivatePodspecs git@gitee.com:fa_dou_miao/ytprivate-podspecs.git

#添加完成后再输入 pod repo list 查看。

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

trunk
- Type: CDN
- URL:  https://cdn.cocoapods.org/
- Path: /Users/kenan/.cocoapods/repos/trunk

YTPrivatePodspecs
- Type: git (master)
- URL:  git@gitee.com:fa_dou_miao/ytprivate-podspecs.git
- Path: /Users/kenan/.cocoapods/repos/YTPrivatePodspecs

二、创建私有库

  索引库完成后我们就可以创建真正的私有库了。首先在Gitee上创建一个YTPrivateBaseKit私有库【注意,除了索引库外,其他组件库不需要添加到repo列表】。然后再使用命令pod lib create [库名]来创建本地项目,例如:


pod lib create YTPrivateBaseKit

#然后回答几个问题

#选择平台
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 ]  
 > no

  完成后会自动打开项目,我这里选用的 Swift 语言,如果选择 OC 的话需要多回答几个问题,都是问你需不需要工具之类的,根据自己的情况设置即可。

  项目打开后我们Show in Finder,文件夹结构如下:

文件结构

  其中Example文件夹为示例项目,实际上在真正上传时默认只会上传YTPrivateBaseKit文件夹下的Classes文件夹和Assets文件夹中的文件。

  所以我们将已经写好的库放入Classes文件夹下并删除ReplaceMe文件,然后进入Example文件夹下执行pod install命令,每次修改库的内容都需要对示例项目pod install一次,如果需要依赖其他第三方库需要在podspec文件中设置依赖,后边我会细说如何设置。

  之后可以在示例项目中引用库,并写一些代码进行测试。注意!封装库的代码一定要控制好publicopenprivate等访问级别。只有添加了publicopen的类,属性和方法才可以被外界访问。

三、设置podspec

  podspec文件默认打开如下:(这里去除掉了注释部分,只留下基础内容)


Pod::Spec.new do |s|

  # 库名称,默认和工程名相同,建议不改
  s.name             = 'YTPrivateBaseKit'   

  # 库的版本,每次升级版本后必须要在这里修改版本号
  s.version          = '0.1.0'                  

  # 该库的简介,更改成适合的简介,使用默认简介会出现简介没有意义的错误
  s.summary          = 'A short description of YTPrivateBaseKit.'   

  # 详细描述,一般不用改,有readme呢
  s.description      = <<-DESC
TODO: Add long description of the pod here.
                       DESC

  # 库的主页,需要更改为正确的主页
  s.homepage         = 'https://github.com/柯南/YTPrivateBaseKit' 

  # 许可,私有库可以不改
  s.license          = { :type => 'MIT', :file => 'LICENSE' }

  # 作者,可以不改
  s.author           = { '柯南' => '15933459928@163.com' }    

  # 库的克隆地址,这个地址必须改成正确的克隆地址,可以是 https 或 ssh
  s.source           = { :git => 'https://github.com/柯南/YTPrivateBaseKit.git', :tag => s.version.to_s } 

  # 该库最低支持版本,可以修改为对应版本
  s.ios.deployment_target = '10.0'

  # 该库上传文件的路径,默认是 Classes 文件夹下的所有文件夹及文件,默认不需要改
  s.source_files = 'YTPrivateBaseKit/Classes/**/*'

  #--------------------------------------------------
  # 以下是默认没有但可以自行添加的基础配置

  # 设置指定版本号或非指定版本号的依赖库,
  s.dependency 'SnapKit'
  # s.dependency 'SnapKit', '~> 0.1.0'

  # 指定 Swift 语言版本,Swift 项目需要设置这个
  s.swift_version = '4.2'


end

  每次修改完podspec文件文件后,也需要重新进入Example文件夹pod install一次。示例项目会自动安装所依赖的库,不需要单独在Podfile文件中编写pod xxx

  在完成对库的编写与测试后,将其推送到远程的私有仓库中并为其打上标签,标签的名称为podspec中的version版本号,注意需要推送标签。

推送标签

  在推送完成后,我们需要进入podspec文件所在目录,对podspec文件执行pod lib lint --allow-warnings命令。例如:


pod lib lint --allow-warnings

#---------------------------------

-> YTPrivateBaseKit (0.1.0)
    - NOTE  | url: The URL (https://gitee.com/fa_dou_miao/ytprivate-base-kit) is not reachable.
    - NOTE  | xcodebuild:  note: Using new build system
    - NOTE  | xcodebuild:  note: Using codesigning identity override: -
    - NOTE  | xcodebuild:  note: Build preparation complete
    - NOTE  | [iOS] xcodebuild:  note: Planning
    - NOTE  | [iOS] xcodebuild:  note: Building targets in dependency order
    - NOTE  | [iOS] xcodebuild:  /Users/kenan/YTPrivateBaseKit/YTPrivateBaseKit/Classes/123.storyboard:Y6W-OH-hqX: warning: “View Controller“ is unreachable because it has no entry points, and no identifier for runtime access via -[UIStoryboard instantiateViewControllerWithIdentifier:]. [9]

YTPrivateBaseKit passed validation.

  当出现passed validation时证明验证成功,如果检测失败会出现类似[!] YTPrivateBaseKit did not pass validation, due to 47 errors.的提示,可以通过给出的- ERROR信息找到失败的原因。

  之后再执行pod spec lint --allow-warnings命令验证spec。同样出现passed validation时证明验证成功。接下来我们就可以将podspec文件推到索引库中了。

四、推送私有库

  在两次lint验证都成功后,使用命令pod repo push [索引库名称] [podspec文件] --allow-warnings进行推送,例如:

pod repo push YTPrivatePodspec YTPrivateBaseKit.podspec --allow-warnings

#------------------------------------------------------------
#当出现以下内容,并且没有 ERROR 时证明推送成功

Validating spec
 -> YTPrivateBaseKit (0.1.0)
    - NOTE  | url: The URL (https://gitee.com/fa_dou_miao/ytprivate-base-kit) is not reachable.
    - NOTE  | xcodebuild:  note: Using new build system
    - NOTE  | xcodebuild:  note: Using codesigning identity override: -
    - NOTE  | xcodebuild:  note: Build preparation complete
    - NOTE  | [iOS] xcodebuild:  note: Planning
    - NOTE  | [iOS] xcodebuild:  note: Building targets in dependency order
    - NOTE  | [iOS] xcodebuild:  YTPrivateBaseKit/YTPrivateBaseKit/Classes/123.storyboard:Y6W-OH-hqX: warning: “View Controller“ is unreachable because it has no entry points, and no identifier for runtime access via -[UIStoryboard instantiateViewControllerWithIdentifier:]. [9]

Updating the `YTPrivatePodspec' repo

Adding the spec to the `YTPrivatePodspec' repo

 - [Add] YTPrivateBaseKit (0.1.0)

Pushing the `YTPrivatePodspec` repo

  推送成功后就可以使用pod search搜索到啦!


pod search YTPrivateBaseKit

#---------------------------------

-> YTPrivateBaseKit (0.1.0)
   一个私有库
   pod 'YTPrivateBaseKit', '~> 0.1.0'
   - Homepage: https://gitee.com/fa_dou_miao/ytprivate-base-kit
   - Source:   https://gitee.com/fa_dou_miao/ytprivate-base-kit.git
   - Versions: 0.1.0 [YTPrivatePodspec repo]

  之后可以新建一个项目测试能否通过Pod安装,需要注意的是需要在Podfile文件顶部添加上source

# 第一个为 cocoapods 索引库的地址
source 'https://github.com/CocoaPods/Specs.git'

# 第二个为私有索引库的地址
source 'git@gitee.com:fa_dou_miao/ytprivate-podspecs.git'

use_frameworks!
platform :ios, '10.0'

target 'Demo' do

    pod 'YTPrivateBaseKit'

end

  只有添加了source才可以在pod install时搜索到私有库,不填加的话默认只会在cocoapods索引中搜索。并且由于在podspec文件中设置了依赖库,在pod install时会自动将依赖的其他库安装进来。

  在后续修改库的内容或升级代码后,只需要从第三步继续执行即可升级私有库。

五、设置图片资源

  在私有库中可以通过xcassets使用图片资源。首先将图片资源文件夹放入Assets文件夹下。

设置图片资源

  并在podspec文件中设置资源路径,然后重新pod install一下,就可以在示例项目的pod库中看到该资源文件夹。


  s.resource_bundles = {
    'YTPrivateBaseKit' => ['YTPrivateBaseKit/Assets/*.{xcassets}']
  }
  
  # 如果只是单个图片的话,可以用这种方式
  # s.resource_bundles = {
  #   'YTPrivateBaseKit' => ['YTPrivateBaseKit/Assets/*.png']
  # }

  但私有库中的图片不能直接通过UIImage(named: String)使用。因为命名空间的存在,当项目引入私有库后,使用named加载图片默认使用的是当前项目的命名空间,而我们的图片资源存放在私有库中,需要使用私有库的命名空间才可以获取。

  我们可以在私有库中通过以下方式获取资源图片。


// 1. 通过命名空间创建 Bundle,命名空间默认就是私有库的名称

    public class func frameworkBundle(_ name: String) -> Bundle? {
        var frameworksUrl = Bundle.main.url(forResource: "Frameworks", withExtension: nil)
        frameworksUrl = frameworksUrl?.appendingPathComponent(name)
        frameworksUrl = frameworksUrl?.appendingPathExtension("framework")
        
        guard let frameworkBundleUrl = frameworksUrl else {
            return nil
        }
        
        let bundle = Bundle(url: frameworkBundleUrl)
        frameworksUrl = bundle?.url(forResource: name, withExtension: "bundle")
        
        guard let bundleUrl = frameworksUrl else {
            return nil
        }
        
        return Bundle(url: bundleUrl)
    }

// 2.通过 Bundle 获取图片

    public class func getImage() -> UIImage? {
        
        var bundle: Bundle?
        if let url = Bundle.main.url(forResource: "YTBaseImages.xcassets", withExtension: nil) {
            
            bundle = Bundle(url: url)
        }else {
            
            bundle = BaseKit.frameworkBundle("YTPrivateBaseKit")
        }
        
        let image = UIImage.init(named: "111", in: bundle, compatibleWith: nil)
        return image
    }

  除了图片资源外,其他的资源文件也可以通过该方法获取。

六、设置子库

  Pod库除了可以直接安装全部功能外,还可以通过子库的方式安装部分功能,例如:

pod 'YTPrivateBaseKit/Core'
pod 'YTPrivateBaseKit/Extension'

  首先将你的模块分类

模块分类

  然后在podspec文件中设置不同模块的文件路径。


#注释掉原本的模块路径
#  s.source_files = 'YTPrivateBaseKit/Classes/**/*'

# 这里是设置默认安转的模块,不设置的话执行 pod 'YTPrivateBaseKit' 时默认安装全部模块,设置后默认只安装设置的模块
#  s.default_subspecs = "Core"


# Core 子模块
  s.subspec 'Core' do |sp|
    # 分别设置子模块的文件路径与资源路径
      sp.source_files = 'YTPrivateBaseKit/Classes/Core/**/*'
      sp.resource_bundles = {
        'YTPrivateBaseKit' => ['YTPrivateBaseKit/Assets/*.{xcassets}']
      }
  end

# Extension 子模块
  s.subspec 'Extension' do |sp|
      sp.source_files = 'YTPrivateBaseKit/Classes/Extension/**/*'
  end

  设置后重新将私有库推送升级,即可在使用时通过YTPrivateBaseKit/CoreYTPrivateBaseKit/Extension按需安装功能库。

七、强制升级pod库

当我们使用某些库时会出现 pod lint 失败的问题,例如在使用 Kingfisher 的时候,由于项目不支持 SwiftUI, 会导致 pod lint 失败。但是我们又想用这个库,可以使用手动升级的方式。

步骤与代码升级类似:
1.首先将我们的私有库推上去,打上标签,注意标签需要推送。

2.将 PrivatePodspec 索引库拉取到本地,打开对应私有库的文件夹,新建一个对应版本号的文件夹,然后将新的 podsepc 文件放进去,然后推送。

目录结构如下图


image.png

然后就强制升级成功啦,可以使用 pod install 进行安装。

以上便是快速搭建私有库的全部流程了
??????如果觉得有用的话就点个赞吧??????

有关iOS私有库快速搭建(CocoaPods私有库)的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  3. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  4. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  5. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  6. Ruby - 如何处理子类意外覆盖父类(super class)私有(private)字段的问题? - 2

    假设您编写了一个类Sup,我决定将其扩展为SubSup。我不仅需要了解你发布的接口(interface),还需要了解你的私有(private)字段。见证这次失败:classSupdefinitialize@privateField="fromsup"enddefgetXreturn@privateFieldendendclassSub问题是,解决这个问题的正确方法是什么?看起来子类应该能够使用它想要的任何字段而不会弄乱父类(superclass)。编辑:equivalentexampleinJava返回"fromSup",这也是它应该产生的答案。 最佳答案

  7. ruby - 为什么不能使用类IO的实例方法noecho? - 2

    print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

  8. ruby - 从另一个私有(private)方法中使用 self.xxx() 调用私有(private)方法 xxx,导致错误 "private method ` xxx' called” - 2

    我正在尝试获得良好的Ruby编码风格。为防止意外调用具有相同名称的局部变量,我总是在适当的地方使用self.。但是现在我偶然发现了这个:classMyClass上面的代码导致错误privatemethodsanitize_namecalled但是当删除self.并仅使用sanitize_name时,它会起作用。这是为什么? 最佳答案 发生这种情况是因为无法使用显式接收器调用私有(private)方法,并且说self.sanitize_name是显式指定应该接收sanitize_name的对象(self),而不是依赖于隐式接收器(也是

  9. ruby - 如何以表格格式快速打印 Ruby 哈希值? - 2

    有没有办法快速将表格格式的ruby​​哈希打印到文件中?如:keyAkeyBkeyC...1232343451253474456...其中散列的值是不同大小的数组。还是使用双循环是唯一的方法?谢谢 最佳答案 试试我写的这个gem(在表中打印散列、ruby对象、ActiveRecord对象):http://github.com/arches/table_print 关于ruby-如何以表格格式快速打印Ruby哈希值?,我们在StackOverflow上找到一个类似的问题:

  10. ruby - 如何在 Ruby 中实现私有(private)内部类 - 2

    来自Java,我正在尝试在Ruby中实现LinkedList。我在Java中实现它的通常方法是有一个名为LinkedList的类和一个名为Node的私有(private)内部类,其中LinkedList的每个对象都作为Node对象。classLinkedListprivateclassNodeattr_accessor:val,:nextendend我不想将Node类暴露给外部世界。然而,通过Ruby中的这个设置,我可以使用这个访问LinkedList类之外的私有(private)Node类对象-node=LinkedList::Node.new我知道,在Ruby1.9中,我们可以使用

随机推荐