tldr
- xcodegenでちゃんとAdHoc配信までできる設定をするのは結構大変
-> なので、自分で頑張って作ってみました。あとXcodeGenの考察を色々します。
はじめに
どうも。新卒1年目のiOSエンジニアです。
- XcodeGenでプロジェクト管理をする
- 完成したアプリはdeploygateで配信する
という要件のiOSプロジェクトに先日まで参加していたのですが、色々苦労したので、そのときの話を語ります。
そもそもXcodeGenって
iOSプロジェクトを複数人で開発する場合、プロジェクトのファイルを管理する.xcodeproj
ファイルのコンフリクトがよく起こります。大規模開発だとよく起こるトラブル(らしい)です。
これを解消するのがXcodeGenで、プロジェクトのソースやビルド設定などをyamlファイルで定義し、yamlファイルとソースコードから開発環境となる.xcodeproj
ファイルを一意に生成できるツールです。即ち、.xcodeproj
がgit上に無くても、yamlファイルさえあれば開発環境を他の開発者のPCで再現できるようになります。
「.xcodeproj
ファイルを共有せずに済む仕組みとツールがあれば、そもそもコンフリクトとか起こらないよね! 」 という寸法です。
Xcodegenを使う
XcodeGenでgenerateするまで
READMEを見れば大体わかりますが、インストールして、
$ brew install xcodegen
依存しているライブラリとソースコードを入れるディレクトリの準備をして
(ソースコードを入れるディレクトリは先に用意しないとxcodegen generate
できません)
$ cd (プロジェクトルート)
$ mkdir (ソースコードを入れるディレクトリ)
$ pod init
$ vi Podfile
$ pod install
$ vi Cartfile
$ carthage bootstrap --no-use-binaries --cache-builds --platform ios
yamlファイルを書いて (後述)
$ vi project.yaml
generateします。歯車3つ出てきたら成功です
$ xcodegen generate
Loaded project:
Name: testProject
Targets:
testProject: iOS application
⚙️ Generating plists...
⚙️ Generating project...
⚙️ Writing project...
Created project at ($PROJECT_ROOT)/.xcodeproj
$ ls
$PROJECT_NAME Package.swift Pods Sources project.yml
Cartfile Podfile README.md Tests testProject.xcodeproj
生成されたら容赦無くプロジェクトを開いてやりましょう。CocoaPodsを使う場合は.xcworkspace
も一緒に生成されているので無問題です
$ open testProject.xcworkspace
project.yamlを書く
配信しない(とりあえずprojectファイルを生成して開発したい)場合
これ↓だけあればとりあえずprojectファイルが作れます。
name: testProject
deploymentTarget:
iOS: "11.0"
targets:
testProject:
platform: iOS
type: application
sources:
- path: testProject
- path: testPeoject/R.generated.swift
optional: true
info:
path: testProject/Info.plist
properties:
CFBundleDevelopmentRegion: ja_JP
UISupportedInterfaceOrientations: [UIInterfaceOrientationLandscapeRight]
UIRequiresFullScreen: "YES"
UILaunchStoryboardName: "LaunchScreen"
NSCameraUsageDescription: "カメラ撮影をするため"
CFBundleDisplayName: "AppName"
CFBundleIdentifier: "com.skamada.testProject"
dependencies:
- carthage: RxSwift
- carthage: RxCocoa
- carthage: RxRelay
- carthage: SwiftyBeaver
- carthage: Reachability
- carthage: Nuke
preBuildScripts:
- path: /bin/sh
name: Run R.swift
inputFiles:
- $TEMP_DIR/rswift-lastrun
outputFiles:
- $SRCROOT/$PROJECT_NAME/R.generated.swift
script: |
"Pods/R.swift/rswift" generate "$SRCROOT/testProject/R.generated.swift"
ここで使っているのは
-
name
プロジェクト名。 -
deploymentTarget
対応する(buildする)OSバージョン-
sources
ソースコードを格納するディレクトリ名。ディレクトリはあらかじめ作っておきましょう。 -
optional
R.swiftのR.generated.swiftなど、ビルドして初めて生成されるファイルはoptional指定が必要です。 -
info
Info.plist
に設定したいことを羅列します。CF~~~
とかUI~~~
とか、Row Keys
での指定が必要です。XcodeのInfo.plistで右クリック > Show Row Keys/Values
で1つずつ確認してみましょう。Info.plistの生成からしてくれます。 -
dependencies
依存するcarthageライブラリや、他のターゲット(target
)、フレームワーク (framework
)、sdk(sdk
)を指定すれば、勝手に設定してくれます。 -
preBuildScripts
R.swiftのように、ビルドの前後にスクリプトを走らせたい場合は設定しましょう。postBuildScripts
とか、postCompileScripts
とかもあります。
-
AdHoc配信をしたい(証明書、プロビ周りの設定をしたい)場合
こんなの↓を追加で設定してあげましょう。AdHoc配信のために必要なものはここでは説明しません。このあたりの記事を読んでみましょう。
【iOS】複雑な証明書周りをあっさり整理してみた
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: "com.skamada.testProject"
CODE_SIGN_STYLE: Manual
configs:
debug:
CODE_SIGN_IDENTITY: iPhone Developer
PROVISIONING_PROFILE_SPECIFIER: Project-profile-debug
DEVELOPMENT_TEAM: # development teamのID
release:
CODE_SIGN_IDENTITY: iPhone Distribution
PROVISIONING_PROFILE_SPECIFIER: Project-profile-release
DEVELOPMENT_TEAM: # development teamのID
scheme:
targets:
testProject
-
settings
ここ↓の画面で設定できることをあれこれ設定できます。- base:
debug
とかrelease
とかに共通して設定したいことを記述すると一気に設定してくれます。 -
PRODUCT_BUNDLE_IDENTIFIER
配信時のBundle ID
です。CFBundleIdentifier
と別個に設定しないといけないみたいです。 - configs:
debug
とかrelease
とかで分けて設定したい場合は記入しましょう。 -
CODE_SIGN_IDENTITY
iPhone Developer
とか、iPhone Distribution
とかです。 -
PROVISIONING_PROFILE_SPECIFIER
プロビの名前を書きましょう。 -
DEVELOPMENT_TEAM
Apple DeveloperのチームのIDを記入しましょう。チーム名ではありません。 (ここで数時間ハマりました) -
scheme
Build Scheme
↓の設定です。この設定をしないと、Xcodeさんの気分次第でNo Scheme
になってしまいます。
- base:
.gitignore
に追記する
.xcodeproj
とInfo.plist
はproject.yamlから一意に生成できる
∴ .xcodeproj
とInfo.plist
はわざわざgit共有しなくてもいい
ので、gitignoreに追加してあげましょう。
Info.plist
*.xcworkspace
*.xcodeproj
project.yamlを作るのに苦労したところ
配信設定などは特に、project.yamlを作るのに結構苦労しました。
- なぜ苦労したか
-
DEVELOPMENT_TEAMはチーム名でなくてチームID
に気づくのに時間がかかった - プロジェクトを完成させるのが最優先で、project.yamlを完成させるのは必須ではなかったから
- 足りない設定は最悪プロジェクト生成後に手作業で生成すればいいから
-
DEVELOPMENT_TEAMはともかく、モチベーション的な要素が大きかった。
面倒ではあるけど、プロビの設定とかはXcode上でも2クリックくらいで済むので後回しになってました。何より先にちゃんと要件を満たしたコードを書かないと!と思うのが実装者の性。。。?
メリットとデメリットの整理
メリット
.xcproject
ファイルがコンフリクトしない
そもそもgit共有しない運用ができるので。
targetの追加が楽
ビルドターゲットの追加はproject.yaml
に数行追加するだけで済むので楽になるはずです。大規模になると恩恵が大きそう。
デメリット
ファイルツリーが強制的に同じ位置になる
「自分にとって見やすい配置」とかあると思うんです。でもXcodeGenだとアルファベット順強制です。
ちなみに、XcodeGenを使用するとこの仕様のおかげでファイルツリー構成が同じになるので、.xcodeproj
をgitに共有しても.xcproject
コンフリクトはあんまり起こらない(はず)です。1
学習コストがかかる
ツールを導入するので当たり前ですが。設定を1つ追加するたびにREADMEを漁ることになるので学習コスト高めです。
git checkout
のたびにgenerate
が必要
ライブラリ構成やファイルツリー構成がproject.yamlに依存するせいか、作業ブランチを変更するたびにgenerate
しないとうまく動作しません。iOS開発に慣れている人ほど面倒くさいと感じるはず。
generate
と pod install
はセットでやる
podとxcodeの仕様上仕方ないんだと思いますが、xcodegen generate
をするたびにpod install
しないと、podで導入したライブラリは認識されません。
即ち、作業ブランチを変える際は
git checkout ~~
-> xcodegen generate
-> pod install
の3コマンドが必須になります。
3コマンドとなると結構手間なので、コマンドのaliasを作成するなどして対応するのが吉です。
さいごに:無理して全部のプロジェクトに導入しなくていい。でも1回試してみよう
当然導入するとプロジェクトメンバー全員に対して大きめの学習コストが発生するし、XcodeGen導入によって受けられる恩恵はプロジェクト規模にかなり依存する印象でした(規模大きいほど恩恵大)。試しに使ってみてもいいですがどのプロジェクトに導入するかは考えた方が良さそうです。
とはいえ恩恵はしっかりあるので、せひ一度試してみてください。
-
.gitignoreで
.xcodeproj
を共有しないようにするのは私オリジナルの運用方法です。コンフリクトのリスクを最小限に抑えたいならそもそも共有しなければいいじゃん、っていう発想になるよね ってことでこの運用にしました。 ↩