如何制作支持多平臺的Swift Framework (上)

本文原創(chuàng)明郭,歡迎轉(zhuǎn)載匪煌,但請注明出處

Xcode從6.0開始正式支持Framework類型的工程,之前只能創(chuàng)建Static Library。有些時候某些功能是全平臺(iOS辆脸,macOS,watchOS螃诅,tvOS)通用的啡氢,分別為不同平臺創(chuàng)建工程、維護(hù)代碼當(dāng)然可以术裸,但顯然不是最省力的方式倘是。

本文通過制作一個簡單的純Swift編寫的Framework,教你如何在一個項目中維護(hù)一套代碼袭艺,并同時可以構(gòu)建多個平臺的版本搀崭,最終通過Cocoapods和Carthage發(fā)布。

演示環(huán)境:Xcode 7.3.1猾编, Swift 2.2瘤睹,Carthage 0.17,Cocoapods 1.0.0答倡。

第一步轰传,創(chuàng)建Framework工程:

選擇工程模版,這里選擇iOS\Cocoa Touch Framework作為開始苇羡,其實選擇其他平臺下的Framework模版也可以绸吸,因為最終我們是要在一個工程內(nèi)支持所有平臺;第二步先別勾選Include Unit Tests设江,之后會添加;第三步選擇同時創(chuàng)建Git攘轩。

創(chuàng)建工程

創(chuàng)建之后的目錄結(jié)構(gòu)如下:

自動生成的目錄結(jié)構(gòu)

先稍作下改動以符合即將發(fā)布的Swift Package Manager的要求叉存。將包含Info.plistRandomArithmetics.h的文件夾重命名成Sources,并刪除自動生成的RandomArithmetics.h文件:

修改后的目錄結(jié)構(gòu)

Swift Package Manager規(guī)范要求度帮,代碼文件默認(rèn)放在Sources目錄下歼捏。

關(guān)于自動生成的頭文件(RandomArithmetics.h)的作用。如項目中包含Objective-C的代碼笨篷,那么所有Public的頭文件都需要在該頭文件中聲明瞳秽,然后通過這個頭文件間接暴露給使用者(如下圖所示,RandomArithmetics.h被包含在了Build Phases/Headers/Public里)率翅。但因為Swift這門語言代碼本身不使用頭文件.h與實現(xiàn)文件.m來控制“能見度”练俐,接口的開放程度完全由關(guān)鍵字(public, internal, private)控制,因此編譯器有足夠的信息生成訪問控制代碼冕臭,所以不需要這個文件腺晾。

默認(rèn)生成的頭文件

回到Xcode燕锥,因為我們直接修改了目錄結(jié)構(gòu),所以有些文件變紅了悯蝉,需要刪除后重新添加一下:刪除Info.plistRandomArithmetics.h归形,RandomArithmetics group重命名成Sources,之后再把Info.plist添加回來鼻由,最后別忘了更正Build Settings/Info.plist File的值暇榴,使其重新指向正確的相對路徑。

最后編譯(?+B)一下工程蕉世,正常的話Products下的RandomArithmetics.framework將會由紅變黑說明編譯成功蔼紧。

修復(fù)前的工程布局
修復(fù)后的工程布局

第二步,添加代碼

我們要實現(xiàn)的功能很簡單讨彼,隨機(jī)生成20以內(nèi)的自然數(shù)加減法運(yùn)算和乘法口訣問題歉井。這里對不同平臺的功能作以下規(guī)定:

iOS: 支持生成全部類型的問題

macOS:只支持生成20以內(nèi)的加法運(yùn)算問題

watchOS:只支持生成乘法口訣問題

tvOS:只支持生成20以內(nèi)的減法運(yùn)算問題

向工程中添加第一個源文件:ArithmeticProblem.swift,內(nèi)容如下:

ArithmeticProblem.swift

文件中定義了一個表示運(yùn)算符的enum:Operator和一個表示運(yùn)算問題的struct:ArithmeticProblem哈误,二者都是public的哩至,因為要對外可見。

