NRIネットコム Blog

NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

OneTapでSlackに投稿するアプリを作ってみた

本記事は  モバイルアプリWeek  1日目の記事です。
📱  イベント告知  ▶▶ 本記事 ▶▶  2日目  📱


SwiftでSlackに投稿するための準備から、実際に投稿してみる所までを試作してみたのでまとめました!

準備:Slack appを作成する

以前はカスタムインテグレーションよりIncoming Webhookを主に利用していたようです。
しかし、2020年よりカスタムインテグレーションを利用することが非推奨になっているので現時点(2022年)で推奨されているSlack Appを利用した方法で実装&紹介させて頂きます。

(カスタムインテグレーションに関するドキュメント)

api.slack.com

WebhookのURLを取得する

手順は以下の通りです。

  1. 右記よりSlack APIの画面を表示 Slack API: Applications | Slack
  2. Create New Appを選択
  3. Form scratchを選択
  4. App Nameに好きな名前を入力し、紐づけたいworkspaceを選択してCreate Appを選択
  5. Basic InformationよりIncoming Webhooksを選択
  6. Activate Incoming WebhooksをOnにし、Add New Webhook to Workspaceを選択
  7. 投稿先チャンネルをダウンリストから選択できるので任意のチャンネルを選択
  8. Webhook URLが発行されるのでコピーなどしてメモしておく

WebhookのURLが発行されるとこのように表示される

以上でSlack appを利用する準備は終了です。

実装:コードを書いていく

ここからは実際にコードを書いていく作業になります。
と言っても今回はほぼツールを使ってコードを生成していくのでほぼ書かなくてもできます!w

Slackへ投稿するには上記で取得したWebhook URLにJSONをパラメタとして POSTリクエストします。
今回attachmentsを利用しましたがattachmentsがどういったものか、違いは以下の通りです。

attachments無し

{
    "blocks": [
        {
            "type": "context",
            "elements": [
                {
                    "type": "image",
                    "image_url": "https://pbs.twimg.com/profile_images/625633822235693056/lNGUneLX_400x400.jpg",
                    "alt_text": "cute cat"
                },
                {
                    "type": "plain_text",
                    "text": "UserName: Tama",
             }
            ]
        },
        {
            "type": "section",
            "text": {
                "type": "plain_text",
                "text": "今から仕事始める!",
         }
        }
    ]
}

attachments有り

{
    "attachments": [
        {
            "color": "#f2c744",
            "blocks": [
                {
                    "type": "context",
                    "elements": [
                        {
                            "type": "image",
                            "image_url": "https://pbs.twimg.com/profile_images/625633822235693056/lNGUneLX_400x400.jpg",
                            "alt_text": "cute cat"
                        },
                        {
                            "type": "plain_text",
                            "text": "UserName: Tama"
                        }
                    ]
                },
                {
                    "type": "section",
                    "text": {
                        "type": "plain_text",
                        "text": "今から仕事始める!"
                    }
                }
            ]
        }
    ]
}

上記の通りattachmentsを使用する場合はattachmentsを追加し、その中にblockを書いていきます。

またBlock Kit Builderと言うプレビュー表示をしてくれる便利なものが公式にありますので、ここで事前に確認すると良いかと思います。
(以下のURLよりBuild and prototype visuallyにてBlock Kit Builderを試すことができます)

api.slack.com

ドキュメントを見ると基本的にはblocks内に(もしくはfields内)にtextやimageを配置してカスタマイズしていきますが、attachments直下に書くこともできます。
今回はこちらのがシンプルにかけるので採用しましたが、Imageをtextの間に表示させたいとかになるとドキュメントを見る限り"elements"を使用しなければできないと思いますので、そこはお好みで採択していただければと思います。

一応下記にattachments直下に書くサンプルコードを掲載しておきます。

{
  "channel": "CBR2V3XEX",
  "attachments": [
      {
          "fallback": "Plain-text summary of the attachment.",
          "color": "#2eb886",
          "pretext": "Optional text that appears above the attachment block",
          "author_name": "Bobby Tables",
          "author_link": "http://flickr.com/bobby/",
          "author_icon": "http://flickr.com/icons/bobby.jpg",
          "title": "Slack API Documentation",
          "title_link": "https://api.slack.com/",
          "text": "Optional text that appears within the attachment",
          "fields": [
              {
                  "title": "Priority",
                  "value": "High",
                  "short": false
              }
          ],
          "image_url": "http://my-website.com/path/to/image.jpg",
          "thumb_url": "http://example.com/path/to/thumb.png",
          "footer": "Slack API",
          "footer_icon": "https://platform.slack-edge.com/img/default_application_icon.png",
          "ts": 123456789
      }
  ]
}

