iOS 靜態(tài)庫的制作 Unity依賴iOS原生工程庫

主要內(nèi)容翻譯自:《How to Create a Framework》


在iOS中如何創(chuàng)建framework呢?

跟著本文的教程,你將學(xué)會(huì)以下的技能:

  • 在Xcode中創(chuàng)建基本的靜態(tài)庫工程(static library)
  • 創(chuàng)建一個(gè)依賴于你創(chuàng)建的靜態(tài)庫工程的應(yīng)用
  • 探索怎樣將靜態(tài)庫工程轉(zhuǎn)換為框架(framework)
  • 最后,你將學(xué)會(huì)怎樣將圖片資源打包到自定義的資源包( resource bundle),并在你制作的框架中進(jìn)行資源引用(其中,我將補(bǔ)充nib文件的引用)
  • 最后的最后,我將補(bǔ)充如何在你制作的框架中引用第三方靜態(tài)庫(路徑引用,非拷貝第三方庫)

準(zhǔn)備開始

這篇文章的目的不僅僅是像其他文章一樣簡單的介紹制作靜態(tài)庫,還會(huì)詳細(xì)的講解其中的原理。
首先請下載 RWKnobControl 源碼。當(dāng)你跟著學(xué)習(xí)創(chuàng)建靜態(tài)庫的教程后,你將學(xué)會(huì)怎樣來使用它們。

什么是框架呢?(framework 庫、框架)

框架或者叫做庫就是資源的集合. 里面集成了一個(gè)Xcode能夠很容易地納入到工程里的一個(gè)獨(dú)立的結(jié)構(gòu),里面包含了靜態(tài)庫和頭文件。

在OS’X系統(tǒng)中,是可以創(chuàng)建動(dòng)態(tài)鏈接庫的。通過動(dòng)態(tài)庫鏈接技術(shù),程序可以不用再次來鏈接庫就可以實(shí)現(xiàn)庫的更新(熱更新技術(shù)的一種)。在運(yùn)行時(shí)中,只會(huì)拷貝一份靜態(tài)庫中的代碼,就可以讓這份代碼共享到所有使用它的進(jìn)程,所以呢,這種技術(shù)可以減少內(nèi)存的開銷和提高系統(tǒng)的性能。你看,這是不是一種很牛掰的技術(shù)呢?

在iOS系統(tǒng)中,你不能夠添加自定義的庫到你的程序中(其實(shí)是可以的,但是不能上架,會(huì)被拒絕而已。所以你可以使用在企業(yè)應(yīng)用的分發(fā)中。 你看,就象蘋果拒絕了JSPatch一樣。);所以,你只能夠使用蘋果提供的動(dòng)態(tài)鏈接庫。(有什么?CoreFundation..UIKit 等等)。

但是!這并不意味著在iOS中使用庫是不行的。客觀請看:靜態(tài)鏈接庫是可以用的哦,上面說的是動(dòng)態(tài)鏈接庫。

創(chuàng)建一個(gè)靜態(tài)庫工程

打開Xcode并選擇創(chuàng)建一個(gè)Cocoa Touch Static Library工程。如下圖:(掩飾Xcdoe工程版本為8.2.1,其他版本的界面可能有出入,但是你還是會(huì)找到我所提到的東西的,耐心點(diǎn)找找。)

創(chuàng)建靜態(tài)庫.png

并將工程名字命名為:RWUIControls(可不可以不是這個(gè)名字呢?后面教程使用了動(dòng)態(tài)打包framework bundle的腳本,看了講解后 你就知道能不能了。)

一個(gè)靜態(tài)庫工程是由編譯成靜態(tài)庫的頭文件和實(shí)現(xiàn)文件來組成。

為了使你的靜態(tài)庫用起來很簡便,你只需要暴露出一個(gè)頭文件就行了,是怎樣的一個(gè)頭文件呢?頭文件里需要暴露出你需要使用者使用的類的頭文件就行了。

當(dāng)你創(chuàng)建 RWUIControls這個(gè)靜態(tài)庫工程的時(shí)候,工程默認(rèn)為你創(chuàng)建了RWUIControls.h和RWUIControls.m兩個(gè)文件,其中RWUIControls.m是不需要實(shí)現(xiàn)的,你可以刪了它(move to trash)。
打開RWUIControls.h頭文件,在里面添加如下庫:(因?yàn)樵撿o態(tài)庫使用了UIKit的相關(guān)接口,你可以依照你制作的庫的實(shí)際情況來添加你需要的庫。)
#import <UIKit/UIKit.h>

