iOS封裝功能產生 .framework

來源:互聯網
上載者:User

標籤:rsa   兩種方法   源檔案   目的   contents   apt   targe   class   medium   

前言

      如果你想將你開發的控制項與別人分享,一種方法是直接提供原始碼檔案。然而,這種方法並不是很優雅。它會暴露所有的實現細節,而這些實現你可能並不想開源出來。此外,開發人員也可能並不想看到你的所有代碼,因為他們可能僅僅希望將你的這份漂亮代碼的一部分植入自己的應用中。

      另一種方法是將你的代碼編譯成靜態庫(library),讓其他開發人員添加到自己的項目中。然而,這需要你一併公布所有的公開的標頭檔,實在是非常不方便。

你需要一種簡單的方法來編譯你的代碼,這種方法應該使得你的代碼易分享,並且在多個工程中易複用。你需要的是一種方法來打包你的靜態庫,將所有的標頭檔放到一個單元中,這樣你就可以立刻將其加入到你的項目中並使用。

      OS X完美地支援這一點,因為Xcode就提供了一個項目模板,包含著預設構建目標(target)和可以容納類似於圖片、聲音、字型等資源的檔案。你可以為iOS建立Framework,不過這是一個比較複雜的手工活,如果你跟著教程走,你將學到怎麼樣跨過路障,順利地完成Framework的建立。

比較

可以參考這篇文章.a和.framework.a和.framework的區別。


 

我們可以看出.a的封裝和.framework的封裝差不多,也有模擬器和真機合并的過程,通過上邊的圖片我們可以看出.a 和.framework的區別,就是.a+.h+soureFile=.framework。可以看出我們直接封裝.framework其實是最好的。那麼我們就來看看framework怎麼封裝的。

另外關於.a的封裝大家可以參考iOS如何產生.a檔案

目標

      本文將基於Xcode7建立一個簡單的工程,通過兩種方法來教大家如何製作一個自己的framework,目的就是簡單易學的製作framework。這種方法可以使得你的代碼易分享,在多個工程中複用,並且可以隱藏實現細節控制公開的標頭檔

步驟

1、開啟Xcode,建立工程。

不要選擇“Application”,選擇“Framework & Library”。選擇第一個,然後Next。


 

2、建立功能類。

這裡我建立一個繼承自NSObject的SayHello類

3、實現功能。

在新建立的類裡面聲明方法並實現。這裡我寫一個sayHello的方法,以便後面測試使用。


 

4、更改參數

在TARGETS下選中工程,在Build Settings下更改幾個參數。


 

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檔案我們下邊會說到。


 
 

注意:合并完成後會出現一個如的.lipo格式的檔案。


 

這TM是啥,不是應該出現一個類似的嗎?不應該尾碼什麼也沒有嗎?怎麼尾碼會是.lipo,這是什麼檔案啊?!


 

我們的操作是按照人家說的把合成後的檔案名稱字改成MyFrameworkTest替換原來的。而且,把尾碼.lipo去掉!

在按照上述說的,替換了原來的。

然後就可以進行下一步了。

5.將修改後的framework拷貝出來儲存,這就是我們最終製作的framework。

第二種方法

1、選中TARGETS下的工程,點擊上方的Editor,選擇Add Target建立一個Aggregate.


 

2、選擇Other下的Aggregate,點擊Next建立。


 

3、嵌入指令碼。選中剛剛建立的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}"

這裡有一個誤區,就是複製上邊的這段指令碼的時候,會在我們期望的效果裡面多了幾個斷行符號,這幾個斷行符號是致命的,如果不刪除斷行符號,會報出如下的錯誤:


 
 

最後的格式如,盡量一個斷行符號也不能錯:


 

通過第一種方法中“把真機和模擬器的frameworkTest合并成一個”的過程和上邊的指令碼語言比較,我們可以發現其實兩者異路同歸,兩個方法裡面同時用到了“lipo -create  xxx”和“-output xxx”,不同的地方是第一種方法需要我們自己真機和模擬器分別變異一遍,而且需要我們把framework的路徑拖進去,相比而言第二種方法比較簡單。

4、編譯。,command+B編譯。這裡Generic iOS Device的意思是“iOS通用裝置”,大概就是說模擬器和真機都能用。


 

5、編譯成功後會自動跳出一個finder,儲存這個.framework,這就是我們需要的framework。


 

至此,兩種打包framework的方法介紹完成!

 

 

