動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)的區(qū)別:Pass。直接進(jìn)入動(dòng)態(tài)庫(kù)制作主題
零、實(shí)驗(yàn)環(huán)境
0.1.接下去內(nèi)容在Xcode Version 8.3.3 (8E3004b)開(kāi)發(fā)工具中完成。
一、基礎(chǔ)準(zhǔn)備
1.1.創(chuàng)建一個(gè)動(dòng)態(tài)庫(kù)MangoSDK,如下圖

1.2.創(chuàng)建一個(gè)測(cè)試工具類(lèi),如下圖

1.3.在MangoSDK.h中#import "MGUtils.h",如下圖

1.4.點(diǎn)擊工程 -> 在targets中選中MangoSDK -> Build Phases -> Headers,如下圖所示,可以看到在動(dòng)態(tài)庫(kù)中創(chuàng)建的文件會(huì)自動(dòng)添加到Build Phases中的project列表中,MangoSDK.h文件是處于Public列表中,所以外部只能看到MangoSDK.h這個(gè)頭文件,由于我們動(dòng)態(tài)庫(kù)外部使用者需要調(diào)用MGUtilis.h中的方法,所以也需要將MGUtils.h拖拽到Public列表中.

二、編譯動(dòng)態(tài)庫(kù)
2.1.選擇動(dòng)態(tài)庫(kù)對(duì)應(yīng)的Scheme,選擇編譯設(shè)備為對(duì)應(yīng)的真機(jī),如下圖

如果沒(méi)有連接真機(jī),也可以,只要選擇Generic iOS Device選項(xiàng)也是可以編譯出對(duì)應(yīng)真機(jī)的動(dòng)態(tài)庫(kù),如下圖

2.2.編譯動(dòng)態(tài)庫(kù)(command + shift + B)后,在Xcode工程中的Products(這個(gè)目錄不是工程源文件目錄,而是編譯后生成對(duì)應(yīng)的沙盒目錄)找到MangoSDK.framework文件,右鍵show in finder。如下圖


2.3.利用lipo -info 查看動(dòng)態(tài)庫(kù)所支持的CPU指令集,步奏如下
- 打開(kāi)終端
- cd 進(jìn)入
MangoSDK.framework,這里需要注意進(jìn)入的是MangoSDK.framework,而不是MangoSDK.framework所在目錄 - 在終端輸入
$lipo -info MangoSDK
通過(guò)以上三個(gè)步奏后,在終端會(huì)顯示出MangoSDK.framework所支持的CPU指令集,如下圖所示,可以看出默認(rèn)新建工程后所編譯出來(lái)的動(dòng)態(tài)庫(kù)所支持的CPU指令集是arm64(因?yàn)槲宜褂玫恼鏅C(jī)是6sp,其CPU指令集是arm64,后面會(huì)介紹CPU指令集是什么)

上面2.3.2需要額外注意一下,cd進(jìn)入的是MangoSDK.framework,下面演示一下進(jìn)入MangoSDK.framework所在目錄,進(jìn)行lipo -info的錯(cuò)誤結(jié)果:

下面演示正確的lipo -info姿勢(shì):

三、指令集的介紹
3.1. 指令集種類(lèi)
- armv7|armv7s|arm64都是ARM處理器的指令集
- i386|x86_64 是iOS模擬器的指令集
3.2.指令集對(duì)應(yīng)的機(jī)型
arm64:iPhone6s | iphone6s plus|iPhone6| iPhone6 plus|iPhone5S | iPad Air| iPad mini2(iPad mini with Retina Display)
armv7s:iPhone5|iPhone5C|iPad4(iPad with Retina Display)
armv7:iPhone4|iPhone4S|iPad|iPad2|iPad3(The New iPad)|iPad mini|iPod Touch 3G|iPod Touch4
i386: iPhone5 | iPhone 4s | iPhone 4及前代產(chǎn)品的模擬器
x86_64: iPhone5s | iPhone 6 | ... | iPhone8的模擬器
3.3.指令集兼容性說(shuō)明
理論上指令集是向下兼容的,比如連接設(shè)備為arm64,那么是有可能編譯出的動(dòng)態(tài)庫(kù)所支持的指令集為armv7s或者是armv7,這個(gè)具體看后面的介紹。但是向下兼容并不是說(shuō)一個(gè)armv7s的動(dòng)態(tài)庫(kù)可以用在arm64架構(gòu)的設(shè)備上,如果連接的設(shè)備是arm64的,而導(dǎo)入的動(dòng)態(tài)庫(kù)是沒(méi)有支持arm64,那么在編譯階段即會(huì)報(bào)錯(cuò)
四、Xcode指令集的編譯選項(xiàng)說(shuō)明
4.1. 打開(kāi) Target -> Build Setting -> Architectures, 可以看到下圖

