本文原創(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)建之后的目錄結(jié)構(gòu)如下:
先稍作下改動以符合即將發(fā)布的Swift Package Manager的要求叉存。將包含Info.plist和RandomArithmetics.h的文件夾重命名成Sources,并刪除自動生成的RandomArithmetics.h文件:
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)控制,因此編譯器有足夠的信息生成訪問控制代碼冕臭,所以不需要這個文件腺晾。
回到Xcode燕锥,因為我們直接修改了目錄結(jié)構(gòu),所以有些文件變紅了悯蝉,需要刪除后重新添加一下:刪除Info.plist和RandomArithmetics.h归形,RandomArithmetics group重命名成Sources,之后再把Info.plist添加回來鼻由,最后別忘了更正Build Settings/Info.plist File的值暇榴,使其重新指向正確的相對路徑。
最后編譯(?+B)一下工程蕉世,正常的話Products下的RandomArithmetics.framework將會由紅變黑說明編譯成功蔼紧。
第二步,添加代碼
我們要實現(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)容如下:
文件中定義了一個表示運(yùn)算符的enum:Operator和一個表示運(yùn)算問題的struct:ArithmeticProblem哈误,二者都是public的哩至,因為要對外可見。
添加后文件與RandomArithmetics Target關(guān)聯(lián)
添加第二個源文件GenerateProblem.swift蜜自,同樣也與RandomArithmetics?Target關(guān)聯(lián)
文件中定義了三個public函數(shù)分別隨機(jī)返回20以內(nèi)加法菩貌、乘法口訣、20以內(nèi)減法問題重荠。
編譯(?+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ù)用消约,因此這么做能省事一些肠鲫。
之后工程布局和目錄結(jié)構(gòu)將會如下:
接下來把Tests Target重命名成更容易辨識的名稱,如:RandomArithmetics iOSTest或粮。
切換到“Test navigator”导饲,試運(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兩個字目錄:
Checkouts目錄里是Quick/Nimble的工程源碼贱除,Build目錄里是Nimble在三個不同平臺的編譯輸出。接下來我們需要手動的將Nimble添加到工程當(dāng)中媳溺。有兩種方式:
第一種月幌,直接使用Build目錄下的已生成的Framework,具體如何操作不同平臺略有差別悬蔽,請移步官方文檔扯躺。
第二種,將第三方Framework的源碼直接納入統(tǒng)一個xcode workspace蝎困,共同編譯录语。這樣在調(diào)試的時候可以直接步入源碼。我們使用第二種方式禾乘。
回到Xcode工程澎埠,在"File"菜單下選擇"Save As Workspace...",在彈出的對話框中給workspace取項目同名:RandomArithmetics, 并在項目根目錄保存始藕。
然后關(guān)閉工程蒲稳,打開workspace,將Nimble.xcodeproj拖入到Xcode中伍派,使之與RandomArithmetics成為并列項目江耀。
接下來在RandomArithmetics iOSTests Target的“Build Phases/Link Binary With Libraries”中添加對iOS版Nimble.Framework的引用。
設(shè)置完畢后就可以添加測試代碼了诉植,如下圖所示决记,代碼很簡單共三個測試方法分別測試三個函數(shù)的邏輯,這里我們使用了Nimble的Assertion寫法:
切換到Test Navigator后運(yùn)行測試(?+U)倍踪,如果你跟著做到現(xiàn)在的話會看到測試都通過了,Great!
且慢索昂!雖然測試通過但出現(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項目的位置生成了這個路徑:
Xcode這么做無可厚非康谆,它假設(shè)我們可能會把編譯的結(jié)果輸出到這個目錄领斥,但實際最終編譯輸出到哪還受Xcode "Derived Data Location"設(shè)置的影響嫉到。默認(rèn)情況每個Xcode打開窗口(Xcode Session,可以是單個xcodeproj也可以是xcworkspace)會被隨機(jī)分配一個唯一的輸出目錄(Derived Data Location月洛,Window->Projects可以打開查看這個目錄)何恶。
可以看到所有Target的編譯結(jié)果都輸出到同一個目錄下了,因此即便這個路徑不存在嚼黔,Linker還是可以在當(dāng)前目錄找到鏈接對象细层。所以解決這個??最簡單的辦法就是刪掉這個路徑,另外一個方法是指向一個真實存在的輸出路徑唬涧,做個雙保險疫赎。正巧我們使用的Carthage會把編譯結(jié)果輸出到固定的相對路徑:$(PROJECT_DIR)/Carthage/Build/PLATFORM,PLATFORM可以是 iOS碎节、Mac捧搞、watchOS、tvOS四者之一狮荔,所以把這個路徑添加到“Build Settings/Search Paths/Framework Search Paths”下正合適胎撇。
接著再運(yùn)行測試(?+U)就一切正常了。
到目前為止轴合,我們已經(jīng)實現(xiàn)了iOS版RandomArithmetics Framework的功能创坞,在下一篇中我們將介紹如何添加對多平臺版本的支持,以及最后如何通過Cocoapods和Carthage發(fā)布受葛。