iOS 制作 framework 動態(tài)庫

指令集

通常會把CPU的擴(kuò)展指令集稱為”CPU的指令集”(因?yàn)榛镜?,類似加減的指令似乎是必須被CPU所支持的指令)。每款CPU在設(shè)計(jì)時就規(guī)定了一系列與其硬件電路相配合的指令集。

arm處理器

Arm處理器,因?yàn)槠涞凸暮托〕叽缍劽瑤缀跛械氖謾C(jī)處理器都基于arm,其在嵌入式系統(tǒng)中的應(yīng)用非常廣泛,它的性能在同等功耗產(chǎn)品中也很出色。想了解ARM指令集的請點(diǎn)擊這里。

iPhone指令集

蘋果A7處理器支持兩個不同的指令集:32位ARM指令集(armv6|armv7|armv7s)和64位ARM指令集(arm64),i386|x86_64 是Mac處理器的指令集,i386是針對intel通用微處理器32架構(gòu)的。x86_64是針對x86架構(gòu)的64位處理器。當(dāng)使用iOS模擬器的時候會遇到i386|x86_64,iOS模擬器沒有arm指令集。

xcode中設(shè)置指令集

主要有以下三個:Architectures、Valid Architectures、Build Active Architecture Only

Architectures

該編譯選項(xiàng)指定了工程將被編譯成支持哪些指令集,支持指令集是通過編譯生成對應(yīng)的二進(jìn)制數(shù)據(jù)包實(shí)現(xiàn)的,如果支持的指令集數(shù)目有多個,就會編譯出包含多個指令集代碼的數(shù)據(jù)包,造成最終編譯的包很大。

Valid Architectures

該編譯項(xiàng)指定可能支持的指令集,該列表和Architectures列表的交集,將是Xcode最終生成二進(jìn)制包所支持的指令集。

比如,Valid Architectures設(shè)置的支持arm指令集版本有:armv7/armv7s/arm64,對應(yīng)的Architectures設(shè)置的支持arm指令集版本有:armv7s,這時Xcode只會生成一個armv7s指令集的二進(jìn)制包。

Build Active Architecture Only

該編譯項(xiàng)用于設(shè)置是否只編譯當(dāng)前使用的設(shè)備對應(yīng)的arm指令集。

當(dāng)該選項(xiàng)設(shè)置成YES時,你連上一個armv7指令集的設(shè)備,就算你的Valid Architectures和Architectures都設(shè)置成armv7/armv7s/arm64,還是依然只會生成一個armv7指令集的二進(jìn)制包。

通常情況下,開發(fā)測試都是在 Debug模式下,所以該編譯選項(xiàng)在Debug模式都設(shè)成YES,這樣在測試時只編譯一份指令集,有效提高開發(fā)效率。

Release模式為發(fā)布模式,需要支持各種設(shè)備指令集,所以設(shè)置為NO。


制作framework

xcode版本: 8.3.2,Mac OS版本:10.12
創(chuàng)建一個新工程,在choose template頁面選擇Cocoa Touch Framework,如下:

choose template.png

在工程中添加或新建類,然后編譯生成framework,下面是選擇不同設(shè)備或模擬器時所生成framework:

1、debug環(huán)境下
    設(shè)備:arm64(測試機(jī)型有限:6P、5、7)
    模擬器:iPhone7-Plus:x86_64、iPhone4s:i386
2、release環(huán)境下
    設(shè)備:armv7、arm64
    模擬器:i386、x86_64

以上所生成的framework均不包含armv7s,在 Building Setting 中設(shè)置一下 Architectures,在原有基礎(chǔ)上添加一行 armv7s ,如下:

Architectures.png

有一點(diǎn)需要注意的是,如果制作 framework 時采用的是 Objective-C,則需要將希望外部使用的.h文件添加到 public 中,如下:

public_header.png

查看生成的framework

右鍵 Products 目錄下的 framework 文件 “show in finder”,會看到 finder 下存在模擬器和真機(jī)生成的 framework,如下:

