iOS开发分享

【iOS】使用pod创建私有组件

2022-03-11  本文已影响0人  子天々君

创建组件工程

启动命令行,使用pod命令创建组件

pod lib create ZTTools_Swift // 名字自己取,会自动创建相应的工程和文件夹

之后会弹出一些选项,按需要填即可:

// 选择平台
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

// 是否创建UI单元测试
Would you like to do view based testing? [ Yes / No ]
 > No

至此,一个空的组件工程创建完毕。

清理单元测试

一般都用不上单元测试,使用可以把它给删了。

创建私有xcframework

如果不创建私有库,那你组件里的东西都会被看到,这不是我们想要的。
所以,我们需要创建一个库,把代码全放到这个库里面,然后再把这个库弄到组件里面。

xcframework与framework的对比

为什么我们要用.xcframework而不是.framework呢?
首先我们来看看这二者的区别:

创建私有framework工程

我们在组件工程里面再创建一个工程,选择Framework选项,并且把其添加到组件的xcworkspace工作空间里。
配置工程,在General里取消掉对Mac的支持,并调整支持的iOS系统版本

修改Podfile文件

默认的Podfile文件是不支持多项目的,需要我们修改里面的内容。

project路径是一个相对路径,以Podfile文件所在的目录为根目录;一般来说,Podfile文件就在主工程那里,别的工程就以主工程做相对路径


以下为Podfile文件示例:

#use_frameworks! # 全局配,也可以每个项目单独配

platform :ios, '10.0'

# 工作空间名称
workspace 'ZTTools_Swift.xcworkspace' # 同一个工作空间,多个Project使用pod时,需要添加工作空间名称

# 主工程(带podfile的工程)
target 'ZTTools_Swift_Example' do # target的名字
  use_frameworks! # 项目单独配

  project 'ZTTools_Swift.xcodeproj' # 指明target的工程路径;使用相对路径,相对于Podfile文件

  pod 'ZTTools_Swift', :path => '../' # 组件的pod名
end

# 同一个工作空间里面别的项目依赖
target 'ZTTools' do

  use_frameworks! # 项目单独配
  project '../ZTTools/ZTTools.xcodeproj'

  pod 'Alamofire'
  pod 'SnapKit'
end

如果遇到pod报错,可尝试使用sudo gem install cocoapods更新pods解决

创建自动化脚本

我们选中SDK项目,点击File-New-Target,选中Other,然后选择Aggregate,命名为SDKBuildScript,点击完成。

旧版本的Xcode里,Aggregate是在Cross-platform里。

点击File-New-File,选择Shell Script,命名为SDKBuild,点击创建(不要把它添加到Targets,不然会被编译到Framework里的)。