以下attachmentsに関してのドキュメント
Creating rich message layouts | Slack

実際に以下のJSONでSlackに投稿してみた様子

{
  "attachments": [
      {
          "color": "#2d2d2d",
          "author_name": "yuji",
          "author_icon": "icon url",
          "title": "勤務",
          "text": "Start",
          "footer": "OneTapLog app",
          "footer_icon": "icon url",
      }
  ]
}

上から順に
author_iconとauthor_nameで指定したnameやurlからImageを取得して表示しています。
次にtitle、textを表示、最後にfooter_iconで指定したurlからImageを取得し、footerで指定したアプリ名(ここではOneTapLog appとしています)を表示しています。
またattachmentsの色はcolorで指定したカラーコードの色が表示されます。
※実際に試してみる際はauthor_iconとfooter_iconには画像ファイルがあるURLを転記してください。

JSONからstructへ

JSONからSwiftのstructへ変換する際、以下のサイトを使用すると一瞬で変換してくれます!
(今回の記事で一番紹介したかった便利ポイントw)
もちろん自分で書いても問題ないです。

quicktype.io

変換されたコードはコチラ

import Foundation

// MARK: - Welcome
struct Welcome: Codable {
    var attachments: [Attachment]
}

// MARK: - Attachment
struct Attachment: Codable {
    var color, authorName, authorIcon, title: String
    var text, footer, footerIcon: String

    enum CodingKeys: String, CodingKey {
        case color
        case authorName
        case authorIcon
        case title, text, footer
        case footerIcon
    }
}

デフォルトではletで吐き出しますが

Use var instead of let for object properties

にチェックを入れておくとvarで吐き出してくれます。

またデフォルトではstructがWelcomeになっていたり、CodingKeyによってキャメルケースになっているので少し手直しします。

以下整理してみたコードです。

import Foundation

struct Payload: Codable {
    var attachments: [Attachment]
}

struct Attachment: Codable {
    var color: String
    var authorName: String
    var authorIcon: String
    var title: String
    var text: String
    var footer = "OneTapLog app"
    var footerIcon = "表示させたい画像のURL"
}

実装してみる

POSTリクエストするメソッド

func post() async throws {
    // Webhook URLで取得したURL
    let url = URL(string: "https://hooks.slack.com/services/XXXXX")!
    var request = URLRequest(url: url)
    // Postする際は必ずhttpMethodにて"POST"を定義する
    request.httpMethod = "POST"
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    // Slackに投稿する内容
    let payload = Payload(attachments: [Attachment(
        color: "#2d2d2d",
        authorName: "user name",
        authorIcon: "https://XXXXX",
        title: "勤務",
        text: "Start")])
    let jsonEncoder = JSONEncoder()
    // SnakeCaseへ変換
    jsonEncoder.keyEncodingStrategy = .convertToSnakeCase
    // JSONへ変換
    request.httpBody = try jsonEncoder.encode(payload)
    jsonEncoder.keyEncodingStrategy = .convertToSnakeCase
    guard let (data, response) = try? await URLSession.shared.data(for: request) else {
        throw APIError.networkError
    }
    guard (response as? HTTPURLResponse)?.statusCode == 200 else {
        throw APIError.unknown
    }
    print("success:\(data)")
}

以上です!

後は適当な画面を作ってpostメソッド叩けばWebhook URLのスレッドに投稿されます!

所感

今回はとりあえずアプリからOneTapでSlackに投稿する機能を作りたくて試してみました!
今後はWebhook URLやUserNameを登録する画面や、編集できる画面、ボタンをカスタマイズして色んな投稿をOneTapで投稿できるように作り込んでいきたいと思います!
またできたらどこかのタイミングで公開していきたいと思います!

参考サイト一覧

執筆者: 岡優志(oka yuji)
元高校教員→モバイルエンジニアで主にiOSを担当。
Twitter: oka yuji