xcode 8 /iOS10下靜態庫和動態庫的區別 && framework的製做

這裏輸入引用文本本文記錄一下,在SDK開發完成後,如何高效率製做framework。swift

##iOS關於靜態庫、動態庫的一些基本概念和理解誤區 ###1. 庫 庫是源代碼通過編譯,造成的二進制代碼,別人項目中使用咱們的庫的時候,庫在參與編譯的時候,直接link就OK了,按照link的方式,能夠把庫分爲靜態庫動態庫 ###2. 靜態庫 靜態庫在編譯的時候會被直接拷貝一份,複製到目標程序裏,這段代碼在目標程序裏就不會再改變了。xcode

通常以**.a** 和 .framework爲文件後綴名安全

這種作法是犧牲應用「體量」來節省編譯時間。 ###3. 動態庫 與靜態庫相反,動態庫在編譯時並不會被拷貝到目標程序中,目標程序中只會存儲指向動態庫的引用。等到程序運行時,動態庫纔會被真正加載進來。app

動態庫的優勢是,不須要拷貝到目標程序中,不會影響目標程序的體積,並且同一份庫能夠被多個程序使用(由於這個緣由,動態庫也被稱做共享庫)。框架

同時,編譯時才載入的特性,也可讓咱們隨時對庫進行替換,而不須要從新編譯代碼。動態庫帶來的問題主要是,動態載入會帶來一部分性能損失,使用動態庫也會使得程序依賴於外部環境。若是環境缺乏動態庫或者庫的版本不正確,就會致使程序沒法運行iphone

以**.tbd**(以前叫.dylib) 和** .framework** 爲文件後綴名工具

蘋果系統爲咱們提供了不少動態連接庫,咱們能夠在咱們項目工程中查看一下性能

輸入圖片說明 輸入圖片說明 ###4. Framework Framework 是一種打包方式,將庫的二進制文件,頭文件和有關的資源文件打包到一塊兒,方便管理和分發。測試

Framework只是一種打包方式,其自己和靜態、動態無關!ui

Cocoa Touch Framework 的實際內容爲 Header + 動態連接庫 + 資源文件

###5. 對Framework認識的誤區 誤區①:.framework是動態庫,.a是靜態庫,前面已經講過,再也不贅述

誤區②:有人說「自定義的動態庫蘋果審覈不經過」,那我打的framework是否是通不過審覈?

任何沒有時間前提的結論都是耍流氓!!!

在 **iOS 8 / iOS6以前,**iOS 平臺不支持使用動態 Framework,開發者可使用的 Framework 只有系統的framework,這種限制多是出於安全的考慮

換一個角度講,由於 iOS 應用都是運行在沙盒當中,不一樣的程序之間不能共享代碼,同時動態下載代碼又是被蘋果明令禁止的,沒辦法發揮出動態庫的優點,實際上動態庫也就沒有存在的必要了

可是,碼農老是喜歡折騰的,一方面骨子裏面有一種「你不讓我作我偏要作的倔強」,另外一方面用framework確實比用.a加頭文件的方式簡單,因此這一時期的開發者用了不少**「奇淫技巧」來製做framework**,這就有了Fake Framework 和 Real Framework的區分

華麗的分割線------

輸入圖片說明

在 **iOS 8 / iOS6後,iOS平臺添加了動態庫的支持,同時, Xcode 6 也原生自帶了 Framework 支持,注意,先後兩個維度的不一樣是兩件事,不要混淆。。。

那麼,爲何 iOS 8 要添加動態庫的支持?

主要的理由大概就是 Extension 的出現。Extension 和 App 是兩個分開的可執行文件,同時須要共享代碼,這種狀況下動態庫的支持就是必不可少的了。可是這種動態 Framework 和系統的 UIKit.Framework 仍是有很大區別;還有就是爲了支持swift

雖然一樣是動態框架,可是和系統 framework 不一樣,app 中的使用的 Cocoa Touch Framework 在打包和提交 app 時會被放到 app bundle 中(App 和 Extension 的 Bundle 是共享的),運行在沙盒裏,而不是系統中。也就是說,不一樣的 app 就算使用了一樣的 framework,但仍是會有多份的框架被分別簽名,打包和加載,所以蘋果又把這種 Framework 稱爲** Embedded Framework**,也正是代碼簽名機制,經過AppStore發佈的APP是沒法經過替換服務端下發framework的方式來進行熱更新!

##項目遇到的痛點 項目組原本是使用腳本結合xctool(Facebook的一個開源項目)的方式來打包製做framework,但在升級xcode8以後,xctool在xcode8下出現了bug,並且Facebook並無在第一時間維護這個項目,一時間一臉懵逼。。。

因爲項目時間緊,無奈之下只能採用了一個臨時解決方案,就是從新下載一個xcode7版本,讓xctool在xcode7環境下打包,但這絕非長久之計!