把这段脚本复制到SDKBuild中,然后根据注释修改为你自己的。
完成脚本编写后,可以把Xcode里的SDKBuild文件删了(但不要移除到废纸篓

CONFIG="${CONFIGURATION}" # "Release" "${CONFIGURATION}" "Debug" 编译模式,使用Release即可
SCHEME_NAME="${PROJECT_NAME}" # 要build的scheme名,如果和scheme名不一致,需要修改为正确的scheme名
OUTPUT_SDK="${SCHEME_NAME}" # 产物名字
OUTPUT_SDKNAME="${OUTPUT_SDK}.framework"

# 项目里存放Framework的路径
TARGET_FOLDER="${SRCROOT}/../ZTTools_Swift/Classes"

# 工作空间路径
WORK_FOLDER="${SRCROOT}/../Example/ZTTools_Swift.xcworkspace"

# ---------- 以上配置是可以修改的,下面的配置则不需要改 ----------

# 编译时存放xcarchive的路径
SIMULATOR_ARCHIVE_PATH="${SRCROOT}/build/${OUTPUT_SDK}-iphonesimulator.xcarchive"
DEVICE_ARCHIVE_PATH="${SRCROOT}/build/${OUTPUT_SDK}-iphoneos.xcarchive"

# 编译时存放framework的路径
SIMULATOR_DIR_PATH="${SIMULATOR_ARCHIVE_PATH}/Products/Library/Frameworks/${OUTPUT_SDKNAME}"
DEVICE_DIR_PATH="${DEVICE_ARCHIVE_PATH}/Products/Library/Frameworks/${OUTPUT_SDKNAME}"

function removeBuild()
{
    if [ -d "${SRCROOT}/build" ]
    then
    rm -rf "${SRCROOT}/build/"
    fi
}

function removeBuildFile()
{
    for FILE in $(ls "${1}"|tr " " "?")
    do
    if [[ "${FILE}" =~ ".xcconfig" ]]
    then
    rm -f "${1}/${FILE}"
    fi
    done
}

removeBuild
rm -rf "${TARGET_FOLDER}/${OUTPUT_SDK}.xcframework"

# 分别clean模拟器和真机
xcodebuild clean -workspace "${WORK_FOLDER}" -scheme "${SCHEME_NAME}" -configuration "${CONFIG}" -derivedDataPath "./build" -archivePath "${DEVICE_ARCHIVE_PATH}" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES -sdk iphoneos
xcodebuild clean -workspace "${WORK_FOLDER}" -scheme "${SCHEME_NAME}" -configuration "${CONFIG}" -derivedDataPath "./build" -archivePath "${SIMULATOR_ARCHIVE_PATH}" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES -sdk iphonesimulator

# 编译真机的Framework
xcodebuild archive -workspace "${WORK_FOLDER}" -scheme "${SCHEME_NAME}" -configuration "${CONFIG}" -derivedDataPath "./build" -archivePath "${DEVICE_ARCHIVE_PATH}" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES -sdk iphoneos

# 编译模拟器的Framework
xcodebuild archive -workspace "${WORK_FOLDER}" -scheme "${SCHEME_NAME}" -configuration "${CONFIG}" -derivedDataPath "./build" -archivePath "${SIMULATOR_ARCHIVE_PATH}" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES -sdk iphonesimulator

removeBuildFile "${DEVICE_DIR_PATH}"
removeBuildFile "${SIMULATOR_DIR_PATH}"
    
# 合并framework,创建xcframework
xcodebuild -create-xcframework \
-framework "${SIMULATOR_DIR_PATH}" \
-framework "${DEVICE_DIR_PATH}" \
-output "${TARGET_FOLDER}/${OUTPUT_SDK}.xcframework"

open "${TARGET_FOLDER}" # 打开文件夹

removeBuild

点击SDK项目,然后在TARGETS里选中SDKBuildScript,上面选中Build Phases,点击左上角的“+”号,选择New Run Script Phase
在黑框里输入./SDKBuild.sh

  • 当然你也可以直接把脚本写在黑框里,这样子就不需要创建脚本文件了
    如果使用脚本文件的话,会报没权限的错误,所以需要使用命令行来打开权限(因为使用文件方便管理和编写代码,所以这里我选择了使用文件的方式):
    打开命令行,cd到SDKBuild.sh所在的目录,然后执行sudo chmod +x SDKBuild.sh即可解决权限问题
  • 在执行脚本前,需要配置好.podspec文件
  • 第一次运行脚本,编译好库后,需要自行执行一次pod install为demo工程安装该SDK。此后就不需要再执行该命令了,因为脚本会把新打包好的SDK替换掉旧的SDK,如果配置有变,还是需要用pod命令进行更新
  • 更多SDK开发知识请看这篇文章:iOS】使用workspace搭建SDK开发框架

配置SDK工程

如果工程报错no such module 'XXX',并且pods工程下的Products文件夹里的产物全是红的,说明了没生成对应的库。解决方法为:点击Pods工程,在PROJECTBuild Settings里,找到Build Active Architecture Only设置为NOBase SDK设置为iOS;每次pod install后可能会被重置

git管理

创建组件的时候,已经默认创建了git,但是,这个git是组件的,现在得把SDK的git和组件的git进行分开,使得SDK的git作为组件git的子模块进行管理。

创建远程私有库

因为SDK本身是没有git的,所以需要用git init命令给它创建一个本地git仓库。
创建好SDK工程的git后,需要编辑.gitignore文件,内容如下:

*~
.DS_Store
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
DerivedData/
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/
## Other
*.moved-aside
*.xcbkptlist
*.xccheckout
*.xcscmblueprint
## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
# Code Injection
#
# After new code Injection tools there's a generated folder /iOSInjectionProject
# https://github.com/johnno1962/injectionforxcode
iOSInjectionProject/

然后再编辑组件的.gitignore文件,同样是上面的内容。
随后创建2个远程仓库,并把它们和本地git仓库关联起来。
需要注意的是,远程仓库里,SDK的是私有的,pod组件可以是公开的。(因为代码都在SDK里,所以公开pod组件库也不会有什么问题,而且使用起来也更方便

子模块管理

我们为组件工程git添加子模块,这个时候的git得是主模块的git,即使用组件的git来执行添加命令。
添加子模块的命令为git submodule add <url> <path>,其中url可以是远程地址和本地地址,本地地址要用绝对对路径,path则是该子模块存储的目录路径(使用相对路径)。

  • 添加模块之前,组件和SDK的git都需要先提交到远程
  • 如果提交子模块提示The following paths are ignored by one of your .gitignore files,则用git submodule add -f来添加

配置pod的索引文件

项目名.podspec文件(我这里是ZTTools_Swift.podspec),这个文件是用来描述这个pod的说明信息的。当pod install安装库时,只会引入你在.podspec中配置的那些文件。

Pod::Spec.new do |s|
  s.name             = '组件名'
  s.version          = '版本号'
  s.summary          = '组件精简描述'

  s.description      = <<-DESC
组件详细描述
                       DESC

  s.homepage         = '组件主页'
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  s.author           = { '用户名' => '邮箱' }
  s.source           = { :git => 'git地址', :tag => s.version.to_s }
  
  # 需要设置,不然项目引入库后会崩溃
  s.pod_target_xcconfig = {
  'BUILD_LIBRARY_FOR_DISTRIBUTION' => 'YES'
 }
  s.user_target_xcconfig = { 'BUILD_LIBRARY_FOR_DISTRIBUTION' => 'YES' }

  s.ios.deployment_target = '12.0' # 最低系统版本
  s.swift_versions = ['5.0'] # Swift版本
  s.vendored_frameworks = 'ZTTools_Swift/Classes/ZTToolsSDK.xcframework' # 使用私有库
  s.frameworks = 'UIKit', 'Foundation', 'Photos', 'UserNotifications', 'AVFoundation', 'CoreGraphics'
  s.dependency 'Alamofire' # 依赖库
  s.dependency 'SnapKit'

end

如果集成组件后,项目运行报One of the two will be used. Which one is undefined.,说明是符号冲突了,这个是pod的问题。实际上是因为你的组件包含了第三方pod,然后使用组件的工程也包含了这个第三方pod导致的,不喜欢这个提示是话,可以在使用组件的工程里,找到Pods文件夹,在该文件夹下所有的Pods-项目名.debug.xcconfigPods-项目名.release.xcconfig文件,找到文件里面的OTHER_LDFLAGS,把有提示重复的-l"第三方pod名"删除即可

发布组件

校验文件合法性

在发布之前,需要先转到组件所在的文件夹,使用命令校验.podspec文件。(可能需要翻墙
pod lib lint是基础校验命令,用来校验本地.podspec文件的,如果要校验远程,把lib改为spec即可。(spec会同时验证本地和远程是否通过

  • 提示passed validation即为校验通过
  • 提示[!] The spec did not pass validation即为校验失败
  • 只有校验通过了,才能进行下一步操作
  • 一般来说,只需要校验本地即可

发布

需要先转到组件所在的文件夹,使用命令pod trunk me查看是否注册trunk。
如果提示[!] Authentication token is invalid or unverified. Either verify it with the email that was sent or register a new session.说明还没注册过trunk或者登录已经过期了,需要执行pod trunk register 邮箱 '名字' --description='描述文本' --verbose。(后面2个参数是可选的

如果输出名字、邮箱和注册时间等信息,说明已经是注册并是登录状态。这个时候就可以提交组件到pod了。

使用命令pod trunk push xxx.podspec发布组件到pod,同样的可以加上--allow-warnings--verbose参数;如果要跳过验证pod是否导入,还可以加上--skip-import-validation参数。

  • 发布之前请先打上tag,不然会发布失败
  • tag必须和.podspec文件的s.version一致
  • 如果之前打了tag并发布了,更新了文件后请用新的tag,不然不生效(也就是说,你修了一个小bug,想同一个版本号,把本地和远程的tag删了,再打上同样的tag并推上远程,这种方法是不可行的
  • 提交成功后,并不一定能马上搜索到,需要等待一天左右

更新组件

如果提示[!] You need to register a session first.,说明需要验证会话。使用pod trunk register "你之前注册的邮箱"后,去邮箱点击链接验证即可

其他



欢迎来群139322447玩耍

上一篇下一篇

猜你喜欢

热点阅读