framework.png

合并framework

制作framework的過程中經(jīng)常會遇到編譯出來的framework只能被真機(jī)使用或者只能被模擬器使用的情況。造成這個問題的原因是由于在編譯時選擇的目標(biāo)設(shè)備不同的情況下編譯出來framework體系結(jié)構(gòu)不同,選擇真機(jī)進(jìn)行編輯時會編譯產(chǎn)生armv7、armv7s、arm64下的庫文件,而選擇模擬器會產(chǎn)生i386、x86_64下的庫文件。但導(dǎo)入過程中時希望支持所有架構(gòu),所以需要將 framework 合并

查看 framework 所支持架構(gòu)

lipo -info frame_name.framework/framework_name

framework 合并命令:

-create后為要合并在一起的兩個framework,-output后面為合并后的framework名稱及路徑

lipo –create /Debug-iphoneos/Someframework.framwork/Someframework Debug-iphonesimulator/Someframework.framwork/Someframework –output Someframework

合并命令只是合并 framework 下的可執(zhí)行文件,因此需要用合并后的 exec 文件替換真機(jī)或模擬器 framework 中的 exec 文件。

framework合并腳本:

在xcode中添加腳本后會自動將生成的模擬器與設(shè)備的framework合并,比使用合并命令手動合并更簡單,添加步驟如下:

在 Build Phases 中點(diǎn)擊左上角 + ,選擇 New Run Script Phase 添加一項(xiàng)

New Run Script Phase.png

會在頁面底部添加一項(xiàng) Run Script ,如下:

Run Script.png

將下面的腳本代碼粘貼至提示“Type a script or drag…”輸入框內(nèi)

if [ "${ACTION}" = "build" ]
then
INSTALL_DIR=${SRCROOT}/Products/${PROJECT_NAME}.framework
DEVICE_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework
SIMULATOR_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
#ditto "${DEVICE_DIR}/Headers" "${INSTALL_DIR}/Headers"
lipo -create "${DEVICE_DIR}/${PROJECT_NAME}" "${SIMULATOR_DIR}/${PROJECT_NAME}" -output "${INSTALL_DIR}/${PROJECT_NAME}"
open "${DEVICE_DIR}"
open "${SRCROOT}/Products"
fi

測試一下腳本,在release環(huán)境下分別選擇真機(jī)和模擬器運(yùn)行,運(yùn)行成功后會自動打開Finder并定位到工程根目錄下的Products:

Products.png

此時查看Products下的framework所支持的指令集:

TestFrameWork_Architectures.png

動態(tài)庫、靜態(tài)庫與Framework

庫(Library)說白了就是一段編譯好的二進(jìn)制代碼,加上頭文件就可以供別人使用。

什么時候我們會用到庫呢?一種情況是某些代碼需要給別人使用,但是我們不希望別人看到源碼,就需要以庫的形式進(jìn)行封裝,只暴露出頭文件。另外一種情況是,對于某些不會進(jìn)行大的改動的代碼,我們想減少編譯的時間,就可以把它打包成庫,因?yàn)閹焓且呀?jīng)編譯好的二進(jìn)制了,編譯的時候只需要 Link 一下,不會浪費(fèi)編譯時間。

上面提到庫在使用的時候需要 Link,Link 的方式有兩種,靜態(tài)和動態(tài),于是便產(chǎn)生了靜態(tài)庫和動態(tài)庫。

靜態(tài)庫

靜態(tài)庫即靜態(tài)鏈接庫(Windows 下的 .lib,Linux 和 Mac 下的 .a)。之所以叫做靜態(tài),是因?yàn)殪o態(tài)庫在編譯的時候會被直接拷貝一份,復(fù)制到目標(biāo)程序里,這段代碼在目標(biāo)程序里就不會再改變了。

靜態(tài)庫的好處很明顯,編譯完成之后,庫文件實(shí)際上就沒有作用了。目標(biāo)程序沒有外部依賴,直接就可以運(yùn)行。當(dāng)然其缺點(diǎn)也很明顯,就是會使用目標(biāo)程序的體積增大。

