創建你自己的Framework

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

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

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

非常幸運,這正是本篇教程所要解決的問題。你將會學到製作並使用Framework,幫助你解決這個頭疼的問題。OS X完美地支持這一點,因爲Xcode就提供了一個項目模板,包含着默認構建目標(target)和可以容納類似於圖片、聲音、字體等資源的文件。你可以爲iOS創建Framework,不過這是一個比較複雜的手工活,如果你跟着教程走,你將學到怎麼樣跨過路障,順利地完成Framework的創建。

當你跟着這篇教程走完後,你將能夠:

  • 使用Xcode構建一個基本的靜態庫工程。

  • 依賴於該靜態庫工程構建一款應用。

  • 掌握如何將靜態庫工程轉換爲完整的、合格的Framework。

  • 最終,你將看到如何將一個圖像文件同Framework一起打包到resource bundle下。

開始

這篇教程的主要目的是解釋怎麼樣在你的iOS工程中創建並使用一個Framework。所以,不像其他網站上的教程,這篇教程將只使用一小部分Objective-C代碼,並且這一小部分主要是爲了說明我們將會遇到的一些概念。

這裏下載可用的資源文件RWKnobControl。如果你在Creating a Static Library Project 這篇文章中完成了創建第一個項目的過程,這裏你將會看到怎麼樣使用去它們。

在創建本工程時,你將要創建的所有的代碼和項目文件都可以在Github上找到。對於本篇教程中每個創建階段都有不同的commit。

什麼是Framework?

Framework是資源的集合,將靜態庫和其頭文件包含到一個結構中,讓Xcode可以方便地把它納入到你的項目中。

在OS X上,可能會創建一個動態連接(Dynamically Linked)的framework。通過動態連接,framework可以更新,不需要應用重新連接。在運行時,庫中代碼的一份拷貝被分享出來,整個工程都可以使用它,因此,這樣減少了內存消耗,提高了系統的性能。正如你看到的,這是一個功能強大的特性。

