基于 Cookiecutter 打造 iOS 項(xiàng)目模版

所有文章已搬遷到個(gè)人站點(diǎn):me.harley-xk.studio,歡迎訪問留言

前言

每次新創(chuàng)建一個(gè)項(xiàng)目,我們總是要做這些事情:創(chuàng)建項(xiàng)目、初始化 pod、安裝 pod、配置工程、寫(或者引入)一些框架性的代碼。當(dāng)項(xiàng)目寫的多了,會(huì)發(fā)現(xiàn)這里面基本上是大量的重復(fù)勞動(dòng),每次要做的事情幾乎是一樣的,但是又不可避免。特別是當(dāng)有時(shí)候想寫一些玩具性質(zhì)的小項(xiàng)目時(shí),創(chuàng)建項(xiàng)目所使用的勞動(dòng)量相比就更加明顯了。

其實(shí)可以看出來,以上這些工作其實(shí)都屬于模版性質(zhì)的,如果我們能夠先編輯好一個(gè)項(xiàng)目模版,然后每次都基于這個(gè)模版創(chuàng)建新項(xiàng)目的話就好了。其實(shí) Xcode 本身就提供了模版功能,多年前我也曾基于 Xcode 的模版功能做過一些簡單的文件模版和項(xiàng)目模版。但是 Xcode 模版配置比較繁瑣,并且官方的文檔基本找不到(也可能是我沒認(rèn)真找)。

那么有沒有什么別的好辦法呢?這就引出這次要說的主角了:Cookiecutter

簡介

Cookiecutter 是一個(gè)用 Python 開發(fā)的項(xiàng)目模版工具,在 Github 上可以找到它的源碼,這個(gè)項(xiàng)目目前已經(jīng)有將近一萬個(gè) star 了。

Cookiecutter 并不是一個(gè) iOS 專用的工具,它的支持相當(dāng)廣泛,基本上所有主流的項(xiàng)目方案都可以使用它來建立模版,這源于它十分簡單粗暴的實(shí)現(xiàn)原理:先創(chuàng)建一個(gè)項(xiàng)目框架作為模版,將項(xiàng)目名稱等一系列參數(shù)以關(guān)鍵字的方式在配置文件中指定好,然后新建項(xiàng)目時(shí)根據(jù)配置好的模版參數(shù),替換模版中所有目錄和子目錄的名稱,以及所有文本中匹配到的關(guān)鍵字。當(dāng)然了,Cookiecutter 還有很多高級(jí)用法,可以去查詢它的文檔。

這篇文章只是拋磚引玉,介紹一下我基于 Cookiecutter 創(chuàng)建一個(gè)簡單的 App 模版的過程。

安裝

首先需要安裝 Cookiecutter,針對(duì)不同的平臺(tái)和環(huán)境,Cookiecutter 提供了相當(dāng)多的安裝方式。不過 iOS 開發(fā)者基本都在 macOS 環(huán)境下工作,所以其他的就略過了。

mac 下官方推薦使用 Homebrew 來安裝:

brew install Cookiecutter

整個(gè)安裝過程都是自動(dòng)的,非常簡單。

創(chuàng)建模版

新建項(xiàng)目

首先我們需要?jiǎng)?chuàng)建一個(gè)模版:打開 Xcode,新建一個(gè)單頁應(yīng)用。


新建單頁應(yīng)用

點(diǎn)擊 'next', 然后將對(duì)應(yīng)屬性設(shè)置為 template 關(guān)鍵字,如下圖所示:

  • Product Name: {{cookiecutter.product_name}}
  • Organization Name: {{cookiecutter.organization_name}}
  • Organization Identifier: {{cookiecutter.organization_identifier}}
創(chuàng)建項(xiàng)目

然后點(diǎn)擊 next 創(chuàng)建項(xiàng)目,項(xiàng)目創(chuàng)建完畢后,打開 info.plist,將 Bundle identifier 指定為 com.{{cookiecutter.organization_identifier}}.{{cookiecutter.product_name}} 否則 Xcode 默認(rèn)會(huì)將 {} 替換為 -,導(dǎo)致后續(xù)創(chuàng)建項(xiàng)目時(shí)替換失敗。

配置文件

接下來,在與剛創(chuàng)建完畢的項(xiàng)目根目錄同級(jí),也就是 {{cookiecutter.product_name}} 文件夾所在的目錄,創(chuàng)建一個(gè) cookiecutter.json 文件,內(nèi)容如下:

{
    "product_name": "Hello",
    "organization_name": "Someone Co.,Ltd.",
    "organization_identifier": "someone"
}

JSON 中的 key 就是我們剛才創(chuàng)建項(xiàng)目時(shí)填寫的那幾個(gè)用雙括號(hào)包含起來的名稱,并且去掉 cookiecutter 前綴,key 對(duì)應(yīng)的值表示默認(rèn)值。使用 Cookiecutter 從模版創(chuàng)建項(xiàng)目時(shí),它會(huì)詢問配置文件中的這幾個(gè) key,讓我們給它指定名稱,如果不指定,則使用配置文件中的默認(rèn)值。

另外,需要哪些 key,以及 key 的名稱是不固定的,你可以根據(jù)自己的需要自己定義任意數(shù)量的 key,只要保證在模版項(xiàng)目中使用相同的名稱,并且需要帶上 cookiecutter 前綴。

至此,一個(gè)最簡單的項(xiàng)目模版就創(chuàng)建完了,你也可以根據(jù)自己的需要給這個(gè)項(xiàng)目添加一些額外的代碼,新建項(xiàng)目時(shí)所有額外添加的內(nèi)容都將原樣保留。

鉤子

上面創(chuàng)建的項(xiàng)目非常簡單,但是我們實(shí)際開發(fā)中一般都需要使用 Cocoapods 來管理第三方依賴,并且有些庫幾乎是所有項(xiàng)目都需要用到的,比如 Alamofire、SnapKit 等等。那么能不能通過模版一并完成 pods 的配置和安裝呢?

這就可以用上 Cookiecutter 的鉤子功能了,鉤子通俗一點(diǎn)講也叫回調(diào),可以在某些特性情況下觸發(fā)一些事件,執(zhí)行一些操作等。

Cookiecutter 的鉤子配置非常簡單,只需要在配置文件同級(jí)目錄下新建一個(gè) hooks 目錄,然后將寫好的腳本放在該目錄中,Cookiecutter 會(huì)自動(dòng)調(diào)用。

目前 Cookiecutter 支持兩個(gè)事件,即創(chuàng)建項(xiàng)目之前和創(chuàng)建項(xiàng)目完成之后,會(huì)分別調(diào)用對(duì)應(yīng)的腳本文件,目前支持 shell 腳本和 python 腳本。在安裝前調(diào)用的腳本需要命名為 pre_gen_project.sh 或者 pre_gen_project.py;同樣的,在安裝之后調(diào)用的腳本需要命名為 post_gen_project.sh 或者 post_gen_project.py,取決于腳本使用的語言。

自動(dòng)安裝 pods

首先需要在項(xiàng)目目錄下,即 {{cookiecutter.product_name}}/ 目錄下創(chuàng)建 Podfile 文件,并配置好常用的依賴庫:

target '{{cookiecutter.product_name}}' do

  use_frameworks!

  # Pods for {{cookiecutter.product_name}}

  # Networking
  pod 'Alamofire'
  # ImageCache
  pod 'Kingfisher'
  # AutoLayout
  pod 'SnapKit'

end

好了,不要執(zhí)行 pod install,因?yàn)檫@只是個(gè)模版,可能實(shí)際創(chuàng)建項(xiàng)目時(shí)這些庫已經(jīng)更新了,所以需要在創(chuàng)建項(xiàng)目時(shí)才安裝依賴。

接下來打開 post_gen_project.sh, 寫上 pod 安裝相關(guān)的命令:

#!/bin/bash
GREEN='\033[0;32m'
echo -e "${GREEN}Project successfuly generated!"
echo -e "${GREEN}Installing Pods..."
pod install
echo -e "${GREEN}Pods Install Finished"

其實(shí)只需要寫一句 pod install 就夠了,不過為了創(chuàng)建項(xiàng)目時(shí)命令行的輸出內(nèi)容能夠更加友好,我添加了一些額外的狀態(tài)輸出的內(nèi)容,你也可以在其中添加一些其他需要處理的事務(wù)。

這時(shí)候我們的項(xiàng)目框架才算基本完成。此時(shí),我們的項(xiàng)目模版目錄應(yīng)該是類似下面這樣:

ios_template/
├── {{cookiecutter.product_name}}/
│   ├── {{cookiecutter.product_name}}.xcodeproj
│   ├── Podfile
│   └── ...
├── hooks
│   ├── pre_gen_project.sh
│   └── post_gen_project.sh
└── cookiecutter.json

使用

分發(fā)模版

模版做完了,放到哪里呢?本地目錄也是可以的,Cookiecutter 支持從任何可以訪問的路徑加載項(xiàng)目模版,不過為了方便使用和團(tuán)隊(duì)共享,最好是將模版推送到 git 倉庫中,這樣也方便后期修改以及多人維護(hù)等。

另外,如果你的模版項(xiàng)目非常大,也可以打包成 zip 上傳,Cookiecutter 支持從 zip 包創(chuàng)建項(xiàng)目,創(chuàng)建時(shí)會(huì)自動(dòng)解壓。

創(chuàng)建項(xiàng)目

創(chuàng)建項(xiàng)目也非常簡單,確保 Cookiecutter 已經(jīng)正確安裝后,只需要 cd 到你準(zhǔn)備創(chuàng)建項(xiàng)目的目錄,然后執(zhí)行以下命令就好了:

cookiecutter https://github.com/Harley-xk/iOS_Template_Comet.git

后面的路徑可以是本地路徑也可以是遠(yuǎn)程路徑,可以是 git,也可以是 zip。Cookiecutter 還支持很多其他的倉庫形式,詳細(xì)可以查看它的文檔。

命令執(zhí)行后就開始創(chuàng)建項(xiàng)目了,Cookiecutter 會(huì)對(duì)你在配置文件中設(shè)置的每一個(gè)關(guān)鍵字進(jìn)行詢問,你可以輸入新項(xiàng)目需要使用的值,或者也可以直接回車后使用默認(rèn)值。

可以看到命令行的輸出如下:

創(chuàng)建項(xiàng)目

Cookiecutter 會(huì)在用戶目錄下緩存所有安裝過的項(xiàng)目模版,下次安裝時(shí)會(huì)詢問你是否需要更新模版:

You've downloaded /Users/Harley-xk/.cookiecutters/iOS_Template_Comet before. Is it okay to delete and re-download it?

輸入 yes,它會(huì)自動(dòng)更新模版后創(chuàng)建項(xiàng)目。

另外可以看到在創(chuàng)建項(xiàng)目之后 pod install 指令也自動(dòng)執(zhí)行了,我們在 Podfile 里面指定的三個(gè)依賴庫都已經(jīng)成功安裝了。可以進(jìn)入 MyApp 目錄下面,打開 MyApp.xcworkspace 查看創(chuàng)建完畢的項(xiàng)目:

創(chuàng)建完畢的項(xiàng)目

結(jié)束語

其實(shí)可以發(fā)現(xiàn) Cookiecutter 的原理和使用都非常簡單?,F(xiàn)在項(xiàng)目越做越龐大,架構(gòu)也越來越復(fù)雜,雖然我們可以通過組件化的方式最大化的重用代碼,減少工作量,但是依然需要寫大量的膠水代碼來整合各個(gè)組件,做大量的項(xiàng)目配置、項(xiàng)目初始化的工作,通過使用 Cookiecutter,可以進(jìn)一步節(jié)省大量的工作。

ps. 我在 Github 上創(chuàng)建了我自己的 iOS 項(xiàng)目模版,你如果不想自己寫,也可以使用我的模版:https://github.com/Harley-xk/iOS_Template_Comet.git

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容