【Objective-c】開發封裝動態庫framework 裝B神技

開發中我們也經常會使用第三方SDK,只要幾行代碼就實現功能,重點是你看不到代碼是怎么實現的,頓時感覺這個逼格很高,大牛一位。(面試中甚至有面試官問:你會不會封裝SDK?當時心中忐忑不安,心想什么鬼,面試的是多少K的工作,居然要會SDK)

普及一下靜態庫和動態庫的定義及區別

靜態庫即靜態鏈接庫(Windows 下的 .lib,Linux 和 Mac 下的 .a)。之所以叫做靜態,是因為靜態庫在編譯的時候會被直接拷貝一份,復制到目標程序里,這段代碼在目標程序里就不會再改變了。靜態庫的好處很明顯,編譯完成之后,庫文件實際上就沒有作用了。目標程序沒有外部依賴,直接就可以運行。當然其缺點也很明顯,就是會使用目標程序的體積增大。

動態庫動態庫即動態鏈接庫(Windows 下的 .dll,Linux 下的 .so,Mac 下的 .dylib)。與靜態庫相反,動態庫在編譯時并不會被拷貝到目標程序中,目標程序中只會存儲指向動態庫的引用。等到程序運行時,動態庫才會被真正加載進來。動態庫的優點是,不需要拷貝到目標程序中,不會影響目標程序的體積,而且同一份庫可以被多個程序使用(因為這個原因,動態庫也被稱作共享庫)。同時,編譯時才載入的特性,也可以讓我們隨時對庫進行替換,而不需要重新編譯代碼。動態庫帶來的問題主要是,動態載入會帶來一部分性能損失,使用動態庫也會使得程序依賴于外部環境。如果環境缺少動態庫或者庫的版本不正確,就會導致程序無法運行(Linux 下喜聞樂見的 lib not found 錯誤)。

創建動態庫framework的步驟》》》》》》見圖

1、新建項目


Snip20161019_1.png

2、將代碼導入到項目中,并將公開的接口暴露


Snip20161019_2.png

注意:開放接口的頭文件,一定要導入這個新建文件的頭文件中,否則其他項目導入framework時會出現:找不到子模塊的警告??
Snip20161019_12.png

3、設置適合所有框架


Snip20161019_3.png

4、因為動態庫打包出來只能是在真機或模擬器使用,為了方便調試,可以添加一個腳本命令,生成一個同時支持真機和模擬機的framework