當(dāng)然了,你會(huì)發(fā)現(xiàn)你無法import。因?yàn)殪o態(tài)庫工程無法找到。如何來解決呢,首先選擇 Build Phases來展開Link Libraries面板。點(diǎn)擊添加按鈕+ 來添加你需要的庫(該演示教程需要添加UIKit)

導(dǎo)入相關(guān)庫.gif

如果就這樣創(chuàng)建一個(gè)靜態(tài)庫,它是不起任何作用的,因?yàn)殪o態(tài)庫需要聯(lián)合頭文件來起作用。
接下來,你需要?jiǎng)?chuàng)建一個(gè)新的構(gòu)建方式屬性(Build Phase),它的作用是告訴編譯器哪些頭文件是可以提供給外部訪問的。

在Xcode的頂部菜單欄選擇 Editor\Add Build Phase\Add Copy Headers Build Phase(如果你發(fā)現(xiàn)你找不到 Add Copy Headers Build Phase, 首先保證當(dāng)前Xcode頁面位于Build Phase 頁面;如果你發(fā)現(xiàn) AddCopyHeadersBuildPhase是灰色不可選的,先嘗試點(diǎn)擊下Xcode的空白處再來選擇)

暴露頭文件.gif

請牢記上圖操作:將你需要提供給外部訪問的頭文件拽入 Copy Headers的 Public中(Private:很明顯的意思是對外不開放 Project:也是不開放的哦,你只需記住Public Private 的使用。)


創(chuàng)建一個(gè)UI控制類

靜態(tài)庫工程的配置已經(jīng)設(shè)置好了,你需要將你想打包到靜態(tài)庫的文件導(dǎo)入 RWUIControls下。將你之前下載的打包文件解壓,找到RWKnobControl,并將它拖入到RWUIControls中 并選擇 copy item。如下圖:

這樣的操作將會(huì)添加實(shí)現(xiàn)文件到編譯列表中,默認(rèn)情況下,頭文件會(huì)被添加Project列中(也同樣意味著 private)

接下來,你需要將RWKnobControl.h弄到Public中去。可以拖拽到Public,也可以如下圖方式進(jìn)行設(shè)置(注意紅色標(biāo)注):


除此之外,你需要將你想暴露出的頭文件添加到靜態(tài)庫的頭文件中。這樣做的好處在于,以免使用者在庫里去查找他想用的頭文件,他只需要導(dǎo)入靜態(tài)庫的頭文件就行了。請移步到 RWUIControls.h(這個(gè)是你創(chuàng)建靜態(tài)庫工程時(shí)自動(dòng)生成的,你還記得么?),并添加如下代碼:
#import <RWUIControls/RWKnobControl.h>

配置 (Configuring Build Settings)
到此為止,你已經(jīng)學(xué)會(huì)了創(chuàng)建靜態(tài)庫的大部分知識(shí)了,再堅(jiān)持下,跟著做以下配置,你的庫對于使用者來說會(huì)更加友好。

首先,你需要為公開頭文件提供一個(gè)路徑。這種做法保證了靜態(tài)庫在使用過程中能夠定位到相應(yīng)的頭文件。

在工程導(dǎo)航欄中點(diǎn)擊項(xiàng)目(TARGETS),并且選擇RWUIControls, 選擇Build Settings標(biāo)簽,在搜索框中輸入 public header. 雙擊 *Public Headers Folder Path 進(jìn)行如下圖的輸入:

待會(huì)兒將會(huì)為你展示這個(gè)路徑下的東西。

接下來,你需要做其他的設(shè)置,尤其是那些在靜態(tài)庫中的配置。編譯器為你提供了選擇,是否自動(dòng)移除從來沒有使用過的僵尸代碼(dead code).并且你還可以選擇移除debug標(biāo)記等等。

為別人創(chuàng)建了第三方靜態(tài)庫,最好是將以上提到的兩點(diǎn)設(shè)置選擇為NO,如下設(shè)置:

  • Dead Code Stripping – Set this to NO
  • Strip Debug Symbols During Copy – Set this to NO for all configurations
  • Strip Style – Set this to Non-Global Symbols

