引言
SDK定義上是指軟件開發(fā)包,對(duì)應(yīng)iOS端來說就包含了庫(kù)文件、頭文件、資源文件等文件的集合。SDK開發(fā)就是在保證sdk源代碼安全的情況,給開發(fā)者一個(gè)可方便快速接入的,兼容多個(gè)iOS系統(tǒng)、便于真機(jī)模擬器調(diào)試、可以上線AppStore的庫(kù)。這句話包含的幾個(gè)重要的信息將在本文中逐步詳解。
Step1:設(shè)置building setting(選static或者dynamic)

Step2: 接口設(shè)計(jì)
- 接口命名的正確方式:createGroupWithTitle:(NSString *)title
包含:action(create)+parameters(title)
需要對(duì)參數(shù)類型進(jìn)行校驗(yàn):最好的錯(cuò)誤回調(diào)應(yīng)該是至少包含錯(cuò)誤碼,最好包含錯(cuò)誤描述(中英文兩種),如下面例子:(實(shí)例中包含錯(cuò)誤碼和錯(cuò)誤簡(jiǎn)單描述、詳細(xì)描述。)
-(void)requestGroupMasterViaGroupId:(NSString *)groupId
requestSucess:(RequestGroupMasterSucess)success
requestError:(RequestGroupMasterError) error;
typedef void (^RequestGroupMasterError) (CMIMError * error);//獲取群主詳情失敗回調(diào)
//回調(diào)的參數(shù)是一個(gè)CMIMError實(shí)例:
@interface CMIMError : NSObject
@property (nonatomic, assign) CMIMErrorCode code;
@property (nonatomic, readwrite, copy) NSString *codeDescription;
@property (nonatomic, readwrite, copy) NSString *detailDescription;
+ (instancetype)errorWithCode:(CMIMErrorCode)aCode;
- (instancetype)initWithCode:(CMIMErrorCode)aCode;
category、第三方庫(kù)、類的命名、宏定義命名需要獨(dú)一無二
頭文件、屬性暴露合理
保證代碼安全就是保證頭文件暴露合理,并且頭文件中只暴露開發(fā)者需要用到的屬性(定義好readonly屬性)和接口,這樣可以保證開發(fā)者不會(huì)錯(cuò)誤調(diào)用其他接口或?qū)傩允筍DK內(nèi)部狀態(tài)或邏輯錯(cuò)亂。支持的最低系統(tǒng)
通過app可能根據(jù)用戶群體有不同的最低系統(tǒng)支持,例如目前很多app已經(jīng)不再支持ios8以下系統(tǒng),但是SDK作為app的內(nèi)核,需要保證不同客戶的需求都能滿足,所以SDK應(yīng)該盡可能保證支持最低系統(tǒng),一般到iOS6.支持模擬器調(diào)試
為了便于開發(fā)者調(diào)試,需要支持模擬器調(diào)試,所以在打包framework時(shí)需要有x86和i386版本,并通過lipo指令將二者合并到armv7 v7s arm64中去。
步驟:
- 新建一個(gè)framework
- 參數(shù)配置
- Build Settings >> Dead Code Stripping >> 設(shè)置為NO
- Build Settings >> Strip Debug Symbol During Copy >> 全部設(shè)置為NO
- Build Settings >> Strip Style >> 設(shè)置為Non-Global Symbols
- Build Settings >> Link With Standard Libraries >> 設(shè)置為 NO
- Build Settings >> Mach-O Type >> Static Library
- 對(duì)于Mach-O Type:選擇 Static Library 打出來的是靜態(tài)庫(kù)
- 設(shè)置頭文件的屬性(public/project)
- 設(shè)置debug和release的地址
- 編譯
- 復(fù)制合并
實(shí)例
步驟:
新建一個(gè)工程名稱為“ProjectName”,類型為:Cocoa Touch Static Library
刪除與工程名相同的ProjectName.m文件
在ProjectName.h文件中,將所有內(nèi)容刪除,增加:#import < UIKit/UIKit.h>
將UIKit作為依賴庫(kù),加入到工程中(點(diǎn)擊BuildPhases,展開Link Binary with Libraries這一部分,點(diǎn)擊+添加一個(gè)新的framework,找到UIKit.framework,點(diǎn)擊add添加進(jìn)來)
在BuildPhases中,點(diǎn)擊“new Headers Phase”
將公開的頭文件,拖到Public下,將私有的頭文件,拖到projcet下
新建一個(gè)文件夾,命名為:”folder”,將公共的頭文件,放到folder文件夾下
在“Build Setting”中,搜索“public header”,設(shè)置Public Headers Folder Path為:include/$(PROJECT_NAME)/folder
進(jìn)行簡(jiǎn)化設(shè)置(無效代碼和debug用符號(hào))
- Dead Code Stripping設(shè)置為NO
- Strip Debug Symbol During Copy 全部設(shè)置為NO
- Strip Style設(shè)置為Non-Global Symbols
- 編譯運(yùn)行
11.創(chuàng)建framework- Build Phases欄,選擇Editor/Add Build Phase/Add Run Script Build Phase來添加一個(gè)新的腳本
set -e
export FRAMEWORK_LOCN="${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework"
# Create the path to the real Headers dir
mkdir -p "${FRAMEWORK_LOCN}/Versions/A/Headers"
# Create the required symlinks
/bin/ln -sfh A "${FRAMEWORK_LOCN}/Versions/Current"
/bin/ln -sfh Versions/Current/Headers "${FRAMEWORK_LOCN}/Headers"
/bin/ln -sfh "Versions/Current/${PRODUCT_NAME}" \
"${FRAMEWORK_LOCN}/${PRODUCT_NAME}"
# Copy the public headers into the framework
/bin/cp -a "${TARGET_BUILD_DIR}/${PUBLIC_HEADERS_FOLDER_PATH}/" \
"${FRAMEWORK_LOCN}/Versions/A/Headers"
- 選擇靜態(tài)庫(kù),編譯
12 創(chuàng)建Aggregate ,命名為“Framework”
13 將靜態(tài)庫(kù),添加到Aggregate中
14 添加腳本信息
set -e
# If we're already inside this script then die
if [ -n "$RW_MULTIPLATFORM_BUILD_IN_PROGRESS" ]; then
exit 0
fi
export RW_MULTIPLATFORM_BUILD_IN_PROGRESS=1
RW_FRAMEWORK_NAME=${PROJECT_NAME}
RW_INPUT_STATIC_LIB="lib${PROJECT_NAME}.a"
RW_FRAMEWORK_LOCATION="${BUILT_PRODUCTS_DIR}/${RW_FRAMEWORK_NAME}.framework"
function build_static_library {
# Will rebuild the static library as specified
# build_static_library sdk
xcrun xcodebuild -project "${PROJECT_FILE_PATH}" \
-target "${TARGET_NAME}" \
-configuration "${CONFIGURATION}" \
-sdk "${1}" \
ONLY_ACTIVE_ARCH=NO \
BUILD_DIR="${BUILD_DIR}" \
OBJROOT="${OBJROOT}" \
BUILD_ROOT="${BUILD_ROOT}" \
SYMROOT="${SYMROOT}" $ACTION
}
function make_fat_library {
# Will smash 2 static libs together
# make_fat_library in1 in2 out
xcrun lipo -create "${1}" "${2}" -output "${3}"
}
# 1 - Extract the platform (iphoneos/iphonesimulator) from the SDK name
if [[ "$SDK_NAME" =~ ([A-Za-z]+) ]]; then
RW_SDK_PLATFORM=${BASH_REMATCH[1]}
else
echo "Could not find platform name from SDK_NAME: $SDK_NAME"
exit 1
fi
# 2 - Extract the version from the SDK
if [[ "$SDK_NAME" =~ ([0-9]+.*$) ]]; then
RW_SDK_VERSION=${BASH_REMATCH[1]}
else
echo "Could not find sdk version from SDK_NAME: $SDK_NAME"
exit 1
fi
# 3 - Determine the other platform
if [ "$RW_SDK_PLATFORM" == "iphoneos" ]; then
RW_OTHER_PLATFORM=iphonesimulator
else
RW_OTHER_PLATFORM=iphoneos
fi
# 4 - Find the build directory
if [[ "$BUILT_PRODUCTS_DIR" =~ (.*)$RW_SDK_PLATFORM$ ]]; then
RW_OTHER_BUILT_PRODUCTS_DIR="${BASH_REMATCH[1]}${RW_OTHER_PLATFORM}"
else
echo "Could not find other platform build directory."
exit 1
fi
# Build the other platform.
build_static_library "${RW_OTHER_PLATFORM}${RW_SDK_VERSION}"
# If we're currently building for iphonesimulator, then need to rebuild
# to ensure that we get both i386 and x86_64
if [ "$RW_SDK_PLATFORM" == "iphonesimulator" ]; then
build_static_library "${SDK_NAME}"
fi
# Join the 2 static libs into 1 and push into the .framework
make_fat_library "${BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}" \
"${RW_OTHER_BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}" \
"${RW_FRAMEWORK_LOCATION}/Versions/A/${RW_FRAMEWORK_NAME}"
# Ensure that the framework is present in both platform's build directories
cp -a "${RW_FRAMEWORK_LOCATION}/Versions/A/${RW_FRAMEWORK_NAME}" \
"${RW_OTHER_BUILT_PRODUCTS_DIR}/${RW_FRAMEWORK_NAME}.framework/Versions/A/${RW_FRAMEWORK_NAME}"
# Copy the framework to the user's desktop
ditto "${RW_FRAMEWORK_LOCATION}" "${HOME}/Desktop/${RW_FRAMEWORK_NAME}.framework"
15 編譯,桌面上會(huì)生成一個(gè).Framework文件
16 在cmd中檢查Framework文件
- $ cd ~/Desktop/projectName.Framework
- $ xcrun lipo -info projectName