Xamarin.Forms.(iOS|Android)をVisual Studio Team Serviceでビルドし、App Centerにデプロイする

# Xamarin.FormsとVSTSとApp Centerの連携について

[Advent Calendar](https://qiita.com/yakumomo/items/1adac906444ced9398c5)の時は、ちゃんと書ききれなかったのでリベンジ、というわけではないのですが。
なんとか出来たことをついTwitterで呟いてしまったのでここは書いておくフェーズか、と。

わかっているとは思うんですが、本文では Visual Studio Team Service はVSTSと書いてます。

## Microsoftさんには悪いけど

Microsoftさんには悪いけど、ビルドが時間課金されるApp Centerのビルドよりも、五人までなら無料のVSTSのビルドを使いたい、という、完全に個人開発個人趣味的な目的でこんなルートをたどるようにしてみたわけです。

- Xamarin.Formsである程度のプラットフォームの垣根を外し、
- 個人開発者の財布に優しいVSTSでプロジェクト管理を行い、
- これまた個人開発者の財布に優しいApp Centerを使って実機への配布と不具合収集機能を使う
- GitHubやDeployGateと違って完全クローズドにできる

とこんな感じ。
ローカルでやればどれも気にする必要ないんじゃね？というツッコミは無しの方向で。
（開発は個人だがテストの手を少しは使える、もしくは複数の端末使用を想定）

## 事前準備

1. 各プラットフォーム向けのアプリはそれぞれストアで公開できる程度の設定を施しておく
2. iOSの場合、個人情報交換ファイルとプロビジョニングファイルをリポジトリに含めておく
3. 各プラットフォーム用のソリューションファイルを用意しておく
4. Gitをつかうようにする（2018/03/18追記）

### 各プラットフォーム向けのアプリはそれぞれストアで公開できる程度の設定を施しておく

- iOSならDevelopmentかAdHocでipaを作れる程度の、
- Androidならkeystore作ってビルドする程度の

設定をしておかないと、ビルドが失敗します。
Debugビルドなら問題ないとは思いますが、簡単設定をVSTSのビルドで望むなら、Releaseビルドを想定してください。

### iOSの場合、個人情報交換ファイルとプロビジョニングファイルをリポジトリに含めておく

上記のDevelopmentかAdHocで使用するプロビジョニングファイルをダウンロードしてきたものと、キーチェーンアクセスから書き出した証明書を含めておきます。

プロビジョニングファイルはApple Developerサイトからダウンロードしたものをそのまま含めてください。

個人情報交換ファイルはキーチェーンアクセスを使用して書き出します。
ウインドウ左側で **ログイン** と **証明書** を選択し、右側の一覧の中からプロビジョニングに使用したDeveloperかDistributionを選び、右クリックから「〜を書き出す...」を選びます。

![003.png](https://qiita-image-store.s3.amazonaws.com/0/59270/ccaf183b-d2f2-a8b1-1327-9f117336a9e5.png)

保存ダイアログでは、「フォーマット」の欄を **.p12** にし、パスワードは覚えておいてください。
後述の設定で使用します。

### 各プラットフォーム用のソリューションファイルを用意しておく

複数プラットフォームのプロジェクト全体を含んだソリューションを作っている場合は、各々のプラットフォームごとのソリューションファイルをすでにあるソリューションファイルと同じディレクトリ内に作成してください。

iOSビルドのプロジェクト選択は、ソリューション単位での選択です。
Androidビルドのプロジェクト選択はプロジェクト単位なんですが。
この辺のちぐはぐ感が…。

複数入りソリューションと同じディレクトリに置くのは、ビルドのためです。
同じではない場合、NuGetとmsbuild間で失敗する可能性が高まります。

### Gitをつかうようにする

（2018/03/18追記）
コメントで [Gitでないとビルドできない](https://docs.microsoft.com/en-us/appcenter/build/faq#what-can-i-do-if-am-using-team-foundation-version-control-tfvc) ことを教えていただきました。
iOSのビルドにはMacが必要なので、Gitでないとダメなんですね。

## VSTSのビルド設定

すでにVSTSにソースは登録されている状態からのスタートです。
MacとUWPは…機会があれば…。
（まだApp Center登録が成功出来ていないので…）

また、ビルド設定はできることも想定しています。

### iOSのVSTSビルド設定

VSTSでプロジェクトを選び、 **Builds** に移動し、新規のビルド設定を作ります。
ビルド設定を作った際のTemplate選択は **Xamarin.iOS** を選択してください。

![iOS用Template選択](https://qiita-image-store.s3.amazonaws.com/0/59270/c95ec5a2-34c5-78f1-3971-807b45d19a0f.png)

選択直後は以下のような状態です。

![002.png](https://qiita-image-store.s3.amazonaws.com/0/59270/5af3809d-387a-8e16-7c8b-77f6efab49f6.png)

この状態から、まずは **Phase1** の右の **+** をクリックし、 **NuGet** のタスクを追加します。
追加した **NuGet** はタスク一覧の一番上（Phase1の直下）に移動させます。
すると、以下のような状態になります。

![004.png](https://qiita-image-store.s3.amazonaws.com/0/59270/3e8cc8bd-ecff-ecf6-7102-cc4ec2695ebb.png)

各々の設定変更は以下

- **Process** を選び、 **Solution to build** をiOSビルド用のソリューションに選択し直してください。
- **NuGet** を選び、 **Path to solution, packages.config, or project.json** の右の i マークをクリックし、ポップアップ→ **Link** →ポップアップ→ **Link** と選択します。Commandの欄はrestoreのままにしておいてください。
- **Build Xamarin.iOS solution** を選び、 **Signing & Provisioning** 部分を前述の個人情報交換ファイルとそのパスワード、プロビジョニングファイルを指すように設定してください。また、 **Remove Profile After Build** にチェックを入れてください。
- **Advanced** を選び、 **Build Tool** を **MSBuild(Visual Studio for Mac)** に変更してください。

ここで、一旦ビルドしておきましょう。
**Save & queue** あたりでビルドキューに入れますが、その際に **Agent queue** が **Hosted macOS Preview** になっているか確認してビルドをしてください。
ビルドが問題なくできれば、次はApp Centerへのデプロイ設定ですが、先にAndroidのビルド設定をします。

### AndroidのVSTSビルド設定

VSTSでプロジェクトを選び、 **Builds** に移動し、新規のビルド設定を作ります。
ビルド設定を作った際のTemplate選択は **Xamarin.Android** を選択してください。

![005.png](https://qiita-image-store.s3.amazonaws.com/0/59270/bfd61b41-f999-78ad-9a9b-a61dc9f22b86.png)

選択直後は以下のような状態です。

![006.png](https://qiita-image-store.s3.amazonaws.com/0/59270/17872171-cad4-7530-6be2-626d4f18c808.png)

こちらは、このまま設定の変更だけ行います。
各々の設定変更は以下

- **Process** を選び、 **Solution to restore packages** をAndroidビルド用のソリューションに選択し直してください。
- **Build Xamarin.Android Project** を選び、Android用のプロジェクトファイル（csproj）を選択してください。
- テストプロジェクトがなければ、 テストタスクをDisableにしてください。あれば、 **Project** をテストプロジェクトに変更してください。
- **Signing and aligning Apk file(s)** の **Signing Options** の　**Sign the APK** にチェックし、 **Keystore File** 右の歯車マークをクリック→keystoreファイルをアップロードし、その他の欄を埋める

ここで、一旦ビルドしておきましょう。
**Save & queue** あたりでビルドキューに入れ、 **Agent queue** が **Hosted VS2017** か **Hosted macOS Preview** になっているか確認してください。

## App Centerへのデプロイ設定

### App Centerにアプリ登録を作る

App Centerにデプロイする場合、まずはApp Center側に受ける準備が必要です。
[My Apps](https://appcenter.ms/apps)でアプリケーションを作成してください。
とりあえずは適当に。気楽に。

![007.png](https://qiita-image-store.s3.amazonaws.com/0/59270/b3cca520-f610-7b63-0d4d-252210c0feaf.png)

ただ、アプリのOSとPlatformはちゃんと選んでおいてください。

<img width="342" alt="011.png" src="https://qiita-image-store.s3.amazonaws.com/0/59270/eb409fa4-7762-0861-f4c9-8d3b47676eb7.png">

### VSTSのビルド設定のApp Centerへのデプロイを有効にする

VSTSのビルド設定に戻り、最下行で打ち消し線の目にあってる **Deploy 〜 to Visual Studio App Center** を右クリックします。
ポップアップメニューが出るので、 **Enable selected task(s)** をクリックし、タスクを有効化します。

#### App Centerのサービス設定

右側の設定欄の中で、 **App Center Connection** があります。
App Centerの接続先を設定するのですが、最初だと設定されていません。
まずはそこを設定します。

右側に **Manage** のリンクがありますので、そこをクリックしてください。
サービス接続画面になるので、左側の **+ New Service Endpoint** をクリックし、メニューを表示します。

![008.png](https://qiita-image-store.s3.amazonaws.com/0/59270/f7613054-8cc7-fb7b-d347-2089ff992f9f.png)

メニューの一番下に **Visual Studio App Center** があるので、それを選択すると、ウインドウが開き、サービス設定ウインドウが開きます。

![009.png](https://qiita-image-store.s3.amazonaws.com/0/59270/7d0b93be-9fb0-9e59-6282-3c944291eebb.png)

**Connection name** の欄は任意の名前を入れてください。
**API Token** の欄は、App CenterからAPI接続用のTokenを引っ張って来る必要があります。

#### App CenterのAPI Tokenを入手する

再び、App Centerに戻り、左下部のアカウント部分をクリックすると、下部のメニューが表示されます。

![010.png](https://qiita-image-store.s3.amazonaws.com/0/59270/4fbb5856-0ff8-726a-aa33-4b3af4df16a3.png)

**Account Settings** → **API Tokens** と移動し、右上の **New API token** のボタンをクリック。
開いたウインドウの **Description** に任意の名前を入力、 **Access** を **Full Access** に設定し、下部の **Add new API token** をクリック。
**Here’s your API token** のウインドウが開くので、Tokenをコピーします。

#### API Tokenを設定する

またVSTSのサービス接続画面に戻り、ウインドウ内の **API Token** の欄に先ほどコピーしたAPI Tokenをペーストし、 **OK** をクリック。
これで、App Centerのサービス接続設定ができました。

#### ビルド設定にサービス接続を反映

ビルド設定まで戻り、 **App Center Connection** の右にある更新ボタンをクリックし、メニューを更新します。
入力欄のポップアップを表示させると、サービスがあるのでそれを選択して入力欄に反映するようにしてください。

#### デプロイ先アプリの設定

またApp Centerに戻り、アプリをクリックすると、 **Getting Started** のページが表示されます。
ここのURLをコピーしてください。
URLは https://appcenter.ms/users/{xxx}/apps/{yyy} という形式になっています。

VSTSのビルド設定に戻り、 **App Slug** 欄に先のURLから **{xxx}/{yyy}** という形式で入力します。
これでアプリの指定をしたことになります。

最後に、 **Release Note** を適当に書いて **Save & queue** をしてください。

### デプロイできるか確認する

**Queue** してビルドタスクが全て成功すると、App CenterにReleaseとして登録されています。
アプリのページを開き、左メニュー内の **Distribute** → **Releases** を開き、ちゃんとデプロイされているか確認してください。
デプロイできていれば、リリースが増えていきます。

## デプロイできたら

デプロイがちゃんとできたら、次は連携です。
App Centerで実機にインストールしたアプリから通知をApp Centerに送り、Exceptionの場合はVSTSへのチケットを作成するようにしてみましょう。

### アプリ→App Centerのための設定

App Centerのアプリの **Getting Started** のページを開くと、アプリを作った時のPlatformによってApp Center用のライブラリの追加の方法が載っています。
今回はXamarin.Formsなので、Xamarinを選んであります。
その場合、ページ内でXamarinとXamarin.Formsを切り替えられるようになっており、それによって書き方が変わってきます。

まずはここに書いてある設定をアプリに入れ込みます。

### トレース用のメッセージを通知するように設定する

アプリからApp Centerへメッセージを送る場合、以下のような関数でメッセージを送信できます。
**Analytics.TrackEvent** メソッドでメッセージを送信しています。

```csharp
_button.Clicked += (s, e) => {
    Analytics.TrackEvent("Hello, App Center");
};
```

送信されたデータは、App Centerのアプリのページ内の **Analytics** → **Events** から確認できます。
同一のデータはグループでまとめられ、報告回数やユーザー数などがわかるようになっています。

<img width="1010" alt="012.png" src="https://qiita-image-store.s3.amazonaws.com/0/59270/9b348709-68a7-0e4c-97ef-ba3dd49aa6b2.png">

各々の行をクリックすると、詳細データが表示されます。

<img width="616" alt="013.png" src="https://qiita-image-store.s3.amazonaws.com/0/59270/ad17e516-8c8a-6c5d-8231-56340f3540f5.png">

### Exceptionのデータを送るように設定する

アプリからApp CenterへExceptionのデータを送る場合、以下のような関数でメッセージを送信できます。

```csharp
try
{
    object n = null;
    Page p = (Page)n;
    p.Title = "";
}
catch (Exception ex)
{
    Crashes.TrackError(ex);
}
```

ぬるぽが発生したら try〜catchで捕まえて、 **Crashes.TrackError** メソッドでExceptionの内容を送っています。
送信されたデータは、App Centerのアプリのページ内の **Diagnostics** → **Errors** で確認できます。
同一のデータはグループでまとめられ、報告回数やユーザー数などがわかるようになっています。

<img width="1005" alt="014.png" src="https://qiita-image-store.s3.amazonaws.com/0/59270/f1a29755-00a0-9a32-c43b-8b3d939c16a0.png">

各々の行をクリックすると、詳細データが表示されます。

<img width="1030" alt="015.png" src="https://qiita-image-store.s3.amazonaws.com/0/59270/9569a951-dc41-af08-155c-a312acf6ca0b.png">

### クラッシュのデータを送るようにする

これは特に設定をしなくても **Getting Started** に書いてある設定をするだけで送られるようです。
App Centerのアプリのページの **Diagnotics** → **Crashes** で確認できます。
同一のクラッシュはグループでまとめられ、報告回数やユーザー数などがわかるようになっています。

<img width="1043" alt="016.png" src="https://qiita-image-store.s3.amazonaws.com/0/59270/f6fe9607-84b3-36ef-7e19-0504ddcc8f23.png">

各々の行をクリックすると、詳細データが表示されます。

<img width="899" alt="017.png" src="https://qiita-image-store.s3.amazonaws.com/0/59270/744c68d6-488a-b34e-05ae-30dbb08d4b77.png">

### 送られてきたクラッシュのデータをVSTSのチケットとして登録させる

正確には、上記のクラッシュグループごとにチケットとして登録されます。

App Centerのアプリケーションのページを表示し、左側から **Settings** → **Services** を選び、 **VSTS** を選択します。
そうすると、プロジェクトの一覧が表示されるので、一覧の中から目的のプロジェクトを選択して **Next** をクリック。
次の画面では、 **Default payload (optional):** の欄に `{"System.IterationPath": "Iteration 1"}` と入力します。
Iteration名は適当に変更してください。

そして、アプリでクラッシュが起こるとチケットが登録されるようになります。
前項のクラッシュだと、

<img width="1063" alt="018.png" src="https://qiita-image-store.s3.amazonaws.com/0/59270/9be02d2e-2d4a-bdcf-a2c6-1a68a995f19f.png">

こんな感じ。

なお、最初に **Settings** → **Services** の際にGitHubやJiraを選べばそちらでもチケット管理ができるようになるようです。

これで、不具合調査・管理が楽にできそうですね。

## 書いている途中に

これ、書くのに３日くらいかかってるんですが。
書いてる途中でVSTSのBuildの画面構成が変わりました orz
そりゃ、Webのサービスなので、いつこういうことがあるのかはわかりませんよね…。

また、App Centerの **Crashes** とかはPreviewの文字が踊ってます。
いつ、どう変化するかわかりません…。

よく考えると、こんなに一気に書かずに iOS/Android/App Center と分けて書けば３つに分けられたんじゃ…。
まあいいか。