大概一個月以後,雖然xctool項目更新了對 xcode8 以及 xcode8.1 的支持,但仍是決定放棄原有的方案,緣由有二,首先,Facebook有着很好的開源精神,可是也是出了名的喜歡撒手無論的角兒,萬一哪天中止對這個工具的維護,我怎麼辦!!!用一種簡單、穩定、可靠的解決方案是咱們急需的;第二,xctool有很強大的功能,但咱們在項目中只用了其中一小塊,有點殺雞用牛刀的意思,項目中不少冗餘。 ##解決方案 替代方案就是用xcode提供的aggregate結合腳原本製做framework ##製做過程 ###1. 用workspace管理SDK project 新建一個workspace,命名爲TestSDKWorkspace 輸入圖片說明

如今生成的workspace仍是一個空的什麼都沒有,接着往裏面添加咱們的靜態庫project

點擊左下角的**+**號

輸入圖片說明

project類型選擇cocoa touch framework,取名爲TeskSDK 輸入圖片說明

在SDK項目中添加測試源代碼,寫一個Test類,對外提供testMethod方法,注意,這個類要添加到SDK target中去!

#import <Foundation/Foundation.h>
@interface Test : NSObject
- (void)testMethod;
@end

#import "Test.h"
@implementation Test
- (void)testMethod{
    NSLog(@"--------");
    NSLog(@"this is a test method");
    NSLog(@"--------");
}
@end

咱們決定對外暴露Test.h,將其添加至接口文件中

輸入圖片說明

此時,咱們編碼準備工做已經作好了,command+B,咱們能夠在product文件夾下面看到有一個TestSDK.framework從紅變黑,這是否是意味着咱們須要的framework已經大功告成了呢?

no!!!咱們此時只是在特定平臺下編譯的,獲得的也只是這個平臺下的framework,咱們在文件夾中查看以下圖

輸入圖片說明

這就意味着咱們要打同平臺的包,須要通過屢次編譯,最後再去合成,這太麻煩了 ###2. 用「Aggregate+腳本」製做framework 選擇TARGETS點擊而後添加Aggregate

輸入圖片說明

添加以下腳本到Aggregate target對應的build phases-->run script中

#!/bin/sh
#要build的target名
TARGET_NAME=${PROJECT_NAME}
if [[ $1 ]]
then
TARGET_NAME=$1
fi
UNIVERSAL_OUTPUT_FOLDER="${SRCROOT}/${PROJECT_NAME}_Products/"

#建立輸出目錄,並刪除以前的framework文件
mkdir -p "${UNIVERSAL_OUTPUT_FOLDER}"
rm -rf "${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework"

#分別編譯模擬器和真機的Framework
xcodebuild -target "${TARGET_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${TARGET_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build

#拷貝framework到univer目錄
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework" "${UNIVERSAL_OUTPUT_FOLDER}"

#合併framework,輸出最終的framework到build目錄
lipo -create -output "${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework/${TARGET_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/${TARGET_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET_NAME}.framework/${TARGET_NAME}"

#刪除編譯以後生成的無關的配置文件
dir_path="${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework/"
for file in ls $dir_path
do
if [[ ${file} =~ ".xcconfig" ]]
then
rm -f "${dir_path}/${file}"
fi
done
#判斷build文件夾是否存在,存在則刪除
if [ -d "${SRCROOT}/build" ]
then
rm -rf "${SRCROOT}/build"
fi
rm -rf "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator" "${BUILD_DIR}/${CONFIGURATION}-iphoneos"
#打開合併後的文件夾
open "${UNIVERSAL_OUTPUT_FOLDER}"

輸入圖片說明 ###3. 生成framework 在target中選擇TestAggregate,build device選擇Generic Device,而後 command + B 輸入圖片說明

因爲腳本末尾添加了open命令,編譯結束以後會打開framework所在的文件夾

至此,SDK生成完畢,咱們須要寫個demo工程驗證一把 ###4. 驗證framework 在workspace中新建一個demo工程,而後把TestSDK.framework引入

輸入圖片說明

在viewController中調用SDK方法

輸入圖片說明

從控制檯的輸出能夠看出,咱們已經成功的調起TestSDK中的方法。

個人另一篇文章解決引用百度地圖sdk衝突問題,其中介紹瞭如何查看framework的內部結構,你能夠用裏面的方法來查看咱們打出來的framework是不是通平臺的包 ##總結

  1. 開發是一個不斷踩坑和填坑的過程,製做framework在iOS開發中是一個比較小衆的需求,我會持續的把我遇到的蛋疼的事兒記錄下來,以供來着參考,有更好的方法也歡迎討論
  2. 在SDK製做過程當中用workspace的方法管理project是一個頗有效率的方法,這是咱們團隊的adams總結使用的,經過這種方法能夠源碼project和demo project放在一塊兒,能夠同時在一個地方搞定兩件事:SDK開發和framework集成
  3. 學會製做framework僅僅是萬里長征第一步,framework給到第三方集成過程當中會遇到各類麻煩,這就須要不斷的總結和沉澱
  4. 本文目前爲止製做的是動態的framework,若是你的需求是作一個靜態的framework,變化很簡單,你只須要改變building settings -- > Mach-o type爲static便可
  5. 默認的iOS develop target是當前最新版本的,你的framework須要兼容低版本的話就須要在build settings --> development --> iOS develop target中設置你的目標版本
相關文章
相關標籤/搜索