iOS(Swift)から3ステップでMastodonに画像付き投稿を行う
まえがき
- 前回は、登録、ログイン、投稿の3ステップを記載
- 前回の延長線上で画像付きの投稿もやってみよと思い立つ
- 画像やmime/typeは固定で記述してるので適宜変更してください。
- 今回もmastdn.jpを使用しています。適宜変更してください。
- タイトルのことが出来る処理の流れを主軸に記述しているため、ForceUnwrap等よくない書き方は意図的にしています。(早めに直します・・・)
今回もQiitaに投稿済み (今後も技術記事は両方に投稿&Wメンテ予定。これに伴い、はてな記法からMarkdownに変更)
準備
extension Data { public mutating func append(_ string: String) { let data = Data(string.utf8) return self.append(data) } }
// 今回はPNG固定でファイル名とmime/typeを使用 let filename = "hoge.png" let mimetype = "image/png" // Create body for media func createBodyWith(parameters: [String: String]?, filePathKey: String?, imageData: Data, boundary: String) -> Data { var body = Data(); if let parameters = parameters { for (key, value) in parameters { body.append("--\(boundary)\r\n") body.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n") body.append("\(value)\r\n") } } body.append("--\(boundary)\r\n") body.append("Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n") body.append("Content-Type: \(mimetype)\r\n\r\n") body.append(imageData) body.append("\r\n") body.append("--\(boundary)--\r\n") return body } func generateBoundaryString() -> String { return "Boundary-\(NSUUID().uuidString)" }
Step.1 前回の内容を使ってログイン
上記の前記事を参考に、access_tokenを取得します。
Step.2 画像をアップロード
// 画像アップロード先URL let uploadUrl = URL(string: "https://mastdn.jp/api/v1/media")! // params生成 // access_token: Step.1で取得しているもの let params: [String: String] = ["access_token": responseJson["access_token"] as! String] // imageData生成 let imageData = UIImagePNGRepresentation(UIImage(named: filename)!)! // boudary生成 let boundary = generateBoundaryString() // request生成(前回作ったメソッドが使えないため、地道にValue追加) var request = URLRequest(url: urlString!) request.httpMethod = "POST" request.addValue("application/json", forHTTPHeaderField: "Content-Type") request.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type") request.httpBody = createBodyWith(parameters: params, filePathKey: "file", imageData: datas, boundary: boundary) // 画像アップロードPOST let task = session.dataTask(with: request, completionHandler: { data, response, error in do { self.responseJson = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! Dictionary<String, AnyObject> } catch { } }) task.resume()
// responseJsonの中身 { "id": 12356, "preview_url": "https://mastdn.jp/system/media_attachments/files/000/069/064/small/b804bb6a6c8db3d2.png?1492450358", "text_url": "https://mastdn.jp/media/hOgVBgaqylfQM-IolQw", "type": "image", "url": "https://mastdn.jp/system/media_attachments/files/000/069/064/original/b804bb6a6c8db3d2.png?1492450358" }
Step.3 画像ID付きでTootの投稿
// 前回のToot投稿に画像アップロード時のidを付加するだけ // TootURL let tootUrl = URL(string: "https://mastdn.jp/api/v1/statuses")! // access_token: Step.1で取得しているもの // status: Tootの内容 // media_ids: Step.2で取得したid(最大4つまで)。値は配列に格納。 // visibility: 公開範囲。(省略可能) let body: [String: String] = ["access_token": responseJson["access_token"] as! String, "status": "開発アプリからのテスト投稿", "visibility": "public", "media_ids": [responseJson["id"]] as AnyObject] // Toot POST do { try post(url: tootUrl, body: body) { data, response, error in // dataは返ってくるが、投稿できるまでの処理を書くだけなので省略 } } catch { }