Unityから、SlackApiを通して、スクリーンショットやテキストファイルを上げる

概要

Unity Slack 投稿 などとかで調べると結構な記事がでるけれど、それぞれ、Token ってどれ?とか、それはSlackApi側のどこから取ってくるの? とか。 SlackApiとそれを送るフォーマットとかにおいて、むっちゃつまってしまっていたので、とりあえず、自分が、この手順で行ったらできるようにするためのものです。

環境

Unity2018.4.20f

2021年8月15日現在時点でのSlackApi周りの内容です。 これはタイミングによっては、権限に当たるもののWeb上でのUIが変化する場合があります。

前提

Slackのワークスペースを持っている状態である。 SlackのチャンネルにAppなどの追加する権限をそのワークスペース内で保有している。

というのが前提です。

これを通してやった結果できる事

Unityから、Slackに対して、テキストファイル や 画像ファイル(今回はスクリーンショット)を送る事ができる

ひとまず必要な作業内容

やる内容としては以下の通りです。 主にSlack側での準備が主になります。

  • Slack側
    • SlackApiの準備
      • 権限周りの付与
      • Accesstokenの取得
    • Cannel側
      • 作成したSlackApiをCannelに入れる
  • Unity側
    • 送る部分の実装

Slack

SlackApiの準備

以下のサイトにアクセスします。

https://api.slack.com/

このタイミングだと、ちょうど以下のようなページに飛ぶと思います。

f:id:herie270714:20210815170504p:plain

これの右上の [Your apps] というのがあるので、それをクリックします。 するとこの画面になるので、ここから [Create New App]というのがあるので、それをクリックします。するとポップアップみたいな画面が出てくるので、 そこから[From Scratch]->AppNameを入力します。 名前はなんでも構いません。

f:id:herie270714:20210815172822p:plain

次に、Pick a workspace to develop your app in: というのがあるのですが、場合によっては候補として出ない場合があります。 出ない場合は、少し舌のSign into a different workspaceを選んで、Appを入れたいワークスペースに一度自分の認証を通す事で出てきます。

終わったら、CreateAppを押しましょう。 すると以下の画面です。

f:id:herie270714:20210815170538p:plain

これでSlackApp(以下App)が作成されました この画面で、作成するAppに対して、権限の付与や、Tokenの取得を行います。

 権限周りの付与

さて、いよいよ権限まわりの付与です。 現状のAppは、あなたのワークスペースに入れたとしても権限がないので、チャンネルに書き込みもできないし、まして画像も投稿できない状態です。 なので、権限を付与する必要があります。

f:id:herie270714:20210815170802p:plain

権限の付与は、[Add feature and functionality]を押すと 折り畳みが展開されて以下のような感じのものが出てきます。

f:id:herie270714:20210815170824p:plain

これの[Permissions]というのを選択します。 すると画面が変わって、 OAuth&Permissionsというタイトルの画面に変わります。

f:id:herie270714:20210815170923p:plain

ここを下にスクロールすると Scopesという項目があります。 ここで、BotTokenとUserTokenというものがありますが 今回は、BotTokenの方に権限を付与していきます。

このBotTokenとUserTokenの違いはこの記事では言及しませんが、 個人的な認識としては、UserTokenは、Userとしての操作(チャンネルのUser操作など)が必要な権限が該当するみたいな認識です。

え [Add an OAuth Scope]というボタンを押して

files:write を選択します。

これは、Slackのチャンネルに対してファイル関係(画像、テキストなど)をどうかするためのものです。

AccessTokenの取得

権限を付与すると上にスクロールして戻り、 OAuth Token for Your WorkSpaceという項目の[Install to Worksapce]というボタンがあるので、これを押します。

すると以下のような感じの画面になります。 ここで確認すべき内容は、実行できる内容は?の下の文言で、 この部分が、選択した権限の内容になっていればオーケーです。

f:id:herie270714:20210815172506p:plain

チャンネルと会話でアクションを実行する アプリ名としてファイルをアップロード、編集、削除する

となっていればOkです。

許可をすると、元の画面に戻ります。 その際に、Slack側のApp欄に、作成したAppが存在している事を確認してください。

Web画面の方に戻って、 以下の画像の赤枠の部分のTokenがこのワークスペースの上でのこのAppのAccessTokenです。他のサイトではApiTokenなどの名前でも呼ばれている場合がありますが、ここではAccessTokenという呼び名で呼びます。

f:id:herie270714:20210815172723p:plain

作成したSlackApiをCannelに入れる

この段階では、ワークスペースに作成したAppが入っただけなので、この状態だとまだ送る事ができません。 このAppを流したいfileを上げたいCannelに入れる必要があります。

アプリでのSlack側のUIの右上の[このチャンネルの全てのメンバーを表示する]という部分を表示し、その項目の[インテグレーション]という項目があるので、そこをクリックします。