command + B進(jìn)行編譯一下。你好像什么都沒看到,那就對了,說明沒有警告和錯(cuò)誤提示。再來創(chuàng)建一下,這里我們選擇 iOS Device 進(jìn)行編譯。創(chuàng)建完成后,你將會(huì)在Xcode工程左邊的目錄 Products下看到 libRWUIControls.a由之前的紅色變成了黑色(如果沒有,請選擇模擬器編譯一次,再選擇真機(jī)編譯一次;如果還是紅色,多半是Xcode的問題,clear或者重啟試試。),鼠標(biāo)右鍵選擇 Show in Finder 你將會(huì)看到如下目錄:

發(fā)現(xiàn)什么了嗎?這個(gè)include文件夾就是你之前在配置里設(shè)置的(include/$(PROJECT_NAME)),里面包含的兩個(gè)頭文件,就是你暴露出來的。

創(chuàng)建一個(gè)使用你創(chuàng)建的靜態(tài)庫的工程

在此教程下,你將創(chuàng)建一個(gè)使用你自己創(chuàng)建的靜態(tài)庫的工程。
先關(guān)閉靜態(tài)庫工程。然后我們來創(chuàng)建一個(gè)新工程。選擇 Single View Application,并且給工程命名為UIControlDevApp.將類文件的前綴添加為RW,并且將工程修改為只支持 iPhone。最后將工程保存到RWUIControls靜態(tài)庫工程同一級(jí)目錄中。

在UIControlDevApp工程中引入RWUIControls.xcodeproj(拖拽就行了),如下圖:

誒,這種目錄結(jié)構(gòu)是不是好像在哪見過呢?CocoaPods工程! 這樣做的好處在哪里呢,你可以在一個(gè)工作空間中修改靜態(tài)庫,同時(shí)也可以運(yùn)行依賴該庫的工程,進(jìn)行效果校對。這樣很方便。

接下來,請將你之前下載的代碼包中的DevApp文件夾一起拖拽入 UIControlDevApp中(選擇Copy),如下圖:

接下來,你將在你的示意工程中配置靜態(tài)庫依賴:

  • 在工程導(dǎo)航欄中選擇UIControlDevApp工程
  • 在UIControlDevApp中選擇Build Phases 標(biāo)簽
  • 打開Target Dependencies 面板,選擇+進(jìn)行添加
  • 找到RWUIContols 靜態(tài)庫,選擇添加。

為了反向關(guān)聯(lián)靜態(tài)庫,展開Link Binary With Libraries 面板,添加 libRWUIControls.a 如下圖:

添加依賴

好了,到了這一步 你可以運(yùn)行你創(chuàng)建的工程了。如果你嚴(yán)格按照之前的步驟,你將會(huì)看到如下圖所示的效果:

創(chuàng)建腳本

創(chuàng)建framework

迄今為止,你已經(jīng)學(xué)會(huì)了創(chuàng)建靜態(tài)庫。接下來,我們將來創(chuàng)建framework。
在之前創(chuàng)建靜態(tài)庫的時(shí)候,你已經(jīng)完成了大部分創(chuàng)建framework的工作,接下來,你只需要跟著以下步驟就可以完成framework的創(chuàng)建。(看著有點(diǎn)復(fù)雜)

  • framework的目錄結(jié)構(gòu)。framework有著一個(gè)特別的目錄結(jié)構(gòu),為了讓Xcode能識(shí)別出它是framework。接下來你將跟著我來創(chuàng)建這樣的一個(gè)目錄結(jié)構(gòu)。

  • 切片。就目前來講,當(dāng)你編譯庫時(shí),僅僅是針對當(dāng)前的環(huán)境編譯了相應(yīng)的庫(真機(jī)發(fā)布?真機(jī)調(diào)試?模擬器發(fā)布?模擬器調(diào)試?),也就是 i386,arm7,等等。為了能夠讓framework在各種環(huán)境下適用,我們需要將各個(gè)環(huán)境編譯的庫放到framework對應(yīng)的目錄結(jié)構(gòu)下。

Framework 的結(jié)構(gòu)

ios_framework_directory_structure-449x320.png

