创建自己的CocoaPods的私有库

在我们平时的开发中,一定出现过这样的问题

  1. 创建了2个项目,一个项目却是另一个项目的分身,修改代码时需要修改2次。
  2. 新建项目时,从其他项目拖代码至另一个项目复制代码块。
  3. 在众多项目中,代码块重复太多,不知道哪一个是最新的。

以上问题,是我们开发常见的问题,为了解决这些问题,提高开发的质量,加快开发速度,我们有必要自己建立一套成熟的代码库,它可以反复使用并且反复迭代更新,一处修改,多处响应。

创建本地Pod

pod lib create ***

将会询问以下内容:

  1. What Language do you want to use?? [Swift / objC]
  2. Would you like to include a demo application with your Library? [Yes / No]
  3. Would you like to do view based testing? [Yes / No]
  4. What is your class prefix?
    创建成功后会打开Xcode
    路径

打开JQTools.xcworkspace

目录结构

注意,所有类都必须放在classes文件夹下,在创建文件的时候,需要自己选择一次。

Classes文件夹

引用本地的pod

我建议新建的本地库先在本地进行长时间测试,这样可以方便的修改和维护,不用每次修改都要提交一次,更新pod。等你觉得它变得已经很稳定了,再提交至pod,当然代码还是要提交至远程仓库的。

pod 'JQTools',:path=> '/Users/***/MyProject/JQTools'

每次修改后,都要clear一次,前期你一定会大量的使用

配置podspec

  • s.version : 版本号,这里的版本号与Github仓库中的Tag一一对应
  • s.summary : 你的Pod库的总结性描述.
  • s.description : 你的Pod库的具体描述,【这里要注意,s.description的长度必须大于s.summary】
  • s.source: 指向对应的GitHub仓库.
  • s.dependency:表示依赖库
  • s.public_header_files:是要公开的头文件
  • s.frameworks:依赖库
  s.ios.deployment_target = '10.0'
  s.source_files = 'JQTools/Classes/**/*'
  
//图片,文件等资源
   s.resource_bundles = {
     'JQToolsRes' => ['JQTools/Assets/*']
   }

  # s.public_header_files = 'Pod/Classes/Header.h'

//依赖库
   s.frameworks = 'UIKit'
   s.dependency 'SnapKit'
   s.dependency 'ObjectMapper'
   s.dependency 'QMUIKit', '~> 4.0.4'
   s.dependency 'IQKeyboardManagerSwift', '~> 6.5.5'
   s.dependency 'RxSwift','~> 5.1.1'
   s.dependency 'RxCocoa','~> 5.1.1'
   s.dependency 'SwiftyUserDefaults', '4.0.0-alpha.1'

以上,你已经成功的建立了自己的pod,已经可以进行使用了,建议你先在本地进行测试和使用,稳定后提交自己的pod。




1. 登录Github创建一个public仓库

创建过程略

2. 回到本地和远程仓库绑定

git remote add origin https://github.com/***/****.git

提交

  1. 创建trunk账号

trunk需要pod在0.33及以上版本;pod --version检查你的版本,如果版本过低sudo gem install cocoapods进行更新。

  • 可以先检查是否已注册:pod trunk me
  • 进行注册:pod trunk register ***@qq.com yourName

然后你的邮件将受到信息,进行认证即可

验证Pod

pod lib lint **.podspec # 不爆红就是对的
#或
pod lib lint # 你在你的文件目录下

提交pod

pod trunk push

查询你的pod

pod search WKUIKit

常见问题

1. 如何配置Bundle资源

资源文件,需要放在Assets文件夹下,并且在podspec中指定,注意你指定的名称

   s.resource_bundles = {
     'JQToolsRes' => ['JQTools/Assets/*']
   }

2. 如何引用未使用的类

比如本地pod并没有引用QMUIKit,但你对它进行了扩展支持,那么在项目将会报错,可以使用宏canImport,务必将要使用的方法和类用public

#if canImport(QMUIKit)
import QMUIKit

public func A(){
    //todo
}
#end

如果是OC

#if __has_include("QMUIKit/QMUIKit.h")
#import <QMUIKit/QMUIKit.h>
#endif

3. 模拟器与真机判断

有些方法和类在真机和模拟器有比较大的区别,所有在宏定义上面需要区分

关键词:targetEnvironment

        #if targetEnvironment(simulator)
        if fmodl(Float80(Double(self)), 1) == 0 {//如果有一位小数点
            return (NSString(format: "%.0f", self) as String)
        } else if (fmodf(Float(self*10), 1) == 0) {//如果有两位小数点
            return (NSString(format: "%.1f", self) as String)
        } else {
            return (NSString(format: "%.2f", self) as String)
        }
        #else
        if fmodl(Double(self), 1) == 0 {//如果有一位小数点
            return (NSString(format: "%.0f", self) as String)
        } else if (fmodf(Float(self*10), 1) == 0) {//如果有两位小数点
            return (NSString(format: "%.1f", self) as String)
        } else {
            return (NSString(format: "%.2f", self) as String)
        }
        #endif

