前言
如果你想將你開發(fā)的控件與別人分享吱肌,一種方法是直接提供源代碼文件痘拆。然而,這種方法并不是很優(yōu)雅氮墨。它會暴露所有的實現(xiàn)細節(jié)纺蛆,而這些實現(xiàn)你可能并不想開源出來。此外规揪,開發(fā)者也可能并不想看到你的所有代碼桥氏,因為他們可能僅僅希望將你的這份漂亮代碼的一部分植入自己的應用中。
? ? ? 另一種方法是將你的代碼編譯成靜態(tài)庫(library)粒褒,讓其他開發(fā)者添加到自己的項目中识颊。然而,這需要你一并公布所有的公開的頭文件,實在是非常不方便祥款。
你需要一種簡單的方法來編譯你的代碼清笨,這種方法應該使得你的代碼易分享,并且在多個工程中易復用刃跛。你需要的是一種方法來打包你的靜態(tài)庫抠艾,將所有的頭文件放到一個單元中,這樣你就可以立刻將其加入到你的項目中并使用桨昙。
? ? ? OS X完美地支持這一點检号,因為Xcode就提供了一個項目模板,包含著默認構建目標(target)和可以容納類似于圖片蛙酪、聲音齐苛、字體等資源的文件。你可以為iOS創(chuàng)建Framework桂塞,不過這是一個比較復雜的手工活凹蜂,如果你跟著教程走,你將學到怎么樣跨過路障阁危,順利地完成Framework的創(chuàng)建玛痊。
比較
可以參考這篇文章.a和.framework.a和.framework的區(qū)別。
我們可以看出.a的封裝和.framework的封裝差不多狂打,也有模擬器和真機合并的過程擂煞,通過上邊的圖片我們可以看出.a 和.framework的區(qū)別,就是.a+.h+soureFile=.framework趴乡《允。可以看出我們直接封裝.framework其實是最好的。那么我們就來看看framework怎么封裝的浙宜。
另外關于.a的封裝大家可以參考iOS如何生成.a文件
目標
本文將基于Xcode7創(chuàng)建一個簡單的工程官辽,通過兩種方法來教大家如何制作一個自己的framework,目的就是簡單易學的制作framework粟瞬。這種方法可以使得你的代碼易分享同仆,在多個工程中復用,并且可以隱藏實現(xiàn)細節(jié)裙品,控制公開的頭文件俗批。
步驟
1、打開Xcode市怎,新建工程岁忘。
不要選擇“Application”,選擇“Framework & Library”区匠。選擇第一個干像,然后Next帅腌。
2、創(chuàng)建功能類麻汰。
這里我創(chuàng)建一個繼承自NSObject的SayHello類
3速客、實現(xiàn)功能。
在新創(chuàng)建的類里面聲明方法并實現(xiàn)五鲫。這里我寫一個sayHello的方法溺职,以便后面測試使用。
4位喂、更改參數(shù)
在TARGETS下選中工程浪耘,在Build Settings下更改幾個參數(shù)。
5塑崖、增加armv7s
? 在Architectures下增加armv7s七冲,并選中。將Build Active Architecture Only 設置為NO弃舒。
6癞埠、設置Headers
將你要公開的頭文件拖至Public下状原,要隱藏的放在Private或者Project下聋呢,當然,隱藏的頭文件就無法再被引用颠区。
然后需要在Test.h(必須是公開的削锰,否則無法引用)中將你所有要公開的.h引入。
打包Framework
第一種方法
1.選中模擬器毕莱,編譯程序
2.選中測試機器贩,編譯程序
3.在finder中找到framework文件
選中圖中所標示的framework,然后右鍵show in finder朋截。
找到下圖中所示的Test文件蛹稍,一個是Debug-iphoneos(真機)下的,一個是Debug-iphonesimulator(模擬器)下的部服。
4.通過終端命令將兩個framework合為一個模擬器和真機都可使用的framework唆姐。
打開控制臺輸入 lipo -create iphoneos下frameworkTest的路徑 simulator下frameworkTest的路徑 -output 新的路徑,這樣就完成了模擬器和真機版本的合并廓八,新路徑下的frameworkTest就是你合并后的文件奉芦,將這個文件名字改成和你未合并之前的Test一樣的名字,放到framework文件夾下剧蹂,替換掉原來的frameworkTest文件声功。
上邊說的亂糟糟的,看不清楚宠叼,這里給大家解釋一下先巴,看下邊的圖:打開終端,手動輸入畫紅線的lipo -create命令,然后綠線是iphoneos下frameworkTest的路徑(找到iphoneos下frameworkTest的文件伸蚯,拖拽進來)醋闭,會自動有空格,紫線是simulator下frameworkTest的路徑(同樣找到simulator下frameworkTest的文件朝卒,拖拽進來)证逻,也會自動有空格,然后輸入-output抗斤,然后敲空格囚企,在引入一個新的路徑(拖拽進一個新的路徑),最后敲回車瑞眼。這樣就完成合并了龙宏。
上面這段命令就是把真機和模擬器的frameworkTest合并成一個MyNewFrameworktest文件并存放在桌面上的New文件夾下。
這里我們合并的時候會遇到一個error伤疙,這是啥原因還真不知道银酗,但是會在和我們-output的文件夾路徑并列的地方生成一個.lipo文件,這個.lipo文件我們下邊會說到徒像。
注意:合并完成后會出現(xiàn)一個如下圖的.lipo格式的文件黍特。
這TM是啥,不是應該出現(xiàn)一個類似下圖的嗎锯蛀?不應該后綴什么也沒有嗎灭衷?怎么后綴會是.lipo,這是什么文件芭缘印翔曲?!
我們的操作是按照人家說的把合成后的文件名字改成MyFrameworkTest替換原來的劈愚。而且瞳遍,把后綴.lipo去掉!
在按照上述說的菌羽,替換了原來的掠械。
然后就可以進行下一步了。
5.將修改后的framework拷貝出來保存算凿,這就是我們最終制作的framework份蝴。
第二種方法
1、選中TARGETS下的工程氓轰,點擊上方的Editor,選擇Add Target創(chuàng)建一個Aggregate.
2婚夫、選擇Other下的Aggregate,點擊Next創(chuàng)建署鸡。
3案糙、嵌入腳本限嫌。選中剛剛創(chuàng)建的Aggregate,然后選中右側的Build Phases,點擊左下方加號,選擇New Run Script Phase
將這段腳本復制進去:
# Sets the target folders and the finalframework product.# 如果工程名稱和Framework的Target名稱不一樣的話时捌,要自定義FMKNAME# 例如: FMK_NAME = "MyFramework"FMK_NAME=${PROJECT_NAME}# Install dir will be the final output tothe framework.# The following line create it in the rootfolder of the current project.? INSTALL_DIR=${SRCROOT}/Products/$? ? ? {FMK_NAME}.framework# Working dir will be deleted after theframework creation.? WRK_DIR=build? DEVICE_DIR=${WRK_DIR}/Release-iphoneos/$? ? ? ? ? ? ? ? ? ? ? ? {FMK_NAME}.framework? SIMULATOR_DIR=${WRK_DIR}/Release-? iphonesimulator/${FMK_NAME}.framework# -configuration ${CONFIGURATION}# Clean and Building both architectures.xcodebuild -configuration"Release"-target"${FMK_NAME}"-sdk iphoneos clean build? xcodebuild -configuration"Release"-target"${FMK_NAME}"-sdk iphonesimulator clean? ? ? ? ?? build# Cleaning the oldest.if[-d"${INSTALL_DIR}"]thenrm -rf"${INSTALL_DIR}"fimkdir -p"${INSTALL_DIR}"cp -R"${DEVICE_DIR}/""${INSTALL_DIR}/"# Uses the Lipo Tool to merge both binaryfiles (i386 + armv6/armv7) into one? ? ?? Universal final product.? lipo -create"${DEVICE_DIR}/${FMK_NAME}""${SIMULATOR_DIR}/${FMK_NAME}"-output"$? ? ? ? ? ? ? ? ? ? ? {INSTALL_DIR}/${FMK_NAME}"rm -r"${WRK_DIR}"open"${INSTALL_DIR}"
這里有一個誤區(qū)怒医,就是復制上邊的這段腳本的時候,會在我們期望的效果里面多了幾個回車奢讨,這幾個回車是致命的稚叹,如果不刪除回車,會報出如下的錯誤:
最后的格式如下圖拿诸,盡量一個回車也不能錯:
通過第一種方法中“把真機和模擬器的frameworkTest合并成一個”的過程和上邊的腳本語言比較扒袖,我們可以發(fā)現(xiàn)其實兩者異路同歸,兩個方法里面同時用到了“l(fā)ipo -create ?xxx”和“-output xxx”亩码,不同的地方是第一種方法需要我們自己真機和模擬器分別變異一遍季率,而且需要我們把framework的路徑拖進去,相比而言第二種方法比較簡單描沟。
4飒泻、編譯。如圖所示吏廉,command+B編譯泞遗。這里Generic iOS Device的意思是“iOS通用設備”,大概就是說模擬器和真機都能用迟蜜。
5刹孔、編譯成功后會自動跳出一個finder,保存這個.framework娜睛,這就是我們需要的framework。
至此卦睹,兩種打包framework的方法介紹完成畦戒!
最后就是用我們的Framework了,倒入另一個Xcode中结序,我們打開這個framework看看障斋,發(fā)現(xiàn)只有Headers,里面有兩個.h徐鹤,其中一個是我們之前添加的FrameworkDemo.h文件垃环,另一個就是我們的SayHello.h 。
然后引入頭文件:
由于我們測試的方法是實例方法返敬,那么我們實例化一個實例對象遂庄,然后就可以讓這個實例對象調取相應的方法了:
至此,完成Framework的制作和使用劲赠。
總結
最后需要注意的是:
1涛目、.h文件的外漏一定要保證是自己的想要外漏的秸谢。不想外漏的就別外漏了。
2霹肝、開始打包的時候估蹄,一定要在選中模擬器和選中真機上邊分別編譯一次, 我覺得之前在家里沒有真機的時候編譯的好像不對沫换。
3臭蚁、在終端上邊合并的時候可能是error并生成一個.lipo文件,不要怕讯赏,大膽修改成同名的不掛后綴的同名文件刊棕。
4、調用的時候分清楚是類方法還是實例方法待逞,方便調用甥角。
5、在制作framework或者lib的時候识樱,如果使用了category嗤无,則使用改FMWK的程序運行時會crash,此時需要在該工程中 other linker flags添加兩個參數(shù) -ObjC -all_load怜庸。(這點沒有親測)
6当犯、帶有圖片資源的需要把圖片打包成Bundle文件,和framework一起拷貝到相應的項目中割疾。
7嚎卫、公開的類中如果引用的private的類,打包以后對外會報錯宏榕,找不到那個private的類拓诸,可以把那個private的.h放到(也沒親測)
8、namespace 沖突麻昼。靜態(tài)庫用了某第三方庫奠支,項目也用了同樣的第三方庫,在編譯的時候就會有 duplicate symbol 錯誤抚芦,因為有兩份同樣的第三方庫倍谜。解決辦法就是把用到的第三方庫加上自定義前綴,包括類名叉抡、delegate 協(xié)議尔崔、常量名,尤其需要注意 Category 的方法名要修改褥民。
9季春、封裝靜態(tài)庫的時候應盡量避免引入重量級第三方庫,多自己進行封裝轴捎。
10鹤盒、一個靜態(tài)庫要有自己獨有的前綴蚕脏,所有類名、常量等都要加同樣的前綴侦锯。
11驼鞭、真機+模擬器支持。(和第2條意思一樣)Xcode 默認只會用當前環(huán)境(真機或模擬器)生成靜態(tài)庫尺碰,這樣的 SDK 不方便其他項目開發(fā)時調試挣棕。解決辦法就是通過腳本生成一份通用庫,build_universal_library.sh亲桥,via SO.
12洛心、文檔。靜態(tài)庫的方便是使用者直接拿你提供的方法來用题篷,無需關注具體實現(xiàn)词身;不方便在于看不到實現(xiàn),出現(xiàn)問題無法排查番枚,因此需要把 SDK 的版本法严、更新歷史、使用葫笼、FAQ 等寫成文檔深啤,方便使用,也顯得 SDK 比較正式規(guī)范路星。
13溯街、圖片等資源文件用 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/.
14九榔、如果 SDK 有用到 Category,注意項目設置 Other Linker Flags 添加 -ObjC涡相。(后邊介紹了-ObjC的作用)
補充
編譯過程:
從C代碼到可執(zhí)行文件經(jīng)歷的步驟是:源代碼 > 預處理器 > 編譯器 > 匯編器 > 機器碼 > 鏈接器 > 可執(zhí)行文件
在最后一步需要把.o文件和C語言運行庫鏈接起來哲泊,這時候需要用到ld命令。源文件經(jīng)過一系列處理以后催蝗,會生成對應的.obj文件切威,然后一個項目必然會有許多.obj文件,并且這些文件之間會有各種各樣的聯(lián)系丙号,例如函數(shù)調用先朦。鏈接器做的事就是把這些目標文件和所用的一些庫鏈接在一起形成一個完整的可執(zhí)行文件缰冤。Other linker flags設置的值實際上就是ld命令執(zhí)行時后面所加的參數(shù)
下面逐個介紹3個常用參數(shù):
-ObjC:加了這個參數(shù)后,鏈接器就會把靜態(tài)庫中所有的Objective-C類和分類都加載到最后的可執(zhí)行文件中
-all_load:會讓鏈接器把所有找到的目標文件都加載到可執(zhí)行文件中喳魏,但是千萬不要隨便使用這個參數(shù)棉浸!假如你使用了不止一個靜態(tài)庫文件,然后又使用了這個參數(shù)刺彩,那么你很有可能會遇到ld: duplicate symbol錯誤迷郑,因為不同的庫文件里面可能會有相同的目標文件,所以建議在遇到-ObjC失效的情況下使用-force_load參數(shù)创倔。
-force_load:所做的事情跟-all_load其實是一樣的嗡害,但是-force_load需要指定要進行全部加載的庫文件的路徑,這樣的話畦攘,你就只是完全加載了一個庫文件霸妹,不影響其余庫文件的按需加載
作者:和玨貓
鏈接:http://www.reibang.com/p/87dbf57cfe4a
來源:簡書
著作權歸作者所有。商業(yè)轉載請聯(lián)系作者獲得授權知押,非商業(yè)轉載請注明出處叹螟。