接下來我將創(chuàng)建一個(gè)腳本來動(dòng)態(tài)創(chuàng)建靜態(tài)庫。首先在Xcode的工程導(dǎo)航欄中選中 RWUIControls工程,點(diǎn)擊RWUIControls 靜態(tài)庫項(xiàng)目。選擇 Build Phases標(biāo)簽,在Xcode菜單欄中選擇 Editor / Add Build Phase/Add Run Script Build Phase. 如下圖:

ios_framework_framework_add_run_script_build_phase-700x271.png

當(dāng)前創(chuàng)建的Script支持 Bash腳本的運(yùn)行。我們來雙擊 RunScript標(biāo)簽進(jìn)行重命名為 Build Framework, 然后將以下的代碼拷貝進(jìn)代碼框:

set -e export FRAMEWORK_LOCN="${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework" # Create the path to the real Headers diemkdir -p "${FRAMEWORK_LOCN}/Versions/A/Headers" # Create the required symlinks/bin/ln -sfh A "${FRAMEWORK_LOCN}/Versions/Current"/bin/ln -sfh Versions/Current/Headers "${FRAMEWORK_LOCN}/Headers"/bin/ln -sfh "Versions/Current/${PRODUCT_NAME}" \ "${FRAMEWORK_LOCN}/${PRODUCT_NAME}" # Copy the public headers into the framework/bin/cp -a "${TARGET_BUILD_DIR}/${PUBLIC_HEADERS_FOLDER_PATH}/" \ "${FRAMEWORK_LOCN}/Versions/A/Headers"

代碼解讀:
腳本首先創(chuàng)建了這樣的一個(gè)目錄結(jié)構(gòu) RWUIControls.framework/Versions/A/Headers
接下來創(chuàng)建了如下的引用鏈接:

  • Versions/Current => A
  • Headers => Versions/Current/Headers
  • RWUIControls => Versions/Current/RWUIControls

最后,將公開的頭文件拷貝到 Versions/A/Headers 目錄中。其中 -a 參數(shù)表示當(dāng)你做一些修改時(shí),與此拷貝不同步,由此來保證不必要的重復(fù)編譯。

接下來做如下圖的編譯:

右鍵選擇工程目錄里的 Products下的 libRWUIControls.a, 選擇 Show in Finder. 接下來選擇查看包結(jié)構(gòu),你將看到之前提到framework的結(jié)構(gòu)。

但是你會(huì)發(fā)現(xiàn)一個(gè)問題,在目錄結(jié)構(gòu)中沒有你想創(chuàng)建的靜態(tài)庫,別慌,接下來我們將會(huì)創(chuàng)建另外一個(gè)腳本。

支持多框架的創(chuàng)建###

iOS app需要在如下眾多的框架環(huán)境下運(yùn)行:

  • arm7: 支持iOS7的老設(shè)備
  • arm7s: iPhone 5 和 5C
  • arm64: 64-bit ARM processor in iPhone 5S
  • i386: For the 32-bit simulator
  • x86_64: Used in 64-bit simulator

眾多設(shè)備需要不同環(huán)境下編譯的靜態(tài)庫,好象這么做有點(diǎn)復(fù)雜,我們可以采取將各個(gè)平臺(tái)下的靜態(tài)庫添加到framework中。

我們將利用 RWUIControls項(xiàng)目來創(chuàng)建。選擇 RWUIControls項(xiàng)目(target),然后點(diǎn)擊 Add Target 按鈕,選擇添加 Aggregate:

創(chuàng)建集合

并命名為 Framework。

備注: 為什么要這么繞呢?還記得開篇講過iOS審核的問題嗎?那么我們可以采取創(chuàng)建 Aggregate的方式來繞過那個(gè)麻煩的問題,同時(shí)我們還可以在此創(chuàng)建腳本來添加靜態(tài)庫。是不是很神奇?

為了保證在創(chuàng)建Framework前,靜態(tài)庫已經(jīng)創(chuàng)建了,你需要為 Framework添加項(xiàng)目依賴。如下圖:

添加項(xiàng)目依賴

最重要的步驟是,你需要?jiǎng)?chuàng)建一個(gè)支持多環(huán)境的庫,接下來你應(yīng)該象之前你創(chuàng)建一個(gè)腳本那樣,為framework創(chuàng)建一個(gè)腳本。如下圖:

創(chuàng)建腳本