在iOS上,你不能用這種方式添加爲系統添加自定義的framework,因此僅有的動態鏈接的framework只能是Apple提供的那些。(編者注:在iOS 8中已加入此特性,開發者可以使用第三方的動態框架

然而,這並不意味着framework對於iOS而言是無關緊要的,靜態連接的framework依然可以打包代碼,使其在不同的應用中複用。

由於framework本質上是靜態庫的“一站式採購點”,因此在本篇教程中你所做的第一件事就是創建並使用靜態庫。當跟着教程走到如何創建framework時,你就能明白你所做的一切了,整體思路也不會那麼煙霧繚繞了。

創建一個靜態庫工程

打開Xcode,點擊File\New\Project,選擇iOS\Framework and Library\Cocoa Touch Static Library新建一個靜態庫工程.

ios_framework_creating_static_lib-700x482.png

將工程命名爲RWUIControls,然後將工程保存到一個空目錄下。

ios_framework_options_for_static_lib-700x476.png

一個靜態庫工程由頭文件和實現文件組成,這些文件將被編譯爲庫本身。

爲了方便其他開發者使用你的庫和framework,你將進行一些操作,讓他們僅需要導入一個頭文件便可以訪問所有你想公開的類。

當創建靜態庫工程時,Xcode會自動添加RWUIControls.h和RWUIControls.m。你不需要實現文件,因此右鍵單擊RWUIControls.m選擇delete,將它刪除到廢紙簍中。

打開RWUIControls.h,將所有內容替換爲:

1
#import < UIKit/UIKit.h>

導入UIKit的頭文件,這是創建一個庫所需要的。當你在創建不同的組成類時,你將會將它們添加到這個文件中,確保它們能夠被庫的使用者獲取到。

你所構建的項目依賴於UIKit,然而Xcode的靜態庫工程不會自動連接到UIKit。要解決這個問題,就要將UIKit作爲依賴庫添加到工程中。在工程導航欄中選擇工程名,然後在中央面板中選擇RWUIControls目標。

點擊BuildPhases,展開Link Binary with Libraries這一部分,點擊+添加一個新的framework,找到UIKit.framework,點擊add添加進來。

ios_framework_add_uikit_dependency.gif

如果不結合頭文件,靜態庫是沒有用的,靜態庫編譯一組文件,在這些文件中類和方法都以二進制數據的形式存在。在你創建的庫中,有些類將能夠被公開訪問到,有些類只能由庫內部訪問並使用。

接下來,你需要在build欄中添加新的phase,來包含所有頭文件,並將它們放到編譯器可以獲取到的某個地方。然後,你將會拷貝這些到你的framework中。

依然是在Xcode的Build Phases界面,選擇Editor\Add Build Phase\Add Copy Headers Build Phase。

Note:如果你發現按上面找到的菜單項是灰色的(不可點擊的),點擊下方Build Phases界面的白色區域來獲取Xcode的應用焦點,然後重新試一下。

ios_framework_add_copy_headers_build_phase.gif

把RWUIControls.h從項目導航欄中拖到中央面板的Copy Headers下的Public部分。這一步確保任何使用你的庫的用戶均可以獲取該頭文件。

ios_framework_add_header_to_public.gif

Note:顯然,所有包含在你的公共頭文件中的頭文件必須是對外公開的,這一點非常重要。否則,開發者在使用你的庫時會得到編譯錯誤。如果Xcode在讀取公共頭文件時不能讀到你忘記設爲public的頭文件,這實在是太令人沮喪了。

創建一個UI控件

既然你已經設置好你的工程了,是時候爲你的庫添加一些功能了。由於本篇教程的關鍵在於教你怎麼樣創建一個framework,而不是怎麼樣構建一個UI控件,這裏你將使用上一篇教程中創建好的控件。在你之前下載好的壓縮包文件中找到RWKnobControl目錄,從Finder中拖到Xcode下RWUIControls目錄下。

ios_framework_drop_rwuiknobcontrol_from_finder-700x466.png

選擇Copy items into destination group’s folder,點擊下方的選擇框,確保RWUIControls靜態庫目標被選中。

ios_framework_import_settings_for_rwknobcontrol-700x475.png

這一步默認把實現文件添加到編譯列表,把頭文件添加到Project組。這意味着它們目前是私有的。

ios_framework_default_header_membership-700x327.png

Note:在你弄清楚之前,這三個組的名稱可能會讓你迷惑,Public是你期望的,Private下的頭文件依然是可以暴露出來的,因此名字可能有些誤導。諷刺的是,在Project下的頭文件對你的工程來說纔是“私有”的,因此,你將會更多地希望你的頭文件或者在Public下,或者在Project下。

現在,你需要將控件的頭文件RWKnobControl.h分享出來,有幾種方式可以實現這一點,首先是在Copy Headers面板中將這個頭文件從Project欄拖到Public欄。

ios_framework_drag_header_to_public.gif

或者,你可能會發現,更簡單的方法是,編輯文件,改變Target Membership面板下的membership。這個選項更方便一些,可以讓你不斷添加文件,擴充你的庫。

ios_framework_header_membership-407x320.png

Note:如果你不斷往庫中添加新的類,記得及時更新這些類的關係(membership),使盡可能少的類成爲public,並確保其他非public的頭文件都在Project下。

對你的控件的頭文件需要做的另一件事是將其添加到庫的主頭文件RWControls.h中。在這個主頭文件的幫助下,開發者使用你的庫僅僅需要導入一個頭文件,如下面的代碼一樣,而不是自己去選擇自己需要的一塊導入。

1
#import < RWUIControls/RWUIControls.h>

因此,在RWUIControls.h中添加下面的代碼:

1
2
// Knob Control
#import

配置Build Settings

現在距離構建這個項目、創建靜態庫已經非常接近了。不過,這裏要先進行一些配置,讓我們的庫對於用戶來說更友好。

首先,你需要提供一個目錄名,表示你將把拷貝的公共頭文件存放到哪裏。這樣確保當你使用靜態庫的時候可以定位到相關頭文件的位置。

在項目導航欄中點擊項目名,然後選擇RWUIControls靜態庫目標,選擇Build Setting欄,然後搜索public header,雙擊Public Headers Folder Path,在彈出視圖中鍵入如圖所示內容:

ios_framework_public_headers_path-700x174.png

一會你就會看到這個目錄了。

現在你需要改變一些其他的設置,尤其是那些在二進制庫中遺留下的設置,編譯器提供給你一個選項,來消除無效代碼:永遠不會被執行的代碼。當然你也可以移除掉一些debug用符號,例如某些函數名稱或者其他跟debug相關的細節。

因爲你正在創建framework供他人使用,最好禁掉這些功能(無效代碼和debug用符號),讓用戶自己選擇對自己的項目有利的部分使用。和之前一樣,使用搜索框,改變下述設置:

  • Dead Code Stripping設置爲NO

  • Strip Debug Symbol During Copy 全部設置爲NO

  • Strip Style設置爲Non-Global Symbols

編譯然後運行,到目前爲止沒什麼可看的,不過確保項目可以成功構建,沒有錯誤和警報是非常好的。

選擇目標爲iOS Device,按下command + B進行編譯,一旦成功,工程導航欄中Product目錄下libRWUIControls.a文件將從紅色變爲黑色,表明現在該文件已經存在了。右鍵單擊libRWUIControls.a,選擇Show in Finder。

ios_framework_successful_first_build-700x454.png

再此目錄下,你將看到靜態庫,libRWUIControls.a,以及其他你爲頭文件指定的目錄。注意到,正如你所期望的,那些定爲public的頭文件可以在此看到。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章