iOS-framework的補充

weixin_34236497發表於2016-07-12

編譯過程:

從C程式碼到可執行檔案經歷的步驟是:原始碼 > 前處理器 > 編譯器 > 彙編器 > 機器碼 > 連結器 > 可執行檔案
在最後一步需要把.o檔案和C語言執行庫連結起來,這時候需要用到ld命令。原始檔經過一系列處理以後,會生成對應的.obj檔案,然後一個專案必然會有許多.obj檔案,並且這些檔案之間會有各種各樣的聯絡,例如函式呼叫。連結器做的事就是把這些目標檔案和所用的一些庫連結在一起形成一個完整的可執行檔案。Other linker flags設定的值實際上就是ld命令執行時後面所加的引數
下面逐個介紹3個常用引數:
-ObjC:加了這個引數後,連結器就會把靜態庫中所有的Objective-C類和分類都載入到最後的可執行檔案中
-all_load:會讓連結器把所有找到的目標檔案都載入到可執行檔案中,但是千萬不要隨便使用這個引數!假如你使用了不止一個靜態庫檔案,然後又使用了這個引數,那麼你很有可能會遇到ld: duplicate symbol錯誤,因為不同的庫檔案裡面可能會有相同的目標檔案,所以建議在遇到-ObjC失效的情況下使用-force_load引數。
-force_load:所做的事情跟-all_load其實是一樣的,但是-force_load需要指定要進行全部載入的庫檔案的路徑,這樣的話,你就只是完全載入了一個庫檔案,不影響其餘庫檔案的按需載入

注意事項

  • namespace 衝突。靜態庫用了某第三方庫,專案也用了同樣的第三方庫,在編譯的時候就會有 duplicate symbol 錯誤,因為有兩份同樣的第三方庫。解決辦法就是把用到的第三方庫加上自定義字首,包括類名、delegate 協議、常量名,尤其需要注意 Category 的方法名要修改。

  • 封裝靜態庫的時候應儘量避免引入重量級第三方庫,多自己進行封裝。

  • 一個靜態庫要有自己獨有的字首,所有類名、常量等都要加同樣的前。

  • 真機+模擬器支援。Xcode 預設只會用當前環境(真機或模擬器)生成靜態庫,這樣的 SDK 不方便其他專案開發時除錯。解決辦法就是通過指令碼生成一份通用庫,build_universal_library.sh,via SO.

  • 文件。靜態庫的方便是使用者直接拿你提供的方法來用,無需關注具體實現;不方便在於看不到實現,出現問題無法排查,因此需要把 SDK 的版本、更新歷史、使用、FAQ 等寫成文件,方便使用,也顯得 SDK 比較正式規範。

  • 圖片等資原始檔用 bundle 方式打包。一個簡單製作 bundle 的方法:新建資料夾,重新命名為 YourSDK.bundle,然後 Show Package Contents 開啟,加入圖片。使用圖片的時候需要指明 bundle: [UIImage imageNamed:@"YourSDK.bundle/img.png"]。也可以用 Target 方式製作 bundle,比如 iOS Library With Resourceshttp://www.galloway.me.uk/tutorials/ios-library-with-resources/.

  • 如果 SDK 有用到 Category,注意專案設定 Other Linker Flags 新增 -ObjC

聚合編譯framework指令

shell /bin/sh
<pre>

FRAMEWORK_NAME="${PROJECT_NAME}"

FRAMEWORK_NAME="IOTMDK"

SIMULATOR_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${FRAMEWORK_NAME}.framework"

DEVICE_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FRAMEWORK_NAME}.framework"

UNIVERSAL_LIBRARY_DIR="${BUILD_DIR}/${CONFIGURATION}-iphoneuniversal"

FRAMEWORK="${UNIVERSAL_LIBRARY_DIR}/${FRAMEWORK_NAME}.framework"

xcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphonesimulator -arch i386 -arch x86_64 -target ${FRAMEWORK_NAME} -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphonesimulator | echo

xcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphoneos -arch arm64 -arch armv7 -arch armv7s -target ${FRAMEWORK_NAME} -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphoneos | echo

rm -rf "${UNIVERSAL_LIBRARY_DIR}"

mkdir "${UNIVERSAL_LIBRARY_DIR}"

mkdir "${FRAMEWORK}"

cp -r "${DEVICE_LIBRARY_PATH}/." "${FRAMEWORK}"

lipo "${SIMULATOR_LIBRARY_PATH}/${FRAMEWORK_NAME}" "${DEVICE_LIBRARY_PATH}/${FRAMEWORK_NAME}" -create -output "${FRAMEWORK}/${FRAMEWORK_NAME}" | echo

open "${UNIVERSAL_LIBRARY_DIR}"
</pre>

參考文章

1.http://fann.im/blog/2014/01/12/ios-static-library/