將腳本的名字更改為 MultiPlatform Build. 并拷貝以下代碼到腳本里:
#If we're already inside this script then die if [ -n "$RW_MULTIPLATFORM_BUILD_IN_PROGRESS" ]; then exit 0 fi export RW_MULTIPLATFORM_BUILD_IN_PROGRESS=1 RW_FRAMEWORK_NAME=${PROJECT_NAME}RW_INPUT_STATIC_LIB="lib${PROJECT_NAME}.a" RW_FRAMEWORK_LOCATION="${BUILT_PRODUCTS_DIR}/${RW_FRAMEWORK_NAME}.framework"

  • set -e保證了創(chuàng)建一個(gè)完整的framework:當(dāng)腳本編譯錯(cuò)誤,將終止
  • 接下來, 這個(gè) RW_MULTIPLATFORM_BUILD_IN_PROGRESS
    變量確保了這個(gè)腳本不會(huì)被循環(huán)引用,如果循環(huán)引用了,那么就終止。
  • 然后設(shè)置了一些變量. 注意:framework的名字必須和工程名字相同
    ,如下RWUIControls, 靜態(tài)庫名字為 libRWUIControls.a.

接下來創(chuàng)建一些函數(shù),后面我們將使用到,將代碼復(fù)制到腳本里的后面。