4.2. 介紹一下三個(gè)編譯選項(xiàng)
-
Architectures:指明選定Target要求被編譯生成的二進(jìn)制包所支持的指令集 -
Build Active Architecture Only: 指明是否只編譯當(dāng)前連接設(shè)備所支持的指令集,如果是,那么只編譯出連接設(shè)備所對(duì)應(yīng)的指令集,如果否,則編譯出所有其它有效的指令集(由Architectures和Valid Architectures決定) -
Valid Architectures:指明可能支持的指令集并非Architectures列表中指明的指令集都會(huì)被支持
編譯產(chǎn)生的動(dòng)態(tài)庫(kù)所支持的指令集將由上面三個(gè)編譯選項(xiàng)所影響,首先一個(gè)動(dòng)態(tài)庫(kù)要成功編譯,則需要這三個(gè)編譯選項(xiàng)的交集不為空,舉幾個(gè)例子:
示例1:
Architectures 為armv7、arm64
Valid Architectures 為armv7、armv7s、arm64
Build Active Architecture Only 為 debug:YES release:NO
鏈接設(shè)備:iPhone 6s (arm64架構(gòu)的設(shè)備)
編譯(command + shift + B,保證Build Active Architecture Only 為 debug:YES 生效)
結(jié)果:編譯成功,生成的動(dòng)態(tài)庫(kù)支持的指令集為arm64
示例2:
Architectures 為armv7、arm64
Valid Architectures 為 armv7s
Build Active Architecture Only 為 debug:YES release:NO
鏈接設(shè)備:iPhone 6s (arm64架構(gòu)的設(shè)備)
編譯(command + shift + B,保證Build Active Architecture Only 為 debug:YES 生效)
結(jié)果:編譯失敗,因?yàn)楫?dāng)前是debug模式,在該模式下Build Active Architecture Only 為YES,表示只編譯支持該指令集的動(dòng)態(tài)庫(kù),
但是由于A(yíng)rchitectures和Build Active Architecture Only的交集中并不存在arm64,故三者的交集為空,故編譯失敗,無(wú)法生成動(dòng)態(tài)庫(kù)。
示例3:
Architectures 為armv7、arm64
Valid Architectures 為armv7、armv7s、arm64
Build Active Architecture Only 為 debug:NO release:NO
鏈接設(shè)備:iPhone 6s (arm64架構(gòu)的設(shè)備)
編譯(command + shift + B,保證Build Active Architecture Only 為 debug:YES 生效)
結(jié)果:編譯成功,因?yàn)楫?dāng)前是debug模式,在該模式下Build Active Architecture Only 為NO,
表示可以編譯的結(jié)果可能為當(dāng)前連接的設(shè)備所支持的指令集以及其向下兼容的指令集(armv64、armv7s、armv7),其和另外兩個(gè)編譯選項(xiàng)的交集為armv7,故所生成的動(dòng)態(tài)庫(kù)支持的指令集為armv7
所以,我們?cè)诓阶?strong>二、編譯動(dòng)態(tài)庫(kù)中之所以會(huì)生成支持arm64的動(dòng)態(tài)庫(kù)是因?yàn)?
1.Build Active Architecture Only 為 debug:YES release:NO
2.我們使用的是編譯,所以生效的選項(xiàng)為debug:YES,表示只生成當(dāng)前機(jī)型對(duì)應(yīng)的指令集(iPhone 6sp為 arm64)
3\. Architectures和Valid Architectures的交集為armv7、arm64,故三個(gè)選項(xiàng)的最終交集只有arm64,所以生成的動(dòng)態(tài)庫(kù)只支持arm64指令集
五、制作支持iPhone 4及以后機(jī)型的動(dòng)態(tài)庫(kù)
5.1. 支持iPhone 4 及以后機(jī)型的動(dòng)態(tài)庫(kù)的意思是:生成的動(dòng)態(tài)庫(kù)支持的指令集為armv7、armv7s、arm64,所以Architectures的三個(gè)指令可以設(shè)置為:
Build Active Architecture Only 統(tǒng)一為NO(如果不修改,則不能使用編譯去生成動(dòng)態(tài)庫(kù),而是需要去修改scheme的run模式為release,并且command + R運(yùn)行動(dòng)態(tài)庫(kù),為了簡(jiǎn)便,這里統(tǒng)一設(shè)置為NO)
-
Architectures和Valid Architectures都設(shè)置為armv7、armv7s、arm64
設(shè)置后的Architecture 為:image -
按照步奏 二、編譯動(dòng)態(tài)庫(kù) 進(jìn)行操作,最后通過(guò)lipo -info可以看到我們的動(dòng)態(tài)庫(kù)已經(jīng)支持了
armv7、armv7s、arm64,如下圖所示:image
六、制作支持iPhone 4及以后模擬器的動(dòng)態(tài)庫(kù)
6.1. 支持iPhone 4 及以后模擬器的動(dòng)態(tài)庫(kù)的意思是:生成的動(dòng)態(tài)庫(kù)支持的指令集為i386、x86_64,所以Architectures的三個(gè)指令可以設(shè)置為:
- Build Active Architecture Only 統(tǒng)一為NO
- Architectures和Valid Architectures最少都要包含armv7s、arm64(少了armv7s則不會(huì)支持i386,少了arm64則不會(huì)支持x86_64,挺神奇的,還沒(méi)弄懂),設(shè)置后的Architecture 和步奏5.1第一張配圖一樣
- 參照步奏 二、編譯動(dòng)態(tài)庫(kù) 進(jìn)行操作,不過(guò)需要將步奏2.1中編譯設(shè)備選擇為模擬器(任意iPhone模擬器都可以),最后通過(guò)lipo -info可以看到我們的動(dòng)態(tài)庫(kù)已經(jīng)支持了
i386、x86_64,如下圖所示:

七、合并模擬器和真機(jī)動(dòng)態(tài)庫(kù)
7.0.合并動(dòng)態(tài)庫(kù)的前提是已經(jīng)按照第五、第六步奏生成了兩個(gè)對(duì)應(yīng)的動(dòng)態(tài)庫(kù),否則直接進(jìn)行合并操作的話(huà),會(huì)提示找不到文件,這一點(diǎn)可以翻下去看粘貼的腳本命令,仔細(xì)讀一讀就知道原理了。
7.1.通過(guò)步奏五和步奏六生成的動(dòng)態(tài)庫(kù)名字是一樣的,但是不通用于模擬器和真機(jī),如果不合并動(dòng)態(tài)庫(kù)的話(huà),那么在切換模擬器和真機(jī)的時(shí)候需要同時(shí)切換動(dòng)態(tài)庫(kù),這是我們不希望看到的,所以我們需要將模擬器和真機(jī)動(dòng)態(tài)庫(kù)合并為一個(gè)通用的動(dòng)態(tài)庫(kù)。
7.2. 由于在終端中使用lipo -create -output命令合并動(dòng)態(tài)庫(kù)有點(diǎn)復(fù)雜(搞了半個(gè)小時(shí)合并出來(lái)的動(dòng)態(tài)庫(kù)不能使用),故還是使用腳本生成動(dòng)態(tài)庫(kù)好了,步奏如下:
- 新建一個(gè)target腳本,如下圖

- 粘貼以下腳本內(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命令將其合并成一個(gè)通用framework
# 最后將生成的通用framework放置在工程根目錄下新建的Products目錄下
lipo -create "${DEVICE_DIR}/${PROJECT_NAME}" "${SIMULATOR_DIR}/${PROJECT_NAME}" -output "${INSTALL_DIR}/${PROJECT_NAME}"
#open "${DEVICE_DIR}"
#open "${SRCROOT}/Products"
fi
- 編譯新target,如圖所示

- 編譯完成后生成的framework位于工程源代碼根目錄下的Products文件夾下面,通過(guò)
lipo -info可以看到動(dòng)態(tài)庫(kù)已經(jīng)支持i386、x86_64、armv7、armv7s、arm64,如下圖所示

八、使用動(dòng)態(tài)庫(kù)
8.1.將步奏七生成的動(dòng)態(tài)庫(kù)拖入新工程中,在新工程的AppDelegate.m中鍵入如下代碼
#import <MangoSDK/MangoSDK.h>
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
ViewController *vc = [[ViewController alloc] init];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
[self.window makeKeyAndVisible];
self.window.backgroundColor = [UIColor whiteColor];
self.window.rootViewController = vc;
[MGUtils mg_logMessage:@"framework test"];
return YES;
}
8.2.在新工程的target中的General -> Embedded Binaries中添加MangoSDK.framework,如下圖

8.3.分別使用真機(jī)和模擬器運(yùn)行新工程,執(zhí)行成功,控制臺(tái)輸出如下:

九、使用別人提供的動(dòng)態(tài)庫(kù)遇到的坑
9.1.第一類(lèi)坑為別人提供的第三方庫(kù)所支持的CPU指令集不全,出現(xiàn)的錯(cuò)誤信息類(lèi)似如下圖:

上面的截圖中,我們連接的設(shè)備是iPhone 7 模擬器,其CPU架構(gòu)為x86_64,但是我導(dǎo)入的framework是真機(jī)編譯出來(lái)的動(dòng)態(tài)庫(kù)(支持的指令集為armv7、armv7s、arm64,并沒(méi)有x86_64),所以就報(bào)了這樣的類(lèi)似的錯(cuò)誤,進(jìn)一步可以使用步奏 二、編譯動(dòng)態(tài)庫(kù) 中的2.3小點(diǎn)查看別人提供的動(dòng)態(tài)庫(kù)所支持的指令集,這個(gè)坑屬于那個(gè)提供動(dòng)態(tài)庫(kù)的同事造成的,讓他去填就可以。
9.2.運(yùn)行過(guò)程中出現(xiàn) image not found異?;蛘呖刂婆_(tái)沒(méi)有異常輸出,如下圖

出現(xiàn)這種問(wèn)題的原因是我們沒(méi)有往Embedded Binaries中添加MangoSDK.framework,所以進(jìn)行如下操作即可解決這個(gè)異常。話(huà)說(shuō)像訊飛之類(lèi)的framework為什么不需要往Embedded Binaries添加對(duì)應(yīng)SDK,即可以成功運(yùn)行?這一點(diǎn)我還沒(méi)有去研究,知道的小伙伴還請(qǐng)不吝賜言喲

以上便是我近來(lái)和動(dòng)態(tài)庫(kù)打交道過(guò)程中遇到的坑,如果你完整了看完了我這篇文章,還是建議你可以去實(shí)踐一下制作一個(gè)動(dòng)態(tài)庫(kù)。說(shuō)多了都是淚,由于我之前沒(méi)有制作過(guò)動(dòng)態(tài)庫(kù),同事提供了我一個(gè)SDK后,我集成出現(xiàn)了第九點(diǎn)中的兩個(gè)坑,尋同事,同事曰:別人可以,你為什么不可以?iOS你比我熟!如果當(dāng)初我對(duì)動(dòng)態(tài)庫(kù)的整個(gè)流程熟悉的話(huà),那么我就可以對(duì)其說(shuō):首先你提供的動(dòng)態(tài)庫(kù)只支持armv7、armv7s,我的手機(jī)是arm64架構(gòu)指令集的,其次,因?yàn)閯e人使用的設(shè)備恰好是iPhone 5,所以沒(méi)毛病。但是你必須給我重新編譯一個(gè)支持i386、x86_64、armv7、armv7s、arm64的動(dòng)態(tài)庫(kù)。所以熟悉動(dòng)態(tài)庫(kù)的制作-嵌入整個(gè)流程還是必要的。
如果以上內(nèi)容有錯(cuò),還請(qǐng)不吝指出,謝謝大家。
上面我們將 i386 x86_64 armv7 arm64 幾個(gè)平臺(tái)都合并到了一起,所以使用動(dòng)態(tài)庫(kù)上傳appstore時(shí)需要將i386 x86_64兩個(gè)平臺(tái)刪除后,才能正常提交審核
在SDK當(dāng)前路徑下執(zhí)行以下命令刪除i386 x86_64兩個(gè)平臺(tái)
bak文件是備份目錄,上傳appstore之后需要替換回bak目錄下的SDK
mkdir ./bak
cp -r MangoSDK.framework ./bak
lipo MangoSDK.framework/MangoSDK -thin armv7 -output MangoSDK_armv7
lipo MangoSDK.framework/MangoSDK -thin arm64 -output MangoSDK_arm64
lipo -create MangoSDK_armv7 MangoSDK_arm64 -output MangoSDK
mv MangoSDK MangoSDK.framework/