最後就是用我們的Framework了,倒入另一個Xcode中,我們開啟這個framework看看,發現只有Headers,裡面有兩個.h,其中一個是我們之前添加的FrameworkDemo.h檔案,另一個就是我們的SayHello.h 。


 

然後引入標頭檔:


 

由於我們測試的方法是執行個體方法,那麼我們執行個體化一個執行個體對象,然後就可以讓這個執行個體對象調取相應的方法了:


 

至此,完成Framework的製作和使用。

 

總結

最後需要注意的是:

1、.h檔案的外漏一定要保證是自己的想要外漏的。不想外漏的就別外漏了。

2、開始打包的時候,一定要在選中模擬器和選中真機上邊分別編譯一次, 我覺得之前在家裡沒有真機的時候編譯的好像不對。

3、在終端上邊合并的時候可能是error並產生一個.lipo檔案,不要怕,大膽修改成同名的不掛尾碼的同名檔案。

4、調用的時候分清楚是類方法還是執行個體方法,方便調用。

5、在製作framework或者lib的時候,如果使用了category,則使用改FMWK的程式運行時會crash,此時需要在該工程中 other linker flags添加兩個參數 -ObjC -all_load。(這點沒有親測)

6、帶有圖片資源的需要把圖片打包成Bundle檔案,和framework一起拷貝到相應的項目中。

7、公開的類中如果引用的private的類,打包以後對外會報錯,找不到那個private的類,可以把那個private的.h放到(也沒親測)

8、namespace 衝突。靜態庫用了某第三方庫,項目也用了同樣的第三方庫,在編譯的時候就會有 duplicate symbol 錯誤,因為有兩份同樣的第三方庫。解決辦法就是把用到的第三方庫加上自訂首碼,包括類名、delegate 協議、常量名,尤其需要注意 Category 的方法名要修改。

9、封裝靜態庫的時候應盡量避免引入重量級第三方庫,多自己進行封裝

10、一個靜態庫要有自己專屬的首碼,所有類名、常量等都要加同樣的首碼。

11、真機+模擬器支援。(和第2條意思一樣)Xcode 預設只會用當前環境(真機或模擬器)產生靜態庫,這樣的 SDK 不方便其他項目開發時調試。解決辦法就是通過指令碼產生一份通用庫,build_universal_library.sh,via SO.

12、文檔。靜態庫的方便是使用者直接拿你提供的方法來用,無需關注具體實現;不方便在於看不到實現,出現問題無法排查,因此需要把 SDK 的版本、更新歷史、使用、FAQ 等寫成文檔,方便使用,也顯得 SDK 比較正式規範。

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代碼到可執行檔經曆的步驟是:原始碼 > 前置處理器 > 編譯器 > 彙編器 > 機器碼 > 連結器 > 可執行檔

在最後一步需要把.o檔案和C語言運行庫連結起來,這時候需要用到ld命令。源檔案經過一系列處理以後,會產生對應的.obj檔案,然後一個項目必然會有許多.obj檔案,並且這些檔案之間會有各種各樣的聯絡,例如函數調用。連結器做的事就是把這些目標檔案和所用的一些庫連結在一起形成一個完整的可執行檔。Other linker flags設定的值實際上就是ld命令執行時後面所加的參數

下面逐個介紹3個常用參數:

-ObjC:加了這個參數後,連結器就會把靜態庫中所有的Objective-C類和分類都載入到最後的可執行檔中

-all_load:會讓連結器把所有找到的目標檔案都載入到可執行檔中,但是千萬不要隨便使用這個參數!假如你使用了不止一個靜態庫檔案,然後又使用了這個參數,那麼你很有可能會遇到ld: duplicate symbol錯誤,因為不同的庫檔案裡面可能會有相同的目標檔案,所以建議在遇到-ObjC失效的情況下使用-force_load參數。

-force_load:所做的事情跟-all_load其實是一樣的,但是-force_load需要指定要進行全部載入的庫檔案的路徑,這樣的話,你就只是完全載入了一個庫檔案,不影響其餘庫檔案的按需載入

 

後期會試著把貝塞爾畫餅的demo封裝成framework,另外可能會增加Bundle檔案的產生方法。

參考自1、iOS-製作Framework(最新)

          2、iOS--建立你自己的Framework

 

最後,哪裡不對的地方可以給我留言,我會及時改進的,謝謝大家。



和玨貓
連結:http://www.jianshu.com/p/87dbf57cfe4a
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

iOS封裝功能產生 .framework

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.