3ステップでslack連携を行おう！[unity向け]

## 前提
unityを使った開発をしてる際に作りました。
実際の業務開発だったら普通にデバッグできるのであんまり使わないと思いますが、趣味での利用なりなんなり使える箇所はあると思います。

## Introduction
unityを使ってアプリを作ってるときであれば、デバッグしながら動かしたりlog出力したりとかはいくらでもできますよね。
けどそこから実機(iPhone,Android,HoloLens,etc.)で試そうとした際にエラーメッセージ見づらい！
ってなったのでslackにunityから投げる仕組みを作りました。大体はコピペで張り付ければ使えるはずです。

## 使用にあたって
実機にデプロイする際には`networking permission`の設定を許可する箇所が必ずどこかにあります。(対象デバイスによってまちまちなのでここでの紹介は割愛。)
当然ながらnetwork経由でのslack投稿になるので、networking permissionをactivateしないと投稿されませんのでご注意を。

## ソースコード
とりあえずソースコード

``` CS
using System;
using System.Collections;
using UnityEngine;

namespace SlackApi
{
    [Serializable]
    public class PostMessageData
    {
        public readonly string token = "enter your slack token";
        public readonly string channel = "enter your slack channel";
        public readonly string icon_url = "enter your own icon url";
        public string text = "unityからSlackに連携したよ！";
        public string parse = string.Empty;
        public string link_names = string.Empty;
        public string username = "ゆにてぃちゃん！";
        public string icon_emoji = string.Empty;
    }

    [Serializable]
    public class UploadData
    {
        public readonly string token = "enter your slack token";
        public readonly string channel = "enter your slack channel";
        public string filename = DateTime.Now.ToString();
        public string text = "unityからSlackに連携したよ！";
        public string title = "画像を上げるよ！" + DateTime.Now.ToString("yyyyMMddHHmmss");
        public string initial_comment = string.Empty;
        public readonly string username = "ゆにてぃちゃん！";
        public string icon_url = "enter your own icon url";
    }

    public static class SlackAPI
    {
        public static IEnumerator PostMessage(
            PostMessageData data,
            Action onSuccess = null,
            Action<string> onError = null
        )
        {
            var form = new WWWForm();
            form.AddField("text", data.text);
            form.AddField("parse", data.parse);
            form.AddField("link_names", data.link_names);
            form.AddField("username", data.username);
            form.AddField("icon_emoji", data.icon_emoji);

            form.AddField("token", data.token);
            form.AddField("channel", data.channel);
            form.AddField("icon_url", data.icon_url);
            var url = "https://slack.com/api/chat.postMessage";
            var www = new WWW(url, form);
            yield return www;
            var error = www.error;

            if (!string.IsNullOrEmpty(error))
            {
                if (onError != null)
                {
                    onError.Invoke(error);
                }

                yield break;
            }

            if (onSuccess != null)
                onSuccess.Invoke();
        }

        public static IEnumerator UploadScreenShot(
            UploadData data,
            int? x = null,
            int? y = null,
            Action onSuccess = null,
            Action<string> onError = null

        )
        {
            yield return new WaitForEndOfFrame();
            if (x == null) x = 0;
            if (y == null) y = 0;

            var width = Screen.width;
            var height = Screen.height;
            var texture = new Texture2D(width, height, TextureFormat.ARGB32, false);
            var source = new Rect(x.Value, y.Value, width, height);

            texture.ReadPixels(source, 0, 0);
            texture.Apply();

            var form = new WWWForm();
            var contents = texture.EncodeToPNG();

            form.AddField("text", data.text);
            form.AddField("title", data.title);
            form.AddField("initial_comment", data.initial_comment);
            form.AddField("username", data.username);
            form.AddField("icon_url", data.icon_url);

            form.AddField("token", data.token);
            form.AddField("channel", data.channel);
            form.AddBinaryData("file", contents, data.filename, "image/png");

            var url = "https://slack.com/api/files.upload";
            var www = new WWW(url, form);
            yield return www;
            var error = www.error;

            if (!string.IsNullOrEmpty(error))
            {
                if (onError != null)
                {
                    onError.Invoke(error);
                }
                yield break;
            }
            else
            {
                Debug.Log("Success!!!");
                onSuccess();
            }
        }
    }
}
```

### 使用手順
1,後はこれを`SlackAPI`って名前でunity内で作成すること。
2,`token`,`channel`を入力してください。(左記項目は必須。その他項目についてはご自由に)
  ※slack tokenの取得については[こちら](https://api.slack.com/custom-integrations/legacy-tokens)
3,後はこれを他のメソッドなりから呼び出すだけ！簡単！
呼び出し方についてはunityのお作法通りに以下のようにCoroutine使って呼べばいいだけです。
実例は以下の通り。

``` CS
using SlackApi;
using System;
using System.Collections;
using System.Net;
using System.Threading;

public class SignalRConnection : MonoBehaviour
{
    private void Start()
    {
        try
        {     
        }
        catch (Exception ex)
        {
            var message = DateTime.Now.ToString("MM/dd HH:mm:ss") + "\r\n" +
                         "ex.Message:" + ex.Message + "\r\n" +
                         "ex.StackTrace:" + ex.StackTrace;

            var data = new PostMessageData { };
            data.text = message;
            data.username = "例外を検出しました！ from " + SystemInfo.deviceName;

            var routine = SlackAPI.PostMessage(data);
            StartCoroutine(routine);
        }
    }
}
```

こんな具合にtry~catchに仕込んで、実機で何か発生したときにslackに投げてくれるような感じです。
　
## 最後に
unityを使っての開発だとunity editor上と実機上で異なる振る舞いを見せることが多々あります。
その際にはやはりエラーメッセージを元に修正するのが一番早いのでそれの可視化は必須です。そのための簡単かつ導入敷居の低いslackを紹介しましたのでuntiy開発する際は是非ご検討を。