function build_static_library {# Will rebuild the static library as specified # build_static_library sdk xcrun xcodebuild -project "${PROJECT_FILE_PATH}" \ -target "${TARGET_NAME}" \ -configuration "${CONFIGURATION}" \ -sdk "${1}" \ ONLY_ACTIVE_ARCH=NO \ BUILD_DIR="${BUILD_DIR}" \ OBJROOT="${OBJROOT}" \ BUILD_ROOT="${BUILD_ROOT}" \ SYMROOT="${SYMROOT}" $ACTION} function make_fat_library { # Will smash 2 static libs together # make_fat_library in1 in2 out xcrun lipo -create "${1}" "${2}" -output "${3}" }

  • build_static_library
    SDK 作為一個(gè)參數(shù), (例如 *iphoneos7.0)
    *來創(chuàng)建庫, 大多數(shù)參數(shù)都會(huì)通過, 注意這個(gè)參數(shù) ONLY_ACTIVE_ARCH
    是確保當(dāng)前的構(gòu)造版本中所有的框架環(huán)境都支持當(dāng)前的SDK。
  • make_fat_library
    用 lips
    來合并兩個(gè)靜態(tài)庫。 將輸入的兩個(gè)靜態(tài)庫合并后輸出. 關(guān)于lipo的更多知識(shí)請點(diǎn)擊lipo。

接下來就是來怎么使用以上的兩個(gè)函數(shù)了,你需要知道哪些SDK,以及這些SDK的路徑位置。

# 1 - Extract the platform (iphoneos/iphonesimulator) from the SDK name if [[ "$SDK_NAME" =~ ([A-Za-z]+) ]]; then RW_SDK_PLATFORM=${BASH_REMATCH[1]} else echo "Could not find platform name from SDK_NAME: $SDK_NAME" exit 1 fi
# 2 - Extract the version from the SDK if [[ "$SDK_NAME" =~ ([0-9]+.*$) ]]; then RW_SDK_VERSION=${BASH_REMATCH[1]} else echo "Could not find sdk version from SDK_NAME: $SDK_NAME" exit 1 fi
# 3 - Determine the other platform if [ "$RW_SDK_PLATFORM" == "iphoneos" ]; then RW_OTHER_PLATFORM=iphonesimulator else RW_OTHER_PLATFORM=iphoneos fi
# 4 - Find the build directory if [[ "$BUILT_PRODUCTS_DIR" =~ (.*)$RW_SDK_PLATFORM$ ]]; then RW_OTHER_BUILT_PRODUCTS_DIR="${BASH_REMATCH[1]}${RW_OTHER_PLATFORM}" else echo "Could not find other platform build directory." exit 1 fi

以上4個(gè)聲明的意思都非常相近, 用判斷來給這兩個(gè)參數(shù)賦值 RW_OTHER_PLATFORM
和 RW_OTHER_BUILT_PRODUCTS_DIR.

以下講解四個(gè) if 的作用

  • SDK_NAME必須是 iphoneos7.0 或 iphonesimulator6.1的格式。 正則表達(dá)是確保以非數(shù)字開頭的字符串。 所以它就確定為 iphoneos或者 iphonesimulator
  • 同樣的道理,保證為如下, 7.0or 6.1etc.
  • 應(yīng)該還是看得懂吧,判斷環(huán)境進(jìn)行賦值。 是iphonesimulator 還是 iphoneos
  • 從創(chuàng)建的版本目錄中獲取平臺(tái)名字,用其他版本的來替換。這一步保證其他平臺(tái)能夠從創(chuàng)建的路徑中查找到。

添加如下腳本代碼到腳本的后面:

# Build the other platform. build_static_library "${RW_OTHER_PLATFORM}${RW_SDK_VERSION}"
# If we're currently building for iphonesimulator, then need to rebuild
# to ensure that we get both i386 and x86_64 if [ "$RW_SDK_PLATFORM" == "iphonesimulator" ]; then build_static_library "${SDK_NAME}"fi
# Join the 2 static libs into 1 and push into the .framework make_fat_library "${BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}" \ "${RW_OTHER_BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}" \ "${RW_FRAMEWORK_LOCATION}/Versions/A/${RW_FRAMEWORK_NAME}"

  • 首先對你之前創(chuàng)建的函數(shù)的調(diào)用,目的是構(gòu)建起他版本
  • 如果你當(dāng)前創(chuàng)建的模擬器版本,Xcode會(huì)默認(rèn)只創(chuàng)建如下兩種庫:i386或x86_64.為了能夠創(chuàng)建這兩種架構(gòu)的庫,第二步調(diào)用 build_static_library來創(chuàng)建 iphonesimulatorSDK, 并且確保兩種庫已經(jīng)創(chuàng)建。
  • 最后來調(diào)用 make_fat_library函數(shù),讓靜態(tài)庫融入到framework中的路徑里。

堅(jiān)持!最后一步了,將以下代碼添加到腳本的最后面:

# Ensure that the framework is present in both platform's build directories cp -a "${RW_FRAMEWORK_LOCATION}/Versions/A/${RW_FRAMEWORK_NAME}" \ "${RW_OTHER_BUILT_PRODUCTS_DIR}/${RW_FRAMEWORK_NAME}.framework/Versions/A/${RW_FRAMEWORK_NAME}"
# Copy the framework to the user's desktop ditto "${RW_FRAMEWORK_LOCATION}" "${HOME}/Desktop/${RW_FRAMEWORK_NAME}.framework"

  • 第一條命令是確保framework存在于兩種路徑里
  • 最后一步是將創(chuàng)建好的framework拷貝到你的桌面。當(dāng)然,這一步是可選的。但是這樣會(huì)很方便你去使用。

好了,所有的操作都搞定了,只需要選擇 Framework進(jìn)行編譯一下(隨便你選什么設(shè)備都行):

你可以查看framework包內(nèi)容:

查看framework目錄結(jié)構(gòu)

如何來檢查當(dāng)前拷貝出的framework是否支持所有環(huán)境的呢?
打開你的終端(terminal),如下圖操作:


驗(yàn)證framework支持的平臺(tái).png

你將看見列出了五種環(huán)境,armv7 armv7s i386 x86_arm64 OK 搞定。

怎么使用?這里我就不贅述了,直接將framework拖入到你工程的 framework目錄下,然后導(dǎo)入頭文件就行了。

以上我們講解了靜態(tài)庫的打包,但是我們還沒講解資源的打包(圖片、字體、nib)。

創(chuàng)建一個(gè)Bundle

打開UIControlDevApp工程,選擇RWUIControls子工程(還記得之前我們在一個(gè)工作空間里管理兩個(gè)工程嗎?)。點(diǎn)擊 Add Target按鈕:

創(chuàng)建Bundle.gif

當(dāng)前你創(chuàng)建的Bundel默認(rèn)是 OSX的,你需要將它更改為 iOS。 操作如下圖:

修改bundle支持iOS.png

接下來你需要更改產(chǎn)品名字(后面腳本會(huì)用到,更改和靜態(tài)庫的名字一樣),如下圖:

修改名字.png

默認(rèn)情況下,當(dāng)你在Bundle中添加兩倍圖時(shí),系統(tǒng)會(huì)將它編譯為多分辨率的格式 TIFF,這樣是你不希望的,因?yàn)闀?huì)導(dǎo)致奇怪的問題。你可以做如下圖的設(shè)置:

