Xcode8時代のプロジェクト新規作成方法まとめ

いまのところの自分的にベストだと思うプロジェクト作成方法のメモです。毎回どうやっていたか忘れるので書いときます。
Carthageも便利ですが、自分的にはすべてやってくれるCocoapodsの方が好きなので、こちらを使います。
また、fastlaneも便利なので入れます。

# Xcodeでの作業

まずはXcodeを起動して、メニューの「File」 -> 「New」 -> 「Project」
iOSのApplicationを選択して「Next」で、適切な値を入力して「Next」->「Create」

一旦Xcodeは閉じます。

# Cocoapods

普通にインストールするだけでもできるのですが、チームでの開発の場合、全員同じバージョンのrubyとbundlerとcocoapodsにしたいのでそうします。

## Homebrew

### インストール

mac標準のrubyでまずはhomebrewをインストールします。

```$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"```

### ruby関連のインストール

homebrewでruby関連をインストールしておきます。

```
$ brew update
$ brew install openssl
$ brew install readline
$ brew install ruby-build
$ brew install rbenv
$ brew install rbenv-gemset
```

## rbenv

Ruby環境のバージョン切り替えツールです。

まずはPATHを通しておきます。

```
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile
```

### rbenv-default-gemsの利用

これは、rbenvでrubyをインストールした時についでにgemもインストールする時に利用するツールです。
どのバージョンのrubyでも共通に利用したいgemがある場合に役立ちます。
今回はすべてのプロジェクトで同じバージョンのbundlerを使う想定です。

まずはインストール

```
$ git clone https://github.com/sstephenson/rbenv-default-gems.git ~/.rbenv/plugins/rbenv-default-gems
```

```~/.rbenv/default-gems``` に ```rbenv install``` 後に一緒に gem install したいgemを指定します。

```
bundler ~>1.13.1
```

これで、```rbenv install``` をした時に ```gem install bundler -v 1.13.1``` も一緒に行われます。

インストール可能なrubyバージョンを調べてインストールします。
```プロジェクト/.ruby-version``` にバージョンが記述されます。

```
$ rbenv install -l
・・・
$ rbenv install バージョン番号
$ rbenv local バージョン番号
```

## Bundler

アプリ毎のgem（とそのバージョン）管理ツール

```rbenv-default-gems``` でインストール済みです。

cocoapodsはこれを通してインストールします。 プロジェクト直下に ```Gemfile``` を作成して定義します。

```Gemfile
source "https://rubygems.org"

gem 'cocoapods', '1.0.1'
gem 'fastlane', '1.104.0'
```

以下のコマンドでGemfileに記述したgemがインストールされます。

```
$ bundle install --path vendor/bundle
```

## Cocoapods

依存ライブラリ解決ツールです。

