Automatically manage signingに負けないfastlaneでのiOSアプリ配布

[cloudpack あら便利カレンダー 2017](https://cloudpack.github.io/benri2017/) の13日目です。

in-houseで社内に配布するときにチームを変更しないといけなかったり
別案件では受託開発で証明書とProvisioning Profileしかもらえないといったことはよくあります。
Target追加するのはバグの元…
Schemeを複製して配布時に変更してArchive…
そんなことしないで手作業ではなくfastlaneで簡単に配布したり、ipaを作られるようにしちゃいましょうーという記事です。

# ざっくりとした方法

1. 配布用のConfigurationsを作成する
1. xcconfigを作成し、各種設定を追加する
1. Projectの設定を変更する
1. fastlaneでチーム切り替え、Automatically manage siginingなどを設定する

あとはfastlaneで配布/ipa作成するだけ！
fastlane
# fastlaneインストール

qiitaに素晴らしい記事が上がっているので省きます！
参考: [これから始めるfastlane](http://qiita.com/econa77/items/d81a392d6b195cfb7316)

# 別チームでのアプリ配布設定
in-house用のものを例にして、まずはXcode上で設定を行います。

## Configurationsの追加
InHouse配布用のConfigurationを追加します。
Configuration名はのちほどfastlaneでの設定に使用します。

![image_01.png](https://qiita-image-store.s3.amazonaws.com/0/187223/63ef0ea7-4995-8d0a-2c54-7f6d0eb829c7.png "image_01.png")


CocoaPodsを使っている場合、作成したConfigration用のxcconfigがないため
下記のコマンドで作成しましょう。

```
$ pod install
```

## xcconfig作成
各Configurations用のxcconfigを作成します。
Project navigatorでxcconfigを作成するgroupを右クリックし、 `New File…`を選択します。
Configuration Setting Fileを選択し、任意の名前をつけます。

![image_02.png](https://qiita-image-store.s3.amazonaws.com/0/187223/0402b2da-48ba-1345-9c49-51913c9b4b4b.png "image_02.png")


## xcconfig記述
作成した各xcconfigに下記の設定を行います。
- podで作成されたxcconfigの読み込み（Cocoapodsを使用している場合）
- Bundle Identifierの設定
- アプリ名の設定

```
// CocoaPodsを使用している場合。パスは適宜置き換えてください。
#include "Pods/Target Support Files/Pods-FastlaneTestApp/Pods-FastlaneTestApp.debug.xcconfig"

// Bundle Identifier
PRODUCT_BUNDLE_IDENTIFIER = jp.cloudpack.fastlane.debug
// アプリ名
PRODUCT_NAME = fastlane debug
```

## xcconfig適用
反映されるように、Projectに設定します。
Project navigatorでProjectを選択し、Configurationsをそれぞれ設定します。
`Cmd+B`でビルドしてパスが間違っていないことを確認します。

![image_03.png](https://qiita-image-store.s3.amazonaws.com/0/187223/29278281-4770-31a5-628d-7e4f3ef1ded6.png "image_03.png")

## Projectの設定
xcconfigで設定した `Bundle Identifier`や `アプリ名`はそのままでは反映されていません。
Build Settingで下記の項目に `$(inherited)`を設定します。

- Product Bundle Identifier
- Product Name

![image_04.png](https://qiita-image-store.s3.amazonaws.com/0/187223/72e4cce1-0833-f5b1-aedb-fb7c611a760b.png "image_04.png")

# fastlaneの設定
## fastlane初期設定
下記コマンドを実行します。
`Username`のみ入力必須で他は入力しなくてよいです。

```
fastlane init
```

## fastlane/Fastfileの編集

### 各種パス、Configurations、チームIDを記述

```
platform :ios do

  APP_SCHEME = "FastlaneTestApp"
  PLIST_PATH = "./" + APP_SCHEME + "/Info.plist"
  PROJECT_NAME = APP_SCHEME + ".xcodeproj"

  # Configurations
  IN_HOUSE = "InHouse"
  RELEASE = "Release"

  # for in-house
  TEAM_ID = "**********"
  IN_HOUSE_TEAM_ID = "**********"
```

### ビルド用lane追加
出力先やファイル名をgymで毎回設定するのは手間なので
下記のようなprivate_laneをよく使用しています。

```
private_lane :build do |options|
  build = get_info_plist_value(path: PLIST_PATH, key: "CFBundleVersion")
  version = get_info_plist_value(path: PLIST_PATH, key: "CFBundleShortVersionString")
  scheme = options[:scheme] || APP_SCHEME
  config = options[:config] || IN_HOUSE
  method = options[:method] || "ad-hoc"
  include_bitcode = options[:include_bitcode] || false

  gym(
    clean: true,
    configuration: config,
    scheme: scheme,
    output_directory: "./fastlane/Build/#{build}_#{version}",
    output_name: "#{scheme}_#{config}_#{build}_#{version}",
    include_bitcode: include_bitcode,
    export_method: method
  )
end
```

### 配布用のlane作成
ビルド前にチームIDを切り替えて、ビルド完了後に元のチームに戻しています。

```
lane :inhouse do

  # 配布用のチームIDに切り替える
  update_project_team(
    path: PROJECT_NAME,
    teamid: IN_HOUSE_TEAM_ID
  )

  # enterpriseを指定してビルド
  build(
    method: "enterprise"
  )

  # チームIDを戻す
  update_project_team(
    path: PROJECT_NAME,
    teamid: TEAM_ID
  )

  # DeployGateやCrashlyticsなどの設定はよしなに
  # deploygate(
  #   message: RELEASE_NOTE_DEV,
  #   api_token: "your api token"
  # )
  
  # ENV['CRASHLYTICS_API_TOKEN'] = "your api token"
  # ENV['CRASHLYTICS_BUILD_SECRET'] = "your build secret"
  
  # crashlytics(
  #   crashlytics_path: "./Pods/Crashlytics/iOS/Crashlytics.framework",
  #   notes: "notes",
  #   groups: ["group"]
  # )
end
```

## アプリ配布
laneを実行してアプリ配布します。
いつもの配布どおり、配布用の証明書が必要です。

```
$ fastlane inhouse
```

# release版ipaファイルの作成
`配布用証明書`と `Provisioning Profile`のみがある状態です。
このままfastlaneで作成しようとしてもチームに入っていないため作成ができません。
Automatically manage signingをオフにしてビルドするだけと思いきや
自動化するには色々設定が必要となります。

## チームID、Provisioning Profile名の確認
もらった `.mobileprovision`をエディタで開き `Name`の値と `TeamIdentifier`の値をそれぞれ確認します。

```
<key>Name</key>
<string>fastlane test</string>
<key>TeamIdentifier</key>
<array>
  <string>**********</string>
</array>
```

## Release.xcconfigに設定
Release.xcconfigに下記を追記します。

```
PROVISIONING_PROFILE_SPECIFIER = fastlane test
DEVELOPMENT_TEAM = ********** // TeamIdentifierの値
```

## BuildSettingsの変更
XcodeでBuild Settingsを開き、各項目を設定します。

### Code Signing Identity
automatically manage signingオフで配布したいConfigurationには `iOS Distribution`を設定します。
下記のとおりに設定しないとエラーとなり、ここでしばらくハマりました。。

| Automatically manage signing | Any iOS SDKの設定 |
| ----- | ----- |
| オン | iOS Developer |
| オフ | iOS Distribution |

![image_05.png](https://qiita-image-store.s3.amazonaws.com/0/187223/f048b4c1-01f5-fc1d-6d0b-ca0e04b8dd24.png "image_05.png")

### Development Team
オフで配布したいConfigurationのみ `$(inherited)`を設定します。
`Other...`を選択すると値の設定ができます。

![image_06.png](https://qiita-image-store.s3.amazonaws.com/0/187223/077ae551-fdda-c977-4ec0-ea8b8dc53377.png "image_06.png")

### Provisioning Profileの設定
すでに設定したものが反映されている場合はそのままでOKです。
もし別のものが入っている場合は `$(inherited)`を設定しましょう。

![image_07.png](https://qiita-image-store.s3.amazonaws.com/0/187223/526cb55c-a7b0-f8eb-520e-4bf3d47138f8.png "image_07.png")

## リリース用ipa作成用lane作成
チームIDの変更とほぼ同じく、ビルドの前にAutomatically manage signingをオフにし、
ビルド後にオンに戻します。
Google先生に聞くと [fastlane-plugin-update_project_codesigning](https://github.com/hjanuschka/fastlane-plugin-update_project_codesigning) というプラグインが出てきますが、
[2.20.0](https://github.com/fastlane/fastlane/releases/tag/2.20.0) でfastlaneに取り入れられているのでそちらを使用します。

```
lane :release do

  # Automatic code signingをオフにする
  automatic_code_signing(
    path: PROJECT_NAME,
    use_automatic_signing: false
  )

  # app-store用にビルド
  build(
    config: RELEASE,
    method: "app-store"
  )

  # オンに戻す
  automatic_code_signing(
    path: PROJECT_NAME,
    use_automatic_signing: true
  )

end
```

## ipa作成
laneを実行してipaを作成します。

```
$ fastlane release
```

# まとめ
忙しい時期になるとアプリ配布の時間がもったいなく感じます
最初に設定しておくと後々（リリース前など）とても楽になります。
今回は触れていませんがCIとの連携もいいですね。