![Snip20161019_5.png](http://upload-images.jianshu.io/upload_images/1923392-73cdcf4be0b4b5e1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

Snip20161019_6.png

Snip20161019_7.png

腳本命令
set
 -e

set
 +u

### Avoid recursively calling this script.

if
 [[ $UF_MASTER_SCRIPT_RUNNING ]]

then

exit 0

fi

set
 -u

export UF_MASTER_SCRIPT_RUNNING=1

### Constants.

UF_TARGET_NAME=${PROJECT_NAME}

FRAMEWORK_VERSION=
"A"

UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal

IPHONE_DEVICE_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphoneos

IPHONE_SIMULATOR_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphonesimulator

### Functions

## List files in the specified directory, storing to the specified array.

#

# @param $1 The path to list

# @param $2 The name of the array to fill

#

##

list_files ()

{

filelist=$(ls 
"$1"
)

while
 read line

do

eval 
"$2[\${#$2[*]}]=\"\$line\""

done <<< 
"$filelist"

}

### Take build target.

if
 [[ 
"$SDK_NAME"
 =~ ([A-Za-z]+) ]]

then

SF_SDK_PLATFORM=${BASH_REMATCH[1]} # 
"iphoneos"
 or 
"iphonesimulator"
.

else

echo 
"Could not find platform name from SDK_NAME: $SDK_NAME"

exit 1

fi

### Build simulator platform. (i386, x86_64)

echo 
"========== Build Simulator Platform =========="

echo 
"===== Build Simulator Platform: i386 ====="

xcodebuild -project 
"${PROJECT_FILE_PATH}"
 -target 
"${TARGET_NAME}"
 -configuration 
"${CONFIGURATION}"
 -sdk iphonesimulator BUILD_DIR=
"${BUILD_DIR}"
 OBJROOT=
"${OBJROOT}"
 BUILD_ROOT=
"${BUILD_ROOT}"
 CONFIGURATION_BUILD_DIR=
"${IPHONE_SIMULATOR_BUILD_DIR}/i386"
 SYMROOT=
"${SYMROOT}"
 ARCHS=
'i386'
 VALID_ARCHS=
'i386'
 $ACTION

echo 
"===== Build Simulator Platform: x86_64 ====="

xcodebuild -project 
"${PROJECT_FILE_PATH}"
 -target 
"${TARGET_NAME}"
 -configuration 
"${CONFIGURATION}"
 -sdk iphonesimulator BUILD_DIR=
"${BUILD_DIR}"
 OBJROOT=
"${OBJROOT}"
 BUILD_ROOT=
"${BUILD_ROOT}"
 CONFIGURATION_BUILD_DIR=
"${IPHONE_SIMULATOR_BUILD_DIR}/x86_64"
 SYMROOT=
"${SYMROOT}"
 ARCHS=
'x86_64'
 VALID_ARCHS=
'x86_64'
 $ACTION

### Build device platform. (armv7, arm64)

echo 
"========== Build Device Platform =========="

echo 
"===== Build Device Platform: armv7 ====="

xcodebuild -project 
"${PROJECT_FILE_PATH}"
 -target 
"${TARGET_NAME}"
 -configuration 
"${CONFIGURATION}"
 -sdk iphoneos BUILD_DIR=
"${BUILD_DIR}"
 OBJROOT=
"${OBJROOT}"
 BUILD_ROOT=
"${BUILD_ROOT}"
  CONFIGURATION_BUILD_DIR=
"${IPHONE_DEVICE_BUILD_DIR}/armv7"
 SYMROOT=
"${SYMROOT}"
 ARCHS=
'armv7 armv7s'
 VALID_ARCHS=
'armv7 armv7s'
 $ACTION

echo 
"===== Build Device Platform: arm64 ====="

xcodebuild -project 
"${PROJECT_FILE_PATH}"
 -target 
"${TARGET_NAME}"
 -configuration 
"${CONFIGURATION}"
 -sdk iphoneos BUILD_DIR=
"${BUILD_DIR}"
 OBJROOT=
"${OBJROOT}"
 BUILD_ROOT=
"${BUILD_ROOT}"
 CONFIGURATION_BUILD_DIR=
"${IPHONE_DEVICE_BUILD_DIR}/arm64"
 SYMROOT=
"${SYMROOT}"
 ARCHS=
'arm64'
 VALID_ARCHS=
'arm64'
 $ACTION

### Build device platform. (arm64, armv7)

echo 
"========== Build Universal Platform =========="

## Copy the framework structure to the universal folder (clean it first).

rm -rf 
"${UNIVERSAL_OUTPUTFOLDER}"

mkdir -p 
"${UNIVERSAL_OUTPUTFOLDER}"

## Copy the last product files of xcodebuild command.

cp -R 
"${IPHONE_DEVICE_BUILD_DIR}/arm64/${PROJECT_NAME}.framework"
 "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework"

### Smash them together to combine all architectures.

lipo -create  
"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/i386/${PROJECT_NAME}.framework/${PROJECT_NAME}"
 "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/x86_64/${PROJECT_NAME}.framework/${PROJECT_NAME}"
 "${BUILD_DIR}/${CONFIGURATION}-iphoneos/armv7/${PROJECT_NAME}.framework/${PROJECT_NAME}"
 "${BUILD_DIR}/${CONFIGURATION}-iphoneos/arm64/${PROJECT_NAME}.framework/${PROJECT_NAME}"
 -output 
"${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}"

### Create standard structure for framework.

#

# If we don't have "Info.plist -> Versions/Current/Resources/Info.plist", we may get error when use this framework.

#

# MyFramework.framework

# |-- MyFramework -> Versions/Current/MyFramework

# |-- Headers -> Versions/Current/Headers

# |-- Resources -> Versions/Current/Resources

# |-- Info.plist -> Versions/Current/Resources/Info.plist

# `-- Versions

#     |-- A

#     |   |-- MyFramework

#     |   |-- Headers

#     |   |   `-- MyFramework.h

#     |   `-- Resources

#     |       |-- Info.plist

#     |       |-- MyViewController.nib

#     |       `-- en.lproj

#     |           `-- InfoPlist.strings

#     `-- Current -> A

#

echo 
"========== Create Standard Structure =========="

mkdir -p 
"${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Versions/${FRAMEWORK_VERSION}/"

mv 
"${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}"
 "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Versions/${FRAMEWORK_VERSION}/"

mv 
"${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Headers"
 "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Versions/${FRAMEWORK_VERSION}/"

mkdir -p 
"${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Resources"

declare -a UF_FILE_LIST

list_files 
"${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/"
 UF_FILE_LIST

for
 file_name 
in
 "${UF_FILE_LIST[@]}"

do

if
 [[ 
"${file_name}"
 == 
"Info.plist"
 ]] || [[ 
"${file_name}"
 =~ .*\.lproj$ ]]

then

mv 
"${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${file_name}"
 "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Resources/"

fi

done

mv 
"${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Resources"
 "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Versions/${FRAMEWORK_VERSION}/"

ln -sfh 
"Versions/Current/Resources/Info.plist"
 "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Info.plist"

ln -sfh 
"${FRAMEWORK_VERSION}"
 "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Versions/Current"

ln -sfh 
"Versions/Current/${PROJECT_NAME}"
 "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}"

ln -sfh 
"Versions/Current/Headers"
 "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Headers"

ln -sfh 
"Versions/Current/Resources"
 "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Resources"

### Open the universal folder.

open 
"${UNIVERSAL_OUTPUTFOLDER}"

5、生成framework文件,選中“StyleBox”文件,運行程序


Snip20161019_9.png

Snip20161019_11.png

到這里,framework的創建已經成功了,只要右擊“show in Finder”,就可以找得framework并導入其他項目中

Paste_Image.png

項目實際使用中,直接導入framework,并且需要動態庫需要在此添加:


Snip20161019_14.png

當動態庫中,包含資源文件如nib文件或圖片的....


Snip20161019_13.png

以上是創建framework的基本流程

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容