4. 自己的pod的Bundle读取

let mainBundle  = Bundle(for: type(of: self))
let path = mainBundle.path(forResource: "JQToolsRes", ofType: "bundle")
let jqToolsBundle = Bundle(path: path!)
let filePath = jqToolsBundle?.path(forResource: "citysCode", ofType: "txt")

如果在修改自己的库里的某些代码,需要资源的时候,建议你这样写:

let mainBundle  = Bundle(for: type(of: self))

如果已经被项目引用,上面的写法就不对了需要改成这样:

let mainBundle  = Bundle(for: JQTool.self)

例子一:读区Resources下的城市表:

image.png
        let mainBundle  = Bundle(for: JQTool.self)
        let path = mainBundle.path(forResource: "JQToolsRes", ofType: "bundle")
        let jqToolsBundle = Bundle(path: path!)
        let filePath = jqToolsBundle?.path(forResource: "citysCode", ofType: "txt")
    
        do {
            let content = try String(contentsOfFile: filePath!)
            print(content)
        } catch  {

        }

为什么是JQToolsRes?前面我们已经在podspec里面配置了,成为了一个bundle

   s.resource_bundles = {
     'JQToolsRes' => ['JQTools/Assets/*']
   }

例子二:读取Resources下的bundle中的图片

image.png

在Icon.bundle中有一张ty_qrcode_bg的图片

        var a = Bundle(for: JQTool.self).path(forResource: "Icon", ofType: "bundle")
        let jqToolBundle = Bundle(path: a!)
        let image = UIImage(named: "ty_qrcode_bg", in: jqToolBundle, compatibleWith: .none)

例子三:读取Resources下的*.xcassets

image.png
        let a = Bundle(for: JQTool.self)
        let image = UIImage(named: "ty_qrcode_line", in: a, compatibleWith: .none)

5. Swift项目中使用OC

为了统一管理OC类,重写组织了结构:


image.png

并在Header中暴露了两个OC类


image.png

如果你出现以下错误


image.png

将private的类提升至public


image.png

再将header.h放置Support files-> XXXX-umbrella.h 中

然后就可以在Pod里或源项目中使用了。


进一步 提高效率开发

一个真正成熟的库,就需要运用到实际的开发项目中,当是一个团队开发时,一个人进行库的维护所花费精力巨大,所以需要进行协同维护

  1. 定义好命名规则
  2. 定义好模块分类
  3. 完美的注释说明
    等等

查看pod trunk --help

image.png

你会发现可以使用add-owner添加拥有者,赋予对库的更新操作,当不在需要此人来进行维护,remove-owner即可,这种方式比较符合公司库的管理,这也是建立公司敏捷开发所需要的

更进一步:一切为了安全

  1. 制作frmaework库
  2. 开发framework库

NOTE:OC需要将Header进行暴露提升,Swift靠public关键词,同时要将OC文件放置XXXFramework.h

runScript

image.png

image.png
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Step 1. Build Device and Simulator versions
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos  BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
# Step 2. Copy the framework structure (from iphoneos build) to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
# Step 3. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"
fi
# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
# Step 5. Convenience step to copy the framework to the project's directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"
# Step 6. Convenience step to open the project's directory in Finder
open "${PROJECT_DIR}"

编辑 \*.podspec文件

s.vendored_frameworks = ['JQTools/Classes/Framework/FrameworkDemo.framework'] # 添加私有的Framework

进行pod install

image.png

  1. 报错:Multiple commands produce....

如果你把framework放在了Classes,重新pod install 时,多引用了,保留以上图片的,删除其他引用即可。

  1. 报错:Framework not found:
#import "TestFramework.h" //改为 #import "TestFramework/TestFramework.h"

总结

trunk 提交至 pod 报错:

  1. warning: Could not find remote branch 0.1 to clone. fatal: Remote branch 0.1 not found in upstream origin

给git仓库打上标签,podspecs.version = 0.1

git tag '0.1'  
git push --tags  
git push origin master

提交仓库报错:hint: Updates were rejected because the tag already exists in the remote.

提交时,未提交Tag标签,导致冲突

git pull --tags

2. error: include of non-modular header inside framework module 'XXXX.Header'
如果你是OC,与Swift的混编,并且出现的错误都是OC的XXX.h

本地pod包的建立,算是你所有开发使用的精华,能够一处变动,全项目修改,你会遇到一个问题:你的代码封装定会用到其他第三方,比如你封装了一个下载图片的类,A项目适合,但B项目并不需要,如果B项目不去pod依赖的其他的第三方,那么你封装下载图片的类会因为没有引用而报错,B项目就不得不去pod,从而导致B项目过于臃肿。
解决的方法:
你可以移除本地的pod依赖,在实际项目看情况使用。canImport宏进行了一次判断,如果不可用,就不能使用,也不会报错。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容