修改bundle配置.png

好了,請記住:當(dāng)你編譯framework時(shí),bundle也需要被framework引用。如下圖操作:

添加bundle引用.gif

好了,我們最后可以像framework的腳本一樣,添加一個(gè)拷貝Bundle到桌面的操作,添加如下代碼到 MuiltiPlatform Build 腳本中:

# Copy the resources bundle to the user's desktop ditto "${BUILT_PRODUCTS_DIR}/${RW_FRAMEWORK_NAME}.bundle" \ "${HOME}/Desktop/${RW_FRAMEWORK_NAME}.bundle"

選擇framework 進(jìn)行編譯,你會(huì)在你的桌面上發(fā)現(xiàn)兩個(gè)包:xxx.framework, xxx.bundle

好了創(chuàng)建Bundle已經(jīng)成功,但是如何使用呢?

圖片的引用:
UIImage *image = [UIImage imageNamed:@"RWUIControls.bundle/RWRibbon"];

nib的引用:
NSString * bundlePath =[[NSBundle mainBundle] pathForResource:@“RWUIControls" ofType:@“bundle”];
NSBundle * bundle = [NSBundle bundleWithPath:bundlePath];
[UIStoryboard storyboardWithName:@“xxx” bundle:bundle];

引用xib也是同樣的道理,把mainBundle替換為你創(chuàng)建的bundle就行了。

但是!請注意

這里我加一點(diǎn)補(bǔ)充:如果xib/storyBoard中的文件與你創(chuàng)建的類進(jìn)行了關(guān)聯(lián),例如:stroyBoard中的 MainViewController 與你創(chuàng)建的 MainViewController class進(jìn)行了關(guān)聯(lián),你需要將 MainViewController.h 文件給暴露出來(這個(gè)類在靜態(tài)庫中,靜態(tài)庫引用了你創(chuàng)建的Bundle,你需要在靜態(tài)庫中將 MainViewController.h拖入到 Public中)。

補(bǔ)充知識(shí)點(diǎn):###

如果你有個(gè)非常大的工程B,你想將它作為主工程A的插件(第三方庫),并且B中使用了Cocoapods來管理第三方庫,那么按照之前講解之作framework的流程來看,你需要將B中的代碼全部拖到 framework 工程中進(jìn)行編譯。

試想,如果B工程是多個(gè)人開發(fā)或者需要經(jīng)常更新,怎么辦?還是拷貝代碼到framework工程嗎?太麻煩了是吧?

猜想下,我們可以創(chuàng)建一個(gè)framework工程C,如果C與B在同一個(gè)工作空間中(workspace), 并且C中引用(是引用,不是拷貝)B中所有的代碼,那么C是不是可以隨著B的更新而更新呢? 答案是:嘗試下~(當(dāng)然是可以的)

且看下圖:

工程結(jié)構(gòu).png

如果你在 SystematicAnatomyControls(靜態(tài)庫)中引用第三方庫 如:
#import <AFNetworking/AFNetworking.h>
你在編譯時(shí),Xcode會(huì)告訴你無法找到。為什么?(跨工程路徑問題,找不到Cocopods中的庫)
怎么解決呢?

先在主工程中做如下操作:

設(shè)置Pods宏路徑.png

PODS_ROOT 為你自定義添加的,添加方式如下:

添加自定義設(shè)置.png

講解:/../表示回退到上一級(jí)目錄,我為什么這么做?--參照Pods的做法,主工程依賴Pods的內(nèi)容,那么主工程也得找到Pods中的文件,下圖是我工程的目錄情況,同樣也告訴你我為什么用 /../ 這種方式來查找文件。

工作空間路徑.png

然后我們來做如下圖操作:

配置Header Search Path.png

講解:表示從哪里查詢頭文件;“ ” 冒號(hào)的意思是忽略路徑中的空格。


本文主要參照《How to Create a Framework》;
如翻譯有誤,請指正。
在文末我做了相應(yīng)的補(bǔ)充,希望能夠幫到你。
本文所采用的技術(shù)已做相應(yīng)的論證,主要使用于Unity導(dǎo)出的Xcode工程依賴原生工程靜態(tài)庫。
如有其它相關(guān)問題,歡迎暢討!

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

推薦閱讀更多精彩內(nèi)容