動態(tài)庫

動態(tài)庫即動態(tài)鏈接庫(Windows 下的 .dll,Linux 下的 .so,Mac 下的 .dylib/.tbd)。與靜態(tài)庫相反,動態(tài)庫在編譯時并不會被拷貝到目標(biāo)程序中,目標(biāo)程序中只會存儲指向動態(tài)庫的引用。等到程序運(yùn)行時,動態(tài)庫才會被真正加載進(jìn)來。

動態(tài)庫的優(yōu)點(diǎn)是,不需要拷貝到目標(biāo)程序中,不會影響目標(biāo)程序的體積,而且同一份庫可以被多個程序使用(因?yàn)檫@個原因,動態(tài)庫也被稱作共享庫)。同時,編譯時才載入的特性,也可以讓我們隨時對庫進(jìn)行替換,而不需要重新編譯代碼。動態(tài)庫帶來的問題主要是,動態(tài)載入會帶來一部分性能損失,使用動態(tài)庫也會使得程序依賴于外部環(huán)境。如果環(huán)境缺少動態(tài)庫或者庫的版本不正確,就會導(dǎo)致程序無法運(yùn)行(Linux 下喜聞樂見的 lib not found 錯誤)。

iOS Framework

除了上面提到的 .a 和 .dylib/.tbd 之外,Mac OS/iOS 平臺還可以使用 Framework。Framework 實(shí)際上是一種打包方式,將庫的二進(jìn)制文件,頭文件和有關(guān)的資源文件打包到一起,方便管理和分發(fā)。
在 iOS 8 之前,iOS 平臺不支持使用動態(tài) Framework,開發(fā)者可以使用的 Framework 只有蘋果自家的 UIKit.Framework,F(xiàn)oundation.Framework 等。這種限制可能是出于安全的考慮(見這里的討論)。換一個角度講,因?yàn)?iOS 應(yīng)用都是運(yùn)行在沙盒當(dāng)中,不同的程序之間不能共享代碼,同時動態(tài)下載代碼又是被蘋果明令禁止的,沒辦法發(fā)揮出動態(tài)庫的優(yōu)勢,實(shí)際上動態(tài)庫也就沒有存在的必要了。
由于上面提到的限制,開發(fā)者想要在 iOS 平臺共享代碼,唯一的選擇就是打包成靜態(tài)庫 .a 文件,同時附上頭文件(例如微信的SDK)。但是這樣的打包方式不夠方便,使用時也比較麻煩,大家還是希望共享代碼都能能像 Framework 一樣,直接扔到工程里就可以用。于是人們想出了各種奇技淫巧去讓 Xcode Build 出 iOS 可以使用的 Framework,具體做法參考這里這里,這種方法產(chǎn)生的 Framework 還有 “偽”(Fake) Framework 和 “真”(Real) Framework 的區(qū)別。
iOS 8/Xcode 6 推出之后,iOS 平臺添加了動態(tài)庫的支持,同時 Xcode 6 也原生自帶了 Framework 支持(動態(tài)和靜態(tài)都可以),上面提到的的奇技淫巧也就沒有必要了(新的做法參考這里)。為什么 iOS 8 要添加動態(tài)庫的支持?唯一的理由大概就是 Extension 的出現(xiàn)。Extension 和 App 是兩個分開的可執(zhí)行文件,同時需要共享代碼,這種情況下動態(tài)庫的支持就是必不可少的了。但是這種動態(tài) Framework 和系統(tǒng)的 UIKit.Framework 還是有很大區(qū)別。系統(tǒng)的 Framework 不需要拷貝到目標(biāo)程序中,我們自己做出來的 Framework 哪怕是動態(tài)的,最后也還是要拷貝到 App 中(App 和 Extension 的 Bundle 是共享的),因此蘋果又把這種 Framework 稱為 Embedded Framework

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容