Azure HockeyApp でモバイル アプリの開発/配布(ベータテスト)/クラッシュレポーティング

#Azure HockeyApp とは
>**[HockeyApp \| Microsoft Azure](https://azure.microsoft.com/ja-jp/services/hockeyapp/)**
> *モバイル アプリの開発、配布、ベータ テスト*
> *Android、Cordova、iOS、OS X、Unity、Windows、Xamarin のアプリをサポート*
> 
> - 信頼できるクラッシュ レポートを即時に利用可能
> - アプリ内で実際のユーザーからフィードバックを収集
> - アプリで実行中のコードを把握できるオープン ソース SDK
> - 既存のビルド システムおよび作業項目管理ソリューションに統合

[HockeyApp](https://hockeyapp.net/)は、2014/12/11にMicrosoftにジョインし、Azureの一員となった モバイル DevOps ソリューションになります。テスト担当者にビルドを配布、メトリックスの追跡やクラッシュの情報を収集したり、ユーザーからのフィードバックを得ることが出来ます。 

#HockeyAppを使ってみる

##HockeyAppにサインイン

1. ブラウザでHockeyAppを表示します。
https://www.hockeyapp.net/
![HockeyApp - The Platform for Your Apps.png](https://qiita-image-store.s3.amazonaws.com/0/12177/129f0b67-da9d-b1fe-fb75-4ce76a77444c.png)
*※コンソールはAzure ポータルに統合はされていませんが、Microsoft Accountでのサインインには対応しています。*

2. Microsoft アカウントでログインします。
    ![Sign In – HockeyApp.png](https://qiita-image-store.s3.amazonaws.com/0/12177/c30d4c30-ec80-a45b-e4ad-7aff6039cacb.png)

##HockeyAppにAppの作成

  ログインするとアプリケーションのチュートリアルが始まります。
  今回は、AndroidアプリにHockeyAppを組み込みたいと思います。

1. [Integrate SDK]で[Android]を選択し、[Start Integration]をクリックします。
    ![Dashboard – HockeyApp.png](https://qiita-image-store.s3.amazonaws.com/0/12177/159f5226-48e4-d816-e692-5ef1d92a042d.png)
2. [Create App]画面で、[Platform]は[Android]を選択、[Releate Type]は[beta]を選択(※テスター配布目的のため)、[Title]と[Package Name]に任意の名前を入力し、[Next Step]をクリックします。
   ![Integration_ Create App – HockeyApp.png](https://qiita-image-store.s3.amazonaws.com/0/12177/4c2362af-77af-9f89-c90a-9a22fff57ae7.png)
3. [Add dependency]に、アプリに設定する内容が表示されます。

    ※この内容はAndroidアプリの作成で説明します。
    ![Integration_ Add dependency – HockeyApp.png](https://qiita-image-store.s3.amazonaws.com/0/12177/e050bc22-8967-19db-5c38-fe9a83cdc8c8.png)
4. [Integrate SDK]の、アプリに設定する内容が表示されます。

    ※この内容はAndroidアプリの作成で説明します。
　　　　![Integration__Integrate_SDK_–_HockeyApp_1_.png](https://qiita-image-store.s3.amazonaws.com/0/12177/2429915b-77b9-aadc-63df-487182919edf.png)

##Androidアプリの作成

1. アプリ作成

    [Application Name]と[Package Name]は、HockeyAppで登録した内容と合わせます。
    ![Create_New_Project.png](https://qiita-image-store.s3.amazonaws.com/0/12177/c6e08bc7-daf0-b195-09e4-265f4b82a933.png)

2. アプリのActivityに[Navigation Drawer Activity]を選択

    *画面遷移のアクション時の収集をしたいため*
　　　　　　　　![Create_New_Project_3.png](https://qiita-image-store.s3.amazonaws.com/0/12177/c96d1f26-8e5f-675e-4dfb-53fc747c593c.png)

3. build.gradleの設定

    1. android -> defaultConfig に HOCKEYAPP_APP_IDを追加

        ```groovy
        manifestPlaceholders = [HOCKEYAPP_APP_ID: "1234567890123456789012345678901"]
        ```

    2. android -> dependencies に HockeySDKを追加

        ```groovy
        compile 'net.hockeyapp.android:HockeySDK:4.1.1'
        ```

    ![app_-_HockeyAppExample_-____Dropbox_Devs_AndroidWorkspace_MySample_HockeyAppExample_.png](https://qiita-image-store.s3.amazonaws.com/0/12177/48b1aef0-bef4-463b-e4b2-29726ad2d97c.png)

4. AndroidManifest.xmlの設定

    1. application に HOCKEYAPP_APP_IDのmeta-dataを追加

        ```xml
        <meta-data
            android:name="net.hockeyapp.android.appIdentifier"
            android:value="${HOCKEYAPP_APP_ID}" />
        ```
    ![AndroidManifest_xml_-_HockeyAppExample_-____Dropbox_Devs_AndroidWorkspace_MySample_HockeyAppExample_.png](https://qiita-image-store.s3.amazonaws.com/0/12177/ec9172bf-d67f-381a-8abb-929610b2d469.png)

###クラッシュ レポーティング

アプリにクラッシュレポート機能を追加します。

1. MainActivityに以下の行を追加します。

    ```java
        @Override
        protected void onResume() {
            super.onResume();

            checkForCrashes();
        }

        private void checkForCrashes() {
            CrashManager.register(this);
        }
    ```
    onReasume 時に、クラッシュレポーティングの機能を有効にし、以前のクラッシュが存在するかチェックします。クラッシュが存在した場合、HockeyAppにクラッシュログを送信するかどうかの確認ダイアログが表示されます。

2. 任意のタイミングで以下のよう例外を発生させてみます。

    ```java
    throw new RuntimeException("Oops! RuntimeException!");
    ```

3. アプリがクラッシュします。
    ![device-2016-11-08-102245.png](https://qiita-image-store.s3.amazonaws.com/0/12177/99f1e51c-5dcc-f5f8-0b10-17d246a41768.png)

4. アプリを再起動すると、クラッシュログ送信の確認ダイアログが表示されます。
    ![device-2016-11-08-102255.png](https://qiita-image-store.s3.amazonaws.com/0/12177/ccee32fb-f3ed-5413-fe49-c279e42cdea6.png)

    [SEND REPORT]をタップします。

5. HockeyAppのAppページにCrashesにクラッシュログが追加されています。
    ![Crash_Groups_for_HockeyAppExample_–_HockeyApp.png](https://qiita-image-store.s3.amazonaws.com/0/12177/c57a6238-3ab3-cb15-6661-1bfb6490cf35.png)

6. ユーザーの確認無しに、クラッシュログを自動的に送信したい場合は、CrashManagerListenerをカスタムします。

    ```java
    private void checkForCrashes() {
        String appIdentifier = Util.getAppIdentifier(this);
        CrashManager.register(this, appIdentifier, new CrashManagerListener() {
            @Override
            public boolean shouldAutoUploadCrashes() {
                // クラッシュログを自動的に送信
                return true;
            }
        });
    }
    ```

###アップデートの配布

アプリ内にアップデートの機能を追加します。

1. MainActivityに以下の行を追加します。

    ```java
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ...
        checkForUpdates();
    }

    @Override
    public void onPause() {
        super.onPause();
        unregisterManagers();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterManagers();
    }

    private void checkForUpdates() {
        UpdateManager.register(this);
    }

    private void unregisterManagers() {
        UpdateManager.unregister();
    }
    ```
    onCreate 時に、バックグラウンドでアップデートのチェックを行います。新しいアップデートが存在した場合、アラートダイアログが表示されます。

2. HockeyAppのAppページでAPKを更新します。

    1. [Add Version]をクリックします。
    ![HockeyAppExample_2.png](https://qiita-image-store.s3.amazonaws.com/0/12177/ecb0ba14-4f21-8f0a-8eda-e71a479d2c08.png)

    2. 新しいAPKをDrag and Dropします。
    ![HockeyAppExample__1_.png](https://qiita-image-store.s3.amazonaws.com/0/12177/0c795d94-b858-4f0d-63e6-4c35448b8149.png)

    3. リリースノートの入力
    ![Release notes for version 1.0 (1) of.png](https://qiita-image-store.s3.amazonaws.com/0/12177/13817a3e-a940-86ad-fd52-836588aa1b4d.png)
 
    4. ステータスの指定
    ![Download flags for version 1.0 (1) of.png](https://qiita-image-store.s3.amazonaws.com/0/12177/e7bc575a-4a24-aca0-3ecd-4fe1df21aa27.png)
        * [Installation] -> [Yes] ... アプリでアップデートのアラートダイアログを表示するために[Yes]を選択します。
        * [Restrict Downloads] -> [No] ... ダウンロードの制限は指定しません。

    5. 通知の指定
    ![Notifications for version 1.0 (1) of.png](https://qiita-image-store.s3.amazonaws.com/0/12177/7b262b9d-0ea8-fc1a-a245-2cee98ccda5c.png)

    6. [Done]ボタンをクリックして完了します。
    ![Released version 1.0 (1) of HockeyAppExample.png](https://qiita-image-store.s3.amazonaws.com/0/12177/a213fa56-f592-d47c-8d46-cec6f78b607f.png)

3. アプリを再起動すると、アップデートのアラートダイアログを表示されます。
![device-2016-11-08-112135.png](https://qiita-image-store.s3.amazonaws.com/0/12177/d7369a51-4a50-5660-b05f-eb5722101e66.png)

4. アラートダイアログで、[SHOW]ボタンをタップすると、アップデートの画面が表示されます。
![device-2016-11-08-134827.png](https://qiita-image-store.s3.amazonaws.com/0/12177/5aea1d37-76a4-4e3d-0724-a2739cbe219e.png)

    [UPDATE]ボタンをタップするとアプリのインストールが始まります。

###アプリ内フィードバック

アプリ内からのユーザーフィードバック機能を追加します。

1. MainActivityに以下の行を追加します。
        
    ```java
    @Override
    public void onCreate(Bundle savedInstanceState) {
        // ...

        FeedbackManager.register(this);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                FeedbackManager.showFeedbackActivity(MainActivity.this);
            }
        });
    }
    ```
    FloatingActionButtonでフィードバックを送るFeedbackActivityを起動出来るようにします。

2. アプリを再ビルドし再起動
    1. FloatingActionButtonをタップして、FeedbackActivityを起動します。
    2. 入力フォーム画面が表示されるので、各項目を入力して、[SEND FEEDBACK]ボタンをタップします。
    ![device-2016-11-08-140243.png](https://qiita-image-store.s3.amazonaws.com/0/12177/9d0b413e-b05e-d074-4ead-2aaffdaf400f.png)

        [ADD ATTACHMENT]ボタンでファイルを添付することも可能です。

3. HockeyAppのAppページでフィードバックの確認
    1. Feedbackタブで、ユーザーから送信されてきたフィードバックを読むことが出来ます。
    ![Feedback_for_HockeyAppExample_–_HockeyApp__1_.png](https://qiita-image-store.s3.amazonaws.com/0/12177/b1168df4-ee48-71da-1fd0-067a7c46f7d1.png)
    2. ユーザーフィードバックに対してコメントを返信することも可能です。
    ![Awesome_App__HockeyAppExample__–_HockeyApp.png](https://qiita-image-store.s3.amazonaws.com/0/12177/3d4e6ec2-01c2-169f-c700-a5d1297c9b90.png)

4. アプリでフィードバックに対してのコメントを確認
    1. 再度、FeedbackActivityを起動すると、開発者からのコメントを確認できます。
    ![device-2016-11-08-144314.png](https://qiita-image-store.s3.amazonaws.com/0/12177/07d5f0a2-5c1f-6d89-e74f-7796c232f57e.png)
    [ADD A RESPONSE]ボタンで、新たなフィードバックを送ることが出来るようになっており、ユーザーと開発者のディスカッションが可能となります。

###ユーザーメトリックス

ユーザーのアプリの使用状況を自動的に計測する機能を追加します。

1. MainActivityに以下の行を追加します。
        
    ```java
    @Override
    public void onCreate(Bundle savedInstanceState) {
        // ...

        MetricsManager.register(getApplication());
    }
    ```
    これだけで、セッションとユーザーの統計を収集することが出来ます。

2. HockeyAppのAppページでユーザーメトリックスの確認
![HockeyAppExample (4).png](https://qiita-image-store.s3.amazonaws.com/0/12177/fef5afaf-1f04-83a5-8647-35d85c45bdb2.png)

3. カスタムイベントを追加するには以下の行を追加します。

    ```java
    MetricsManager.trackEvent("YOUR_EVENT_NAME");
    ```

    以下のコードでは、Navigation Drawerのイベントをトラッキングしています。

    ```java
    @SuppressWarnings("StatementWithEmptyBody")
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();

        if (id == R.id.nav_camera) {
            // Handle the camera action
            MetricsManager.trackEvent("NAV_CAMERA");
        } else if (id == R.id.nav_gallery) {
            MetricsManager.trackEvent("NAV_GALLERY");
        } else if (id == R.id.nav_slideshow) {
            MetricsManager.trackEvent("NAV_SLIDESHOW");

        } else if (id == R.id.nav_manage) {
            MetricsManager.trackEvent("NAV_MANAGE");

        } else if (id == R.id.nav_share) {
            MetricsManager.trackEvent("NAV_SHARE");

        } else if (id == R.id.nav_send) {
            MetricsManager.trackEvent("NAV_SEND");

        }

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }
    ```

4. HockeyAppのAppページでカスタムイベントの確認
    1. Evensタブで、カスタムイベントの状況を確認することが出来ます。
    ![Custom_Events_–_HockeyApp.png](https://qiita-image-store.s3.amazonaws.com/0/12177/3856f26c-837e-9190-155a-614532744a54.png)

    注)メトリックスのアップロードと反映には少し時間が掛かります。

#まとめ
Azure HockeyAppを使用すると、ベータ配信/クラッシュレポート/ユーザーメトリックス/ユーザーフィードバックなど、アプリ品質を向上させるための仕組みを簡単に組み込むことが出来ました。
基本的にはアプリの管理はWebだけで完結することが出来ますが、ネイティブのツールも提供されており使いやすくなっています。 -> [HockeyApp for Mac](https://rink.hockeyapp.net/apps/67503a7926431872c4b6c1549f5bd6b1), [HockeyApp for Android](https://rink.hockeyapp.net/apps/0873e2b98ad046a92c170a243a8515f6)
iOSのツールも提供されており、配布の為にデバイスのUUIDの収集などを用意にしてくれます。 -> [HockeyApp for iOS](https://install.hockeyapp.net/)
サードパーティの Bug Trackers, Services, and Webhooks (GitHub,Slack等々) がサポートされているのでDevOpsのエコシステムに組み入れるのは容易ではないと思います。 -> [Knowledge Base \- HockeyApp Support](https://support.hockeyapp.net/kb)

Let's play Hockey! :smile: