@yanzhiwei147
2019-09-17T12:04:24.000000Z
字数 11039
阅读 4501
CocoaPods
tips
SDK
ps:本文以IMSDK为例,基于SDK目录结构规范、cocoapods 0.36.4
开发
ps2:本文成果传送门
ps3:本文阅读储备知识:Cocoapods三种语法
、git操作
、语义化版本
ps4:本文严格限定SDK使用第三方库版本
ps5:本文涉及到git远端操作的均使用HTTP
形式,使用SSH
形式请移步此处完成配置
$ pod repo add sdp_repo http://git.sdp.nd/cocoapods/spec.git
本步骤基于xcode6.1.1
File
->New
->Project
(快捷键⌘
+⇧
+N
)iOS
->Framework & Library
->Cocoa Static Library
,下一步Product Name
中输入IMSDK,完成创建File
->New
->Trarget
OS X
->Framework & Library
->Bundle
,下一步Product Name
中输入IMSDKBundle,完成创建Building Setting
找到Base SDK
,将SDK切换为Latest iOS(iOS8.1)
Building Setting
找到COMBINE_HIDPI_IMAGES
,双击后切换为NO
Info.plist
,注意移除时使用Move To Trash
Building Setting
找到Info.plist
,双击弹出框内移除所有内容Building Phases
里移除所有的Compile Sources
、Link Binary With Libararies
(点击右边的x号)
$ pod init
Vi
、Sublime Text
或者TextMate
):
source 'https://github.com/CocoaPods/Specs.git'
source 'http://git.sdp.nd/cocoapods/spec.git'
# 只能安装在可运行target上(单元测试以及App等),其他比如静态库不需要链接因而决不能安装
pod 'UCSDK', '~> 0.3.1'
source 'https://github.com/CocoaPods/Specs.git'
source 'http://git.sdp.nd/cocoapods/spec.git'
# 注意只能安装可运行的target
target 'IMSDKTests' do
pod 'UCSDK', '~> 0.3.1'
end
$ pod install
静态库的target(此处为IMSDK)没有收到安装依赖的益处,因此我们需要配置一些项目(IMSDK.xcodeproj上的IMSDK必须能不依赖workspace进行编译):
Build Setting
中配置Header Serch Paths
,添加如下:
"$(SRCROOT)/Pods/Headers/Public"
经过上面搜索路径的配置,现在Xcode就能正常找到所有依赖的第三方包的头文件
Build Phases
中配置Copy Files
include
目录下的所有头文件,该步骤可以放缓至发布SDK前进行#import <MUPFoundation/MUPFoundation.h>
使用SDK顶层目录下的build.sh
(内容见附录)进行打包,命令如下:
// 更多功能使用-h进行查看
$ sh build.sh -r IMSDKBundle
打包完毕后会在顶层目录下生成一个output
目录,生成的framework
以及resources
都在该文件夹中。
output
目录结构如下:
├── framework
│ ├── Headers -> Versions/Current/Headers
│ ├── IMSDK -> Versions/Current/IMSDK
│ └── Versions
└── resources
└── IMSDKBundle.bundle
5 directories, 1 file
$ pod spec create IMSDK
IMSDK.podspec
(使用文本编辑器编辑):
s.name = "IMSDK"
s.version = "0.0.1"
s.platform = :ios, "6.0"
s.summary = "IMSDK官方版"
s.author = "IMSDK团队"
s.homepage = "http://git.sdp.nd/cocoapods/imsdk"
s.license = "MIT"
s.source = { :git => "http://git.sdp.nd/cocoapods/imsdk.git", :tag => "#{s.version}" }
s.public_header_files = "#{s.name}.framework/Versions/A/**/*.h"
s.preserve_paths = "*.framework"
s.vendored_frameworks = "#{s.name}.framework"
s.resources = "IMSDKBundle.bundle"
s.dependency "MUPFoundation", "~> 0.3.6"
s.dependency "SmartCan", "~> 0.3.4"
$ pod ipc spec IMSDK.podspec >> IMSDK.podspec.json
IMSDK
项目,权限设置为Public
$ mkdir IMSDK
$ cd IMSDK
$ git init
$ git remote add origin http://git.sdp.nd/cocoapods/imsdk.git
IMSDK.framework
、IMSDKBundle.bundle
、IMSDK.podspec
文件拷贝至该文件夹下,并执行如下命令:
$ touch README.md
$ git add README.md IMSDK.framework IMSDKBundle.bundle IMSDK.podspec
$ git commit -m "提交0.0.1版本发布(二进制库)"
$ git tag -a 0.0.1 -m "tag 0.0.1版本"
// 同步本地branch至远端
$ git push -u origin master
// 把本地库所有tag同步至远端
$ git push --tag
$ pod spec lint --use-libraries --allow-warnings --sources="https://github.com/CocoaPods/Specs.git,http://git.sdp.nd/cocoapods/spec.git" IMSDK.podspec
$ pod repo push sdp_repo IMSDK.podspec --use-libraries --allow-warnings
group
进行同一类repo所有者的物理切分 group
功能来进行大块功能的划分,例如UserCenter作为一个group,内部按照模块划分为UCSDK
与UCSDKDemo
两个repodevelop
分支采用submodule
引入SDK工程开发 podfile
的依赖应是SDK单元测试的超集,不依赖SDK的发布版,而使用工程project形式进行依赖master
分支采用包依赖管理进行开发 podfile
的依赖应是对外发布到specs的形式
#!/bin/sh
SDK_ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
case $SDK_ROOT_DIR in
*\ * )
echo "您的路径中包含空格,像'make install'是不被支持的."
exit 1
;;
esac
###########################################################################
#
# 模拟器支持架构
SIMULATOR_ARCHS="i386 x86_64"
#
# 真机支持架构
IPHONEOS_ARCHS="armv7 armv7s arm64"
#
# 编译使用的SDK
SDK_NAME="iphoneos8.1"
#
# 编译产品路径,指定指定build目录(默认为脚本所在目录下的build)
BUILT_PRODUCTS_DIR="${SDK_ROOT_DIR}/build"
#
# 当前framework版本,一般使用字母递增来表示
FRAMEWORK_VERSION="A"
#
###########################################################################
function show_version() {
echo "version: 1.1"
echo "updated date: 2015-04-20"
}
function show_usage() {
echo "Usage(暂时不支持长选项):\n"
echo "`printf %-16s " $ $0"` argument\n"
echo "Description:"
echo "`printf %-16s ` [-h|--help] 显示帮助信息"
echo "`printf %-16s ` [-v|-V|--version] 显示版本"
echo "`printf %-16s ` [-c|--configuration ... ] 指定编译配置"
echo "`printf %-16s ` [-p|--project ... ] 指定编译工程"
echo "`printf %-16s ` [-P|--frameworkproduct ... ] 指定生成framework产品名"
echo "`printf %-16s ` [-t|--frameworktarget ... ] 指定需要编译framework的target名"
echo "`printf %-16s ` [-r|--resourcetarget ... ] 指定资源编译target名"
}
# Call this when there is an error. This does not return.
function die() {
echo ""
echo "FATAL: $*" >&2
exit 1
}
# 工程名,用以指定需要编译的project
PROJECT_NAME=""
# target名,用以指定需要编译的target,默认与工程名一致
TARGET_NAME=""
# 产品名,用以指定需要编译的target,默认与target名一致
PRODUCT_NAME=""
# 配置,用以指定编译代码的配置
CONFIGURATION=""
# 资源名
RESOURCE_NAME=""
# 编译所有target标识
ALLTARGETS_FLAG=0
# 参数列表
while getopts ":hvVac:p:P:t:r:" OPTNAME
do
case "$OPTNAME" in
"h")
show_usage && exit
;;
"v")
show_version && exit
;;
"V")
show_version && exit
;;
"c")
CONFIGURATION=$OPTARG
;;
"p")
PROJECT_NAME=$OPTARG
;;
"P")
PRODUCT_NAME=$OPTARG
;;
"t")
TARGET_NAME=$OPTARG
;;
"r")
RESOURCE_NAME=$OPTARG
;;
"?")
show_usage && exit
;;
":")
echo "选项$OPTARG缺少输入参数"
die
;;
*)
# Should not occur
echo "处理选项过程发生未知错误"
die
;;
esac
done
XCODEPROJ_SEARCH_RESULT=`find . -name "*.xcodeproj" -d 1`
if [ -n "${XCODEPROJ_SEARCH_RESULT}" ]; then
FILENAME="`basename ${XCODEPROJ_SEARCH_RESULT}`"
XCODEPROJ_NAME="${FILENAME%.*}"
fi
test -n "${CONFIGURATION}" || CONFIGURATION="Release"
test -n "${PROJECT_NAME}" || PROJECT_NAME="${XCODEPROJ_NAME}"
test -n "${TARGET_NAME}" || TARGET_NAME="${PROJECT_NAME}"
test -n "${PRODUCT_NAME}" || PRODUCT_NAME="${TARGET_NAME}"
test -n "${RESOURCE_NAME}" || RESOURCE_NAME=""
# echo "${CONFIGURATION}\n${PROJECT_NAME}\n${PRODUCT_NAME}\n${TARGET_NAME}\n${RESOURCE_NAME}\n"
set -e
set +u
# 避免递归调用
if [[ $SF_MASTER_SCRIPT_RUNNING ]]
then
exit 0
fi
set -u
export SF_MASTER_SCRIPT_RUNNING=1
DEVELOPER=`xcode-select -print-path`
if [ ! -d "$DEVELOPER" ]; then
echo "xcode路径没有被设置正确,$DEVELOPER不存在"
echo "运行"
echo "sudo xcode-select -switch <xcode path>"
echo "来进行默认安装:"
echo "sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer"
exit 1
fi
SDK_IPHONEOS="iphoneos"
SDK_IPHONESIMULATOR="iphonesimulator"
# The following conditionals come from
# https://github.com/kstenerud/iOS-Universal-Framework
if [[ "$SDK_NAME" =~ ([A-Za-z]+) ]]
then
SF_SDK_PLATFORM=${BASH_REMATCH[1]}
else
echo "Could not find platform name from SDK_NAME: $SDK_NAME"
exit 1
fi
if [[ "$SDK_NAME" =~ ([0-9]+.*$) ]]
then
SF_SDK_VERSION=${BASH_REMATCH[1]}
else
echo "Could not find sdk version from SDK_NAME: $SDK_NAME"
exit 1
fi
if [[ "$SF_SDK_PLATFORM" = "iphoneos" ]]
then
SF_OTHER_PLATFORM=iphonesimulator
else
SF_OTHER_PLATFORM=iphoneos
fi
function buildFramework() {
xcodebuild -project ./$PROJECT_NAME.xcodeproj -target $TARGET_NAME -sdk $SDK_IPHONEOS -configuration $CONFIGURATION ARCHS="${IPHONEOS_ARCHS}" build
xcodebuild -project ./$PROJECT_NAME.xcodeproj -target $TARGET_NAME -sdk $SDK_IPHONESIMULATOR -configuration $CONFIGURATION ARCHS="${SIMULATOR_ARCHS}" build
}
function buildBundle() {
xcodebuild -project ./$PROJECT_NAME.xcodeproj -target $RESOURCE_NAME -sdk $SDK_IPHONEOS -configuration $CONFIGURATION ARCHS="${IPHONEOS_ARCHS}" build
}
function copyFramework() {
# prepare_framework
mkdir -p "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Versions/${FRAMEWORK_VERSION}/Headers"
# Link the "Current" version to "${FRAMEWORK_VERSION}"
ln -sfh ${FRAMEWORK_VERSION} "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Versions/Current"
ln -sfh Versions/Current/Headers "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Headers"
ln -sfh "Versions/Current/${PRODUCT_NAME}" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/${PRODUCT_NAME}"
# The -a ensures that the headers maintain the source modification date so that we don't constantly
# cause propagating rebuilds of files that import these headers.
TARGET_BUILD_DIR="${BUILT_PRODUCTS_DIR}/${CONFIGURATION}-${SDK_IPHONEOS}"
cp -a "${TARGET_BUILD_DIR}/include/${PRODUCT_NAME}/" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Versions/${FRAMEWORK_VERSION}/Headers"
# compile_framework
SF_TARGET_NAME=${PROJECT_NAME}
SF_EXECUTABLE_Name="lib${SF_TARGET_NAME}.a"
SF_WRAPPER_NAME="${SF_TARGET_NAME}.framework"
PLATFORM_EXECUTABLE_PATH="${BUILT_PRODUCTS_DIR}/${CONFIGURATION}-${SF_SDK_PLATFORM}/${SF_EXECUTABLE_Name}"
OTHER_PLATFORM_EXECUTABLE_PATH="${BUILT_PRODUCTS_DIR}/${CONFIGURATION}-${SF_OTHER_PLATFORM}/${SF_EXECUTABLE_Name}"
OUTPUT_PATH="${BUILT_PRODUCTS_DIR}/${SF_WRAPPER_NAME}/Versions/${FRAMEWORK_VERSION}/${SF_TARGET_NAME}"
# Smash the two static libraries into one fat binary and store it in the .framework
lipo -create "${PLATFORM_EXECUTABLE_PATH}" "${OTHER_PLATFORM_EXECUTABLE_PATH}" -output "${OUTPUT_PATH}"
# Delete temporary folder if exists
FINAL_OUTPUT_PATH="output/framework/${SF_WRAPPER_NAME}"
if [ -d "${FINAL_OUTPUT_PATH}" ]
mkdir -p "${FINAL_OUTPUT_PATH}"
then
rm -dR "${FINAL_OUTPUT_PATH}"
fi
# Copy the binary to the other architecture folder to have a complete framework in both.
cp -a "${BUILT_PRODUCTS_DIR}/${SF_WRAPPER_NAME}" "${FINAL_OUTPUT_PATH}"
}
function copyBundle() {
# Resources path
RESOURCE_BUILD_PATH="${BUILT_PRODUCTS_DIR}/${CONFIGURATION}-${SF_SDK_PLATFORM}"
# Resources name
RESOURCE_PRODUCT_NAME="${RESOURCE_NAME}.bundle"
# Delete temporary folder if exists
FINAL_RESOURCE_OUTPUT_PATH="output/resources/${RESOURCE_PRODUCT_NAME}"
if [ -d "${FINAL_RESOURCE_OUTPUT_PATH}" ]
mkdir -p "${FINAL_RESOURCE_OUTPUT_PATH}"
then
rm -dR "${FINAL_RESOURCE_OUTPUT_PATH}"
fi
cp -a "${RESOURCE_BUILD_PATH}/${RESOURCE_PRODUCT_NAME}" "${FINAL_RESOURCE_OUTPUT_PATH}"
}
test -z "${PROJECT_NAME}" || (buildFramework && copyFramework)
test -z "${RESOURCE_NAME}" || (buildBundle && copyBundle)
按照我们对git的版本控制的需要,我们写出如下的的.gitignore
:
# Xcode
#
build/
output/
.DS_Store
.svn
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
#
#Pods/
每次使用commit、checkout等冗长的命令想抓狂,可以尝试一下如下的别名设置( ~/.gitconfig),你会有svn的那种简写畅快感:
[alias]
st = status
ci = commit
di = diff
l = log --oneline --decorate -12 --color
ll = log --oneline --decorate --color
lc = log --graph --color
co = checkout
br = branch
rb = rebase
dci = dcommit
sbi = submodule init
sbu = submodule update
sbp = submodule foreach git pull
sbc = submodule foreach git co master
现在一些命令就可以这么用:
// 等同于 git commit -m "我是提交注释"
$ git ci -m "我是提交注释"
// 等同于 git status
$ git st
// 等同于 git diff
$ git di
--verbose
可以输出详细pod命令执行过程--no-repo-update
可以跳过本地pod中央库更新操作pod repo update sdp_repo
后重试