bundlerでinstall済みです。
まずは、setup。これで [CocoaPods master repo](https://github.com/CocoaPods/Specs)を取得して、```~/.cocoapods```に 展開しています。

```
$ bundle exec pod setup
```

次はライブラリを定義するファイル(Podfile)を作成します。

```
$ bundle exec pod init
```

できたPodfileに使いたいライブラリを定義します。

```Podfile
# Uncomment this line to define a global platform for your project
platform :ios, '9.0'

target 'Sample-ios' do
  # Comment this line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for Sample-ios
  pod 'Bond', :git => 'git@github.com:SwiftBond/Bond.git', :tag => 'v5.0.0-beta7'
  pod 'Alamofire', '~> 4.0'
  pod 'ObjectMapper', '~> 2.0'
  pod 'AlamofireObjectMapper', '~> 4.0'
  pod 'SwiftTask', :git => 'git@github.com:ReactKit/SwiftTask.git', :branch => 'swift/3.0'
  pod 'RealmSwift', '~> 1.1'

  target 'Sample-iosTests' do
    inherit! :search_paths
    # Pods for testing
  end

  target 'Sample-iosUITests' do
    inherit! :search_paths
    # Pods for testing
  end
end

post_install do |installer|
    puts("Update debug pod settings to speed up build time")
    Dir.glob(File.join("Pods", "**", "Pods*{debug,Private}.xcconfig")).each do |file|
        File.open(file, 'a') { |f| f.puts "\nDEBUG_INFORMATION_FORMAT = dwarf" }
    end
    installer.pods_project.targets.each do |target|
        target.build_configurations.each do |config|
            config.build_settings['SWIFT_VERSION'] = '3.0'
        end
    end
end
```

以下でpod管理しているライブラリをインストールします。

```
$ bundle exec pod install
```

# git

giboから、先にgitignoreを作っておきます。

```
$ brew install gibo
$ gibo Swift Objective-C Xcode Ruby Vim OSX >> .gitignore
```

Podsディレクトリはgit管理させない派なので、```# Pods/``` のコメントを外します。
その他、気持ち悪ければ、余分な定義を削除します。

その後gitにpushしておきます。

# fastlane

これは、プロビジョニングプロファイルの取得やipa作成などの煩わしい作業を自動化できるツールです。
bundlerでinstall済みです。

```./fastlane``` ディレクトリに設定ファイルを作成します。

```
$ bundle exec fastlane init
```

```Your Apple ID (e.g. fastlane@krausefx.com):``` にApple IDを入力します。

```
This app identifier doesn't exist on iTunes Connect yet, it will be created for you
This app identifier doesn't exist on the Apple Developer Portal yet, it will be created for you
Please confirm the above values (y/n)
```

と出るので```no``` にしときます。

```Password (for <上記メールアドレス>):``` で入力する値は、iTunes Connectのパスワードで、それをFASTLANE_PASSWORD環境変数に保存します。
```App Identifier (com.krausefx.app):``` に本番のBundle Identifierを入力します。
```Would you like to create your app on iTunes Connect and the Developer Portal?``` で yesにするとiTunes Connectに新しいアプリを作成するための入力を求められます。
```Do you want to setup 'deliver', which is used to upload app screenshots, app metadata and app updates to the App Store? This requires the app to be in the App Store already. (y/n)
```  ではYesにするとfastlaneでアップル申請が利用できるようになります。また、すでにApp Storeにアプリがある場合はmetadataなどを取得します。
```Optional: The scheme name of your app (If you don't need one, just hit Enter):``` Testsなどで複数のスキームがあると思うので、Testsでないスキームを入力します。

```$ bundle exec fastlane scan init``` で fastlane/Scanfileファイルを生成して指定します。

```astlane/Scanfile
devices ["iPhone 6s Plus"]

workspace "<プロジェクト名>.xcworkspace"
scheme "<スキーム名>"
configuration "Debug"
sdk "iphonesimulator"

code_coverage true
clean true
```

または、生成されたFastfileの```lane :test``` でスキーム指定をしてもできますが、上記方法をお勧めします。

```fastlane/Fastfile
lane :test do
  scan(scheme: "<スキーム名>")
end
```


## 単体テストの動作確認

<プロジェクト名>.xcworkspaceでXcodeを開いて、Product → Scheme → Manage Schemes で、<プロジェクト名>Testsと<プロジェクト名>UITestsを追加してsharedにチェックを入れておきます。
そして、Product → Scheme → Edit Scheme…　で "Build" セクションを選択して、Runにチェックを入れます。

動作確認をします。

```
$ bundle exec fastlane test
```

## UIテストとSnapShotの動作確認

### SnapShot

```fastlane/Snapfile``` と ```fastlane/SnapshotHelper.swift``` を作成します。

```
$ bundle exec fastlane snapshot init
```

できた```fastlane/Snapfile```を以下のように修正します。

```fastlane/Snapfile
 devices([
   "iPhone 6",
   "iPhone 6 Plus",
   "iPhone 5",
   "iPhone 4s"
 ])
languages([
  "ja-JP",
  ["en", "en_JP"]
])
scheme "スキーマ名"
output_directory "fastlane/screenshots"
clear_previous_screenshots true
workspace "./ワークスペース名.xcworkspace"
```

```fastlane/SnapshotHelper.swift``` をXcodeでUITestプロジェクトに追加します。

試しに以下のようなUIテストコードを書いておきます。

```
override func setUp() {
    super.setUp()
    continueAfterFailure = false
    let app = XCUIApplication()
    setupSnapshot(app)
    app.launch()
}

override func tearDown() {
    super.tearDown()
}

func testExample() {
    snapshot("firstView", waitForLoadingIndicator: true)
    XCUIApplication().tabBars.buttons["Second"].tap()
    sleep(1);
    snapshot("secondView", waitForLoadingIndicator: true)
}

```

```xcodebuild: error: missing value for key 'id' of option 'Destination``` のエラーが出ないように一旦シュミレーターを削除します。

```
$ bundle exec fastlane snapshot reset_simulators
```

実行します。

```
$ bundle exec fastlane snapshot run
```

htmlが生成されれば成功です。


# Xcode Plugin

Xcode8から7以前のpluginが使えなくなりました。
[Xcode8で以前のPluginを使う方法](http://qiita.com/ko2ic/items/23b8f5adf90478fc7418)通りに行い、利用できるようにしておきます。

自分は、```Alcatraz```, ```XVim```, ```ClangFormat-Xcode```, ```VVDocumenter-Xcode```, ```RealmPlugin```, ```Swimat```, ```SwiftLintXcode``` を入れます。

# Lintとフォーマッター

SwiftLintを利用します。

```
$ brew install swiftlint
```

Cocoapodsでもインストールできます。

```Podfile
pod 'SwiftLint'
```

SwiftLintでは以下のように設定ファイルでカスタマイズできます。

```.swiftlint.yml
disabled_rules: 
  - line_length
  - type_name
  - trailing_newline
  - todo
  - force_cast
  - force_try
included: 
  - <プロジェクト名>
excluded: # Lint対象から外すファイルのあるパスを記述、CocoaPodsやCarthage
  - Pods
line_length: 220
type_body_length:
  - 400 # warning
  - 500 # error
#force_cast: warning
#force_try: warning

```

## Xcode設定

SwiftLintの[公式サイト](https://github.com/realm/SwiftLint#usage)に書かれている通りにRunScriptに設定します。

```
if which swiftlint >/dev/null; then
  swiftlint
else
  echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi
```

Podsの場合は以下です。

```
if which swiftlint >/dev/null; then
  "${PODS_ROOT}/SwiftLint/swiftlint"
else
  echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi
```

XcodePluginのSwiftLintXcodeを入れてるとと保存時にLintが動作します。

### Swimat設定
これは、indentのスペース数・空行のindentの扱い・　```{``` の始まりの次の行にするかどうかなどを設定することでファイル保存時に自動フォーマットします。
自分は、```4 Space Indent```, ```format when save``` にします。


~~[SwiftLintXcode](https://github.com/ypresto/SwiftLintXcode)を使っていたけど、動作しなくなったので暫定的にSwimatを利用しています。~~



### ClangFormat設定

Objective-Cも使う場合は、XCodeのメニューで「Edit」→「Clang Format」→「File」を選択

「Enable Format on Save」にします。

# アプリの標準言語を日本語にする方法

[こちらの記事](http://qiita.com/ko2ic/items/8918034d940f66fee97d)通りにする


# 開発用とリリース用の設定をする

[こちらの記事](http://qiita.com/ko2ic/items/1926de0895e9f277871b)通りにする

# 単体テストのために

[こちらの記事](http://qiita.com/ko2ic/items/5979c97b4ac589b1c8a1)通りにする