17
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

iOSでビルド時に自動生成するソースコードをGitで管理しないために

Last updated at Posted at 2020-02-04

はじめに

iOSアプリ開発において、リソースにタイプセーフにアクセスするためのソースコードを自動生成する SwiftGenR.swift のようなツールをよく利用すると思いますが、みなさんはその自動生成されたソースコードは Git 管理下においていますか?

私の開発中のアプリではこれまで Git 管理下においていたのですが、アプリの要件により次のような状況になりました。

  • Build Configuration に応じて自動生成されるコードに違いが出るようになった
  • ソースコード以外にも Build Configuration に応じてアプリにバンドルさせるファイルを切り替える必要性がでてきた

このような状況ですと、Build Configuration によってファイルが変化してしまうため、ビルド時に自動生成するファイルは Git 管理下におかないようにしました。が、その中でつまづきポイントがあったのでメモとして残します。

Git 管理外にすると...

Git コマンドで自動生成ファイルを Git 管理対象外にします。

$ git rm path/to/Generated/file

Xcode プロジェクトツリー上ではそのファイルが赤色で表示され、存在しないことがわかります。
Xcodeプロジェクトツリー/存在しないファイル

そして、自動生成されてもコミット対象にならないよう、.gitignore ファイルに自動生成先ディレクトリを追加しました。

.gitignore
path/to/Generated

この状態でビルドを実行してみたところ、次のようなビルドエラーとなってしまいました。

error: Build input files cannot be found: 'path/to/Generated/Asset.swift', 'path/to/Generated/StoryboardScenes.swift', 'path/to/Generated/Strings.swift', 'path/to/Generated/StoryboardSegues.swift' (in target 'MyApp' from project 'MyApp')

自動生成のタイミングを確認するも...

自動生成のタイミングがソースコードのコンパイル時に間に合っていないのかと思い、Xcode プロジェクトの Build Phases を確認してみましたが、SwiftGen を実行する Run SwiftGenCompile Sources よりも前のタイミングになっていないので問題なさそうです。
Xcodeプロジェクト/Build Phases

プロジェクトツリー上のファイルの存在チェックはこの Build Phases よりも前のタイミングで実施されるのでしょうか?

解決策

いろいろと調べて R.swift リポジトリのこの issue にたどり着きました。

First build always fails using the new build system with Xcode 10 Beta 6

どうやら Xcode10 の新しいビルドシステムでは、Build Phases で生成されたファイル等は成果物として明示してあげる必要がありそうです。ということで先程の Run SwiftGenOutput Files に自動生成されるファイルのパスを追加しました。
Xcodeプロジェクト/Build Phases/Run SwiftGen

これにより、自動生成される前の状態でのXcodeプロジェクトツリー上での表示もこのように変わりました!ファイルアイコンは半透明のままですが、ファイル名は赤色ではなくなっています。
Xcodeプロジェクトツリー/存在しないファイル2

もちろん、ビルドも問題なく通るようになりました :thumbsup:

2020/2/27追記 - この対応による問題と回避策

上記のような対応を実施した場合、自動生成の元となるファイルが変更されても再生成が行われないことがわかりました。これを回避するためには、自動生成の元となるファイルを Input Files に追加しなければならないようです。これは、SwiftGen や R.swift の Issue でも議論されています。

ただ、Input Files が複数に渡る場合(例えば、Storyboard を 1画面1ファイルにしているようなケース)ですと、ファイルを追加するたびにここのメンテナンスが必要となって厄介です。せめてフォルダを指定できればよいのですが、それでは意図した動作とならないようです。

SwiftGen については上記の Issue は "Apple Bug" とラベリングされて止まっており、 [New Feature] Generate xcfilelist for Script Build Phases で Input Files の代わりになる xcfilelist を生成するアプローチが提案されていますが、止まっていますね。

R.swift については v5 で対応されているようです。その修正は mac-cain13/R.swift/pull/468 で、うまい対応策が実施されています。

最終的に私の方では、Build Phase の前に走る Build scheme pre-actions で自動生成を行うことで回避しました。ただ、 SwiftGen/Issue/560のコメント にあるとおり、pre-actions ではスクリプトのエラーが Xcode の方で警告されないため、エラーに気づけないというデメリットがあります...

2020/10/8追記 - ↑の問題への対策

上記の「自動生成の元となるファイルが変更されても再生成が行われない」問題に対して、2つ対策方法ができたので紹介します。

  • SwiftGen v6.4.0 の新機能を使用する
  • Xcode 12 の新機能を使用する

SwiftGen v6.4.0 の新機能を使用する

2020/10/8 にリリースされた v6.4.0 で、.swiftgen.xml の記述を元に SwiftGen の入出力ファイル一覧 (xcfilelist) を出力するコマンド config generate-xcfilelists が追加されました。

.swiftgen.xml を変更した際にこのコマンドを実行し、Build Phases の Run Script の入出力ファイルとして設定するだけです。

swiftgen config generate-xcfilelists --inputs SwiftGenInput.xcfilelist --outputs SwiftGenOutput.xcfilelist

スクリーンショット 2020-10-08 18.29.01.png

Xcode 12 の新機能を使用する

Xcode 12 に Run Script を必ず実行するオプションができました。下図の Based on dependency analysis がそれです。このオプションはデフォルトでオンになってるので、これをオフにすることで入力ファイルの変更有無に関係なくスクリプトが実行されます。

スクリーンショット 2020-10-08 18.32.42.png

17
8
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?