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で投稿できるように作り込んでいきたいと思います!
    またできたらどこかのタイミングで公開していきたいと思います!

    参考サイト一覧

    執筆者岡優志

    iOSエンジニア
    iOSを専門とし、モバイルアプリの開発を行なっています。

    Twitter