添加后文件與RandomArithmetics Target關(guān)聯(lián)

包含ArithmeticProblem.swift的工程布局

添加第二個源文件GenerateProblem.swift蜜自,同樣也與RandomArithmetics?Target關(guān)聯(lián)

GenerateProblem.swift

文件中定義了三個public函數(shù)分別隨機(jī)返回20以內(nèi)加法菩貌、乘法口訣、20以內(nèi)減法問題重荠。

包含GenerateProblem.swift的工程布局

編譯(?+B)一下工程箭阶,看是否可以編譯成功。

接下來添加些Unit Tests驗證代碼邏輯戈鲁。

第三步仇参,添加Unit Tests

創(chuàng)建工程的時候我們故意沒有選擇包含Unit Tests,之后只需添加Unit Test Target即可婆殿,我們選擇iOS\iOS Unit Testing Bundle诈乒,因為目前我們只有一個Cocoa Touch Framework Target等待測試。這是我們的第一個Testing Bundle婆芦,先暫且起一個通用的名字“Tests”怕磨,因為Xcode會用這個名字幫我們生成目錄和文件,我們希望Test的代碼也要復(fù)用消约,因此這么做能省事一些肠鲫。

添加第一個Unit Tests Bundle

之后工程布局和目錄結(jié)構(gòu)將會如下:

添加Unit Test Target之后的工程布局
添加Unit Test Target之后的目錄結(jié)構(gòu)

接下來把Tests Target重命名成更容易辨識的名稱,如:RandomArithmetics iOSTest或粮。

重命名Tests Target

切換到“Test navigator”导饲,試運(yùn)行一把看看正不正常。

Unit Tests試運(yùn)行

接下先添加一個第三方Framework:Quick/Nimble用于方便做Assertion,同時也演示如何用Carthage管理項目依賴帜消。

首先在項目根目錄下添加一個文本文件Cartfile.private棠枉,內(nèi)容如下:

github "Quick/Nimble" ~> 4.1.0

一般將測試代碼里用到的第三方Framework聲明在Cartfile.private里,當(dāng)我們被當(dāng)成依賴使用時聲明在Cartfile.private里的內(nèi)容不會被下載泡挺。

打開Terminal, cd到項目根目錄辈讶,運(yùn)行以下命令:

$ carthage update

完成后,在項目根目錄下會出現(xiàn)個Carthage文件夾娄猫,包含了Checkouts和Build兩個字目錄:

Carthage Update后的目錄結(jié)構(gòu)

Checkouts目錄里是Quick/Nimble的工程源碼贱除,Build目錄里是Nimble在三個不同平臺的編譯輸出。接下來我們需要手動的將Nimble添加到工程當(dāng)中媳溺。有兩種方式:

第一種月幌,直接使用Build目錄下的已生成的Framework,具體如何操作不同平臺略有差別悬蔽,請移步官方文檔扯躺。

第二種,將第三方Framework的源碼直接納入統(tǒng)一個xcode workspace蝎困,共同編譯录语。這樣在調(diào)試的時候可以直接步入源碼。我們使用第二種方式禾乘。

回到Xcode工程澎埠,在"File"菜單下選擇"Save As Workspace...",在彈出的對話框中給workspace取項目同名:RandomArithmetics, 并在項目根目錄保存始藕。

Save As Workspace

然后關(guān)閉工程蒲稳,打開workspace,將Nimble.xcodeproj拖入到Xcode中伍派,使之與RandomArithmetics成為并列項目江耀。

向workspace中添加Nimble

接下來在RandomArithmetics iOSTests Target的“Build Phases/Link Binary With Libraries”中添加對iOS版Nimble.Framework的引用。

添加對Nimble的編譯鏈接

設(shè)置完畢后就可以添加測試代碼了诉植,如下圖所示决记,代碼很簡單共三個測試方法分別測試三個函數(shù)的邏輯,這里我們使用了Nimble的Assertion寫法:

測試方法

切換到Test Navigator后運(yùn)行測試(?+U)倍踪,如果你跟著做到現(xiàn)在的話會看到測試都通過了,Great!

