6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

iOS(Swift)から3ステップでMastodonに画像付き投稿を行う

Last updated at Posted at 2017-04-18

まえがき

・前回は、登録、ログイン、投稿の3ステップを記載
・前回の延長線上で画像付きの投稿もやってみよと思い立つ
・画像やmime/typeは固定で記述してるので適宜変更してください。
・今回もmastdn.jpを使用しています。適宜変更してください。
・タイトルのことが出来る処理の流れを主軸に記述しているため、ForceUnwrap等よくない書き方は意図的にしています。(早めに直します・・・)

準備

Data型の拡張
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 前回の内容を使ってログイン

iOSから3ステップでMastodonに投稿する

上記の前記事を参考に、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 {
}

参考にしたURL

  1. Tootsuite documentation
  2. Image upload example with Swift and PHP
6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?