iOS(Swift)から3ステップでMastodonに投稿を行う
流行りのMastodonのiOSアプリがAmaroqというアプリしかないため、
作ってみようかなと思い立った。
Qiitaにも投稿済み
その過程で必要なログインと投稿の処理を記載する。
正確には3ステップ必要。
全部POSTのみでいけるため、下記の処理を使用
今回はmastdn.jpを使用しています。適宜変更してください。
ForceUnwrap等セーフティな書き方をしていないのは行数を減らすため、意図的に書いています。
必要に応じてセーフティな書き方をしてください。
準備
// Mastodonのインスタンスから返ってくるjson格納用 var responseJson = Dictionary<String, AnyObject>() let session = URLSession.shared // POST METHOD func post(url: URL, body: Dictionary<String, String>, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) throws { var request: URLRequest = URLRequest(url: url) request.httpMethod = "POST" request.addValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = try JSONSerialization.data(withJSONObject: body, options: .prettyPrinted) session.dataTask(with: request, completionHandler: completionHandler).resume() }
Step.1 アプリの認証登録
// 登録URL let registUrl = URL(string: "https://mastdn.jp/api/v1/apps")! // client_name: アプリ名とかどこからの投稿かわかるための名前 // redirect_uris: redirectしないのでこういうものとしておまじない // scopes: 権限。今回に関してはwriteだけで足りるが、必要に応じてスペース区切りで追加 例→ "write read follow" // website: アプリのURLやWebsite。client_nameにこのリンクがつく(省略可能) let body: [String: String] = ["client_name": "TestApp", "redirect_uris": "urn:ietf:wg:oauth:2.0:oob", "scopes": "write"] // 登録POST do { try post(url: registUrl, body: body) { data, response, error in do { self.responseJson = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! Dictionary<String, AnyObject> } catch { } } } catch { }
// registのresponseJsonの中身 { "client_id": "abcdef123456789abcdef123456789abcdef123456789abcdef123456789abcd", "client_secret": "123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234", "id": 9999, "redirect_uri": "urn:ietf:wg:oauth:2.0:oob" }
Step.2 ログイン
// ログインURL let loginUrl = URL(string: "https://mastdn.jp/oauth/token")! // scopes: 権限。Step.1で取得しているものだけしか使用できないはず // client_id: Step.1のresponseで取得したもの // client_secret: Step.1のresponseで取得したもの // grant_type: ログインする方式(で合っているのかな?) // username: 登録したメールアドレス (アカウント名ではない) // password: 登録したパスワード let body: [String: String] = ["scope": "write", "client_id": responseJson["client_id"] as! String, "client_secret": responseJson["client_secret"] as! String, "grant_type": "password", "username": "hogefuga@gmail.com", "password": "hogefuga"] // ログインPOST do { try post(url: loginUrl, body: body) { data, response, error in do { self.responseJson = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! Dictionary<String, AnyObject> } catch { } } } catch { }
// ログインのresponseJsonの中身 { "access_token": "abcdef123456789abcdef123456789abcdef123456789abcdef123456789abcd", "created_at": 1234567890, "scope": "write", "token_type": "bearer" }
Step.3 Tootの投稿
// TootURL let tootUrl = URL(string: "https://mastdn.jp/api/v1/statuses")! // access_token: Step.2で取得しているもの // status: Tootの内容 // visibility: 公開範囲。public, unlisted, private, directとあるが違いは試していないので不明(省略可能) let body: [String: String] = ["access_token": responseJson["access_token"] as! String, "status": "開発アプリからのテスト投稿", "visibility": "public"] // Toot POST do { try post(url: tootUrl, body: body) { data, response, error in // dataは返ってくるが、投稿できるまでの処理を書くだけなので省略 } } catch { }