運(yùn)行測試結(jié)果

且慢索昂!雖然測試通過但出現(xiàn)了一個??建车,點(diǎn)開看看是什么情況:

??

問題出現(xiàn)在Link階段,給Linker指定的某個搜索鏈接對象的目錄不存在椒惨,這個路徑是在"Build Settings/Search Paths/Framework Search Paths"里指定的缤至,是在我們手動添加Nimble.Framework到"Build Phases/Link Binary With Libraries"時Xcode幫我們自動加上的,Xcode根據(jù)Nimble的"Build Settings/Build Locations/Per-configuration Build Products Path"中的值結(jié)合Nimble項目的位置生成了這個路徑:

自動添加的Framework Search Path

Xcode這么做無可厚非康谆,它假設(shè)我們可能會把編譯的結(jié)果輸出到這個目錄领斥,但實際最終編譯輸出到哪還受Xcode "Derived Data Location"設(shè)置的影響嫉到。默認(rèn)情況每個Xcode打開窗口(Xcode Session,可以是單個xcodeproj也可以是xcworkspace)會被隨機(jī)分配一個唯一的輸出目錄(Derived Data Location月洛,Window->Projects可以打開查看這個目錄)何恶。

查看Derived Data Location

可以看到所有Target的編譯結(jié)果都輸出到同一個目錄下了,因此即便這個路徑不存在嚼黔,Linker還是可以在當(dāng)前目錄找到鏈接對象细层。所以解決這個??最簡單的辦法就是刪掉這個路徑,另外一個方法是指向一個真實存在的輸出路徑唬涧,做個雙保險疫赎。正巧我們使用的Carthage會把編譯結(jié)果輸出到固定的相對路徑:$(PROJECT_DIR)/Carthage/Build/PLATFORMPLATFORM可以是 iOS碎节、Mac捧搞、watchOS、tvOS四者之一狮荔,所以把這個路徑添加到“Build Settings/Search Paths/Framework Search Paths”下正合適胎撇。

設(shè)置正確的Search Path

接著再運(yùn)行測試(?+U)就一切正常了。

到目前為止轴合,我們已經(jīng)實現(xiàn)了iOS版RandomArithmetics Framework的功能创坞,在下一篇中我們將介紹如何添加對多平臺版本的支持,以及最后如何通過Cocoapods和Carthage發(fā)布受葛。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末题涨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子总滩,更是在濱河造成了極大的恐慌纲堵,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闰渔,死亡現(xiàn)場離奇詭異席函,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)冈涧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門茂附,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人督弓,你說我怎么就攤上這事营曼。” “怎么了愚隧?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵蒂阱,是天一觀的道長。 經(jīng)常有香客問我,道長录煤,這世上最難降的妖魔是什么鳄厌? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮妈踊,結(jié)果婚禮上了嚎,老公的妹妹穿的比我還像新娘。我一直安慰自己响委,他們只是感情好新思,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赘风,像睡著了一般夹囚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上邀窃,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天荸哟,我揣著相機(jī)與錄音,去河邊找鬼瞬捕。 笑死鞍历,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的肪虎。 我是一名探鬼主播劣砍,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼扇救!你這毒婦竟也來了刑枝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤迅腔,失蹤者是張志新(化名)和其女友劉穎装畅,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體沧烈,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掠兄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了锌雀。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蚂夕。...
    茶點(diǎn)故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖腋逆,靈堂內(nèi)的尸體忽然破棺而出双抽,到底是詐尸還是另有隱情,我是刑警寧澤闲礼,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響柬泽,放射性物質(zhì)發(fā)生泄漏慎菲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一锨并、第九天 我趴在偏房一處隱蔽的房頂上張望露该。 院中可真熱鬧,春花似錦第煮、人聲如沸解幼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽撵摆。三九已至,卻和暖如春害晦,著一層夾襖步出監(jiān)牢的瞬間特铝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工壹瘟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鲫剿,地道東北人。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓稻轨,卻偏偏與公主長得像灵莲,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子殴俱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評論 2 360

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