iPhoneからDropboxにファイルをアップロードしようとしてDropbox API を調べながらやってみた。
準備
ユーザ登録とかアプリの登録とかアクセストークンの発行とかあるけど、まあDropox APIのページに書いてあるとおりやればいい。見たら、すでにアプリの登録までやってあった。昔にラズパイからアップロードしようとした形跡(そういうアプリ名になっている)がある(^^;)。全然覚えてないし、、。
#SwiftyDropboxで試す
swift用にSwiftyDropboxというSDK(?)があるけど、Tutorial通りやっても動かないので1時間くらいで諦める。
直接URLを叩く
URLを叩くだけなので、公式のページ(upload だと[この辺] (https://www.dropbox.com/developers/documentation/http/documentation#files-upload))に結構親切に書いてある通りにやる。
##curlでやってみる
とりあえず curl の例が出ているのでそのままコピペすると動く。
curl -X POST https://content.dropboxapi.com/2/files/upload \
--header "Authorization: Bearer <get access token>" \
--header "Dropbox-API-Arg: {\"path\": \"/Homework/math/Matrices.txt\",\"mode\": \"add\",\"autorename\": true,\"mute\": false,\"strict_conflict\": false}" \
--header "Content-Type: application/octet-stream" \
--data-binary @local_file.txt
get access token のところは、本物はクリックするとアクセストークンが入ってくれる。
##swiftで試しにやってみる
// header
request.addValue("Bearer <ここはアクセストークンが入る>", forHTTPHeaderField: "Authorization")
request.addValue("{\"path\": \"/Homework/math/Matrices.txt\",\"mode\": \"add\",\"autorename\": true,\"mute\": false,\"strict_conflict\": false}",forHTTPHeaderField: "Dropbox-API-Arg")
request.addValue("application/octet-stream",forHTTPHeaderField: "Content-Type")
// POSTするデータをBodyとして設定
request.httpBody = "This is a pen.\n".data(using: .utf8)
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if error == nil, let data = data, let response = response as? HTTPURLResponse {
// HTTPヘッダの取得
print("Content-Type: \(response.allHeaderFields["Content-Type"] ?? "")")
// HTTPステータスコード
print("statusCode: \(response.statusCode)")
print(String(data: data, encoding: .utf8) ?? "")
}
}.resume()
(どこかのサイトからコピペしましたが、今探しても見つかりませんでした。すみません。)
これでOK。
ちゃんとやってみる。
で、パス名とかをちゃんと治してみたら、パス名が英語だとうまくいくけど、日本語だとNG。(400で返ってくる。)
「そうか、encodeしないといけないのね。」と思って、URLエンコードしてみるけどうまく行かない。
「日本語」を「%E6%97%A5%E6%9C%AC%E8%AA%9E」とか書くと、そのままのファイルが出来てしまう。
(Macの)curlで試すと、日本語をUTF8(のファイル)で書いてもそのまま動く。
「encode しなくていいのか?」
だんだん分からなくなる。curlがどんなデータを渡しているのかわからないので、仕方ないので WireShark でパケットを見たら、UTF8 が直接流れている。
じゃあ、ということで swift のプログラムのパケットを見てみたら、日本語のパス名のところで切れている。どうも UTF8 のデータをうまく扱えていないみたいだ。で色々試してみたら、「日本語」を「\u65E5\u672C\u8A9E」って書いてあげると動くのが分かった。なので、
// パス名に日本語が入っていると400で失敗する
var encodedfname: String = ""
for c in fname.utf16 {
encodedfname = encodedfname + String(format: "\\u%04X",c)
}
みたいに変換してあげると動いた。
もっと上手に encode してあげると良いのかもしれないけれど、とりあえず動いたのでOKとする。
なお、ヘッダではなくてURLの引数にパス名を入れる方法があるとは書いてあるけど、シンタックスが見つからなかったので試してません。それならURLエンコードでうまくいくような気がする。