アプリを追加するという項目があるので、作成したAppを入れます。 するとチャンネルのメッセージに

ユーザー名さんにより#チャンネル名に追加されました

といった文章が出てきたら、OKです。 これでSlack側の準備は完了したので、次にUnity側の準備に移ります。

Unity側の準備

Unity側の準備 基本的には、UnityWebRequestに対してWWWFormを通じて送信するスタイルを取ろうと思っています。

とりあえずサンプルコード全体図

サンプルコード全体図

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class SlackApiSample : MonoBehaviour 
{

    /// <summary>
    /// スクリーンショットデータのとりあえずの保存場所
    /// </summary>
    private byte[] screenData;

    /// <summary>
    /// Slack API 関連のもの URLとして必要
    /// </summary>
    private static readonly string SlackApiUrl = "https://slack.com/api";
    private static readonly string ChatPostURL = "/chat.postMessage";
    private static readonly string UploadEndPoint = "/files.upload";

    private string CannelName = "#チャンネル名";
    private string BotAccessToken = "xoxb-あなたのAccessToken";


    public void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
        Send();
        }
    }


    private void Send()
    {
    StartCoroutine(SendRequest());
    }

    private IEnumerator SendRequest()
    {
    yield return CreateScreenShotData();

    var form = BuildScreenShotUploadRequest();
    var request = UnityWebRequest.Post(SlackApiUrl + UploadEndPoint,form);
    request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
    var operation = request.SendWebRequest();

        while(!operation.isDone)
        {
            yield return null;
        }

        if(request.isHttpError)
        {
        Debug.LogFormat("requestError:{0}", request.error);
        }
    else
        {
        Debug.Log(request.downloadHandler.text);
        Debug.Log(request.isNetworkError);
        }

        yield return null;
    }


private IEnumerator CreateScreenShotData()
{
    yield return new WaitForEndOfFrame();
    var tex = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);

    tex.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
    tex.Apply();

    screenData = tex.EncodeToPNG();
        
    Object.Destroy(tex);

    yield return new WaitForEndOfFrame();
    yield return null;
}


private WWWForm BuildScreenShotUploadRequest()
 {
        WWWForm form = new WWWForm();
        form.AddField("token",BotAccessToken);
        form.AddField("channels", CannelName);
        form.AddField("title", "titleの中身が入る");
        form.AddField("filename", "screenshot.png");
        form.AddField("initial_comment","メッセージ");
        form.AddBinaryData("file", screenData, "ssssss.png", "image/png");

        return form;
    }

}

基本的には、UnityWebRequestで URL と 表示情報であるWWWFormの内容を送っています。

ここでの説明としては、全部で2つあって 1. Slack側で準備した情報で必要なもの 2. 送るのに必要なデータ

URLは今回

 private static readonly string SlackApiUrl = "https://slack.com/api";
    private static readonly string UploadEndPoint = "/files.upload";

が必要になります。 これが、ファイルをアップロードする上で必要なものであるためのURLです。

送っているデータの内容の箇所はここ

private WWWForm BuildScreenShotUploadRequest()
    {
        WWWForm form = new WWWForm();
        form.AddField("token",BotAccessToken);
        form.AddField("channels", CannelName);
        form.AddField("title", "titleの中身が入る");
        form.AddField("filename", "screenshot.png");
        form.AddField("initial_comment","メッセージ");
        form.AddBinaryData("file", screenData, "ssssss.png", "image/png");

        return form;
    }

それぞれのパラメーターは、確認している感じ以下の意味合いです。 左がキー値、右が値になります。

token = SlackApiで取得したAccessToken channels = 送るチャンネル名 title = 画像などのプレビューの際のタイトル filename = 送った内容 initial_comment = Slack投稿時のメッセージです。 file = byte配列のデータ、?、データ形式

基本的に、この6つの情報が必要になり、AccessTokenはここで使用する事になります。

うまく送れないなってなったときの対処法

基本的には、以下のコードで取得できるコード部分から発行されるエラーとかが出るのでそれを元に対処します。

        if(request.isHttpError)
        {
        Debug.LogFormat("requestError:{0}", request.error);
        }
    else
        {
        Debug.Log(request.downloadHandler.text);
        Debug.Log(request.isNetworkError);
        }

例えばこんなログ

{"ok":false,"error":"invalid_form_data"}

この場合は送る際に、送る形式が違うなどがあります。 なので、送る際のForm内容、もしくはRequest内容に修正をかける必要があります。

終わりに

結構書かれた時期や用途によって書き方がWWW形式だったり、サンプルそのまま動かしてもなぜかうまくいかない等があったため、またやる機会があった際に振り返れるようにと思い記述しました。

同じ苦労をしている人が、少しでも減る事を祈ります。

また、サンプルコード使用による責任は当ブログは一切責任とりません。