基于 Cookiecutter 打造 iOS 项目模版

所有文章已搬迁到个人站点:me.harley-xk.studio,欢迎访问留言

前言

每次新创建一个项目,我们总是要做这些事情:创建项目、初始化 pod、安装 pod、配置工程、写(或者引入)一些框架性的代码。当项目写的多了,会发现这里面基本上是大量的重复劳动,每次要做的事情几乎是一样的,但是又不可避免。特别是当有时候想写一些玩具性质的小项目时,创建项目所使用的劳动量相比就更加明显了。

其实可以看出来,以上这些工作其实都属于模版性质的,如果我们能够先编辑好一个项目模版,然后每次都基于这个模版创建新项目的话就好了。其实 Xcode 本身就提供了模版功能,多年前我也曾基于 Xcode 的模版功能做过一些简单的文件模版和项目模版。但是 Xcode 模版配置比较繁琐,并且官方的文档基本找不到(也可能是我没认真找)。

那么有没有什么别的好办法呢?这就引出这次要说的主角了:Cookiecutter

简介

Cookiecutter 是一个用 Python 开发的项目模版工具,在 Github 上可以找到它的源码,这个项目目前已经有将近一万个 star 了。

Cookiecutter 并不是一个 iOS 专用的工具,它的支持相当广泛,基本上所有主流的项目方案都可以使用它来建立模版,这源于它十分简单粗暴的实现原理:先创建一个项目框架作为模版,将项目名称等一系列参数以关键字的方式在配置文件中指定好,然后新建项目时根据配置好的模版参数,替换模版中所有目录和子目录的名称,以及所有文本中匹配到的关键字。当然了,Cookiecutter 还有很多高级用法,可以去查询它的文档。

这篇文章只是抛砖引玉,介绍一下我基于 Cookiecutter 创建一个简单的 App 模版的过程。

安装

首先需要安装 Cookiecutter,针对不同的平台和环境,Cookiecutter 提供了相当多的安装方式。不过 iOS 开发者基本都在 macOS 环境下工作,所以其他的就略过了。

mac 下官方推荐使用 Homebrew 来安装:

brew install Cookiecutter

整个安装过程都是自动的,非常简单。

创建模版

新建项目

首先我们需要创建一个模版:打开 Xcode,新建一个单页应用。


新建单页应用

点击 'next', 然后将对应属性设置为 template 关键字,如下图所示:

  • Product Name: {{cookiecutter.product_name}}
  • Organization Name: {{cookiecutter.organization_name}}
  • Organization Identifier: {{cookiecutter.organization_identifier}}
创建项目

然后点击 next 创建项目,项目创建完毕后,打开 info.plist,将 Bundle identifier 指定为 com.{{cookiecutter.organization_identifier}}.{{cookiecutter.product_name}} 否则 Xcode 默认会将 {} 替换为 -,导致后续创建项目时替换失败。

配置文件

接下来,在与刚创建完毕的项目根目录同级,也就是 {{cookiecutter.product_name}} 文件夹所在的目录,创建一个 cookiecutter.json 文件,内容如下:

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

JSON 中的 key 就是我们刚才创建项目时填写的那几个用双括号包含起来的名称,并且去掉 cookiecutter 前缀,key 对应的值表示默认值。使用 Cookiecutter 从模版创建项目时,它会询问配置文件中的这几个 key,让我们给它指定名称,如果不指定,则使用配置文件中的默认值。

另外,需要哪些 key,以及 key 的名称是不固定的,你可以根据自己的需要自己定义任意数量的 key,只要保证在模版项目中使用相同的名称,并且需要带上 cookiecutter 前缀

至此,一个最简单的项目模版就创建完了,你也可以根据自己的需要给这个项目添加一些额外的代码,新建项目时所有额外添加的内容都将原样保留。

钩子

上面创建的项目非常简单,但是我们实际开发中一般都需要使用 Cocoapods 来管理第三方依赖,并且有些库几乎是所有项目都需要用到的,比如 AlamofireSnapKit 等等。那么能不能通过模版一并完成 pods 的配置和安装呢?

这就可以用上 Cookiecutter 的钩子功能了,钩子通俗一点讲也叫回调,可以在某些特性情况下触发一些事件,执行一些操作等。

Cookiecutter 的钩子配置非常简单,只需要在配置文件同级目录下新建一个 hooks 目录,然后将写好的脚本放在该目录中,Cookiecutter 会自动调用。

目前 Cookiecutter 支持两个事件,即创建项目之前和创建项目完成之后,会分别调用对应的脚本文件,目前支持 shell 脚本和 python 脚本。在安装前调用的脚本需要命名为 pre_gen_project.sh 或者 pre_gen_project.py;同样的,在安装之后调用的脚本需要命名为 post_gen_project.sh 或者 post_gen_project.py,取决于脚本使用的语言。

自动安装 pods

首先需要在项目目录下,即 {{cookiecutter.product_name}}/ 目录下创建 Podfile 文件,并配置好常用的依赖库:

target '{{cookiecutter.product_name}}' do

  use_frameworks!

  # Pods for {{cookiecutter.product_name}}

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

end

好了,不要执行 pod install,因为这只是个模版,可能实际创建项目时这些库已经更新了,所以需要在创建项目时才安装依赖。

接下来打开 post_gen_project.sh, 写上 pod 安装相关的命令:

#!/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"

其实只需要写一句 pod install 就够了,不过为了创建项目时命令行的输出内容能够更加友好,我添加了一些额外的状态输出的内容,你也可以在其中添加一些其他需要处理的事务。

这时候我们的项目框架才算基本完成。此时,我们的项目模版目录应该是类似下面这样:

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

使用

分发模版

模版做完了,放到哪里呢?本地目录也是可以的,Cookiecutter 支持从任何可以访问的路径加载项目模版,不过为了方便使用和团队共享,最好是将模版推送到 git 仓库中,这样也方便后期修改以及多人维护等。

另外,如果你的模版项目非常大,也可以打包成 zip 上传,Cookiecutter 支持从 zip 包创建项目,创建时会自动解压。

创建项目

创建项目也非常简单,确保 Cookiecutter 已经正确安装后,只需要 cd 到你准备创建项目的目录,然后执行以下命令就好了:

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

后面的路径可以是本地路径也可以是远程路径,可以是 git,也可以是 zip。Cookiecutter 还支持很多其他的仓库形式,详细可以查看它的文档。

命令执行后就开始创建项目了,Cookiecutter 会对你在配置文件中设置的每一个关键字进行询问,你可以输入新项目需要使用的值,或者也可以直接回车后使用默认值。

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

创建项目

Cookiecutter 会在用户目录下缓存所有安装过的项目模版,下次安装时会询问你是否需要更新模版:

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

输入 yes,它会自动更新模版后创建项目。

另外可以看到在创建项目之后 pod install 指令也自动执行了,我们在 Podfile 里面指定的三个依赖库都已经成功安装了。可以进入 MyApp 目录下面,打开 MyApp.xcworkspace 查看创建完毕的项目:

创建完毕的项目

结束语

其实可以发现 Cookiecutter 的原理和使用都非常简单。现在项目越做越庞大,架构也越来越复杂,虽然我们可以通过组件化的方式最大化的重用代码,减少工作量,但是依然需要写大量的胶水代码来整合各个组件,做大量的项目配置、项目初始化的工作,通过使用 Cookiecutter,可以进一步节省大量的工作。

ps. 我在 Github 上创建了我自己的 iOS 项目模版,你如果不想自己写,也可以使用我的模版:https://github.com/Harley-xk/iOS_Template_Comet.git

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349