作成したiOSアプリ「Repete」(語学学習支援プレイヤー)には、Dropbox上のオーディオファイルを取り入れる機能があります。
Dropboxへのアクセスには、Dropboxが提供するAPIを使用しています。
API v1 is now deprecated | Dropbox Developer Blog
Dropbox API v1が廃止され、新たなアプリおよび既存のアプリはAPI v2を使ってDropboxと接続する必要があるとのことで、今回、移行処理を行いました。
File Type Permissionが廃止された
API v1には、File type Permissionという分類がありました。特定の種類のファイルのみアクセスできるというものです。
API v1 → API v2 migration guide – Developers – Dropbox
API v2では、File Types Permissionがなくなりました。移行にあたっては新たにアプリを登録して、ユーザーにもう一度認証してもらうことになります。
Tip: When messaging to your users the need to re-link their Dropbox account, we suggest the following language: “The Dropbox integration has changed. Please re-link your account to continue [syncing/backing up data/accessing files/etc].”
再リンクの必要を伝えるメッセージの例。
Fie Types Permissionのように特定の種類のファイルのみを取得するには、ファイル拡張子を用いて判別します。
Developer guide – Dropbox
こちらに、API v1でFile type判別に用いていた拡張子の一覧があります。
インストール
Swift製のライブラリをインストール。
Dropbox for Swift Developers | Install
こちらのページにそって、インストール。
AlamofireとSwiftyDropboxがインストールされます。
今回インストールしたバージョンは、
Alamofire: 3.3.1
SwiftyDropbox: 3.2.0
チュートリアル
Dropbox for Swift Developers | Tutorial
チュートリアルでは、アプリを登録して簡単なプロジェクトを作成しました。
チュートリアルプロジェクトでできること。
* Dropboxとの連携許可
* ユーザーのアカウント名を表示
* 指定したフォルダ直下の内容を表示
* ファイルのアップロード
* ファイルのdiskへのダウンロード
* ファイルのメモリへのダウンロード
おおよそやりたいことはできるのだけれど、そのほかに知りたい点がいくつか。
Tutorialを改造しながら、さぐりさぐりで調べていきました。
そのほか調べた事柄
ファイルの情報を知る
getMetadataを用いる。
if let client = Dropbox.authorizedClient { // ファイルのpathを指定して情報を取得 // ("hello.txt"がルートフォルダにあるとします) client.files.getMetadata(path: "/hello.txt").response { response, error in print("*** get Metadata ***") if let metadata = response { print("result:\(metadata.name)") print("") } } }
フォルダかファイルか?
取得したmetadataがフォルダなのかファイルなのか知りたい。
Files.FolderMetadata、Files.FileMetadataを用いる。
if let client = Dropbox.authorizedClient { // ルートフォルダ直下の内容を取得して、名前を表示。ファイルの場合はサイズも表示 client.files.listFolder(path: "") .response { response, error in print() print("*** List folder ***") if let result = response { for entry in result.entries { if entry is Files.FileMetadata { let file = entry as! Files.FileMetadata print("\(file.name) \(file.size)") } else { print("\(entry.name)") } } } else { print(error!) } } }
ファイルの種類を限定
Dropbox for Swift Developers | Overview
こちらのページで紹介されているSample Appの”PhotoWatch”では、
// Check that file is a photo (by file extension) if entry.name.hasSuffix(".jpg") || entry.name.hasSuffix(".png") { // Add photo! self.filenames?.append(entry.name) }
という書き方をしています。
拡張子をチェックして判別しています。
参考:Developer guide – Dropbox
Dropbox API v1でFile type判別に用いていた拡張子の一覧あり。
フォルダ下のすべてのフォルダ・ファイルを取得する
client.files.listFolder(path: "", recursive: true, includeMediaInfo: false, includeDeleted: false, includeHasExplicitSharedMembers: false)
listFolderのさいに、recursiveをtrueにすることで再帰的に調べてフォルダ下のすべてのフォルダ・ファイルが取得できます。
進行状況
進行状況を知るには?
if let client = Dropbox.authorizedClient { let destination : (NSURL, NSHTTPURLResponse) -> NSURL = { temporaryURL, response in let fileManager = NSFileManager.defaultManager() let directoryURL = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] // generate a unique name for this file in case we've seen it before let UUID = NSUUID().UUIDString let pathComponent = "\(UUID)-\(response.suggestedFilename!)" return directoryURL.URLByAppendingPathComponent(pathComponent) } // ルートフォルダにある"audio.mp3"ファイルをダウンロードする client.files.download(path: "/audio.mp3", destination: destination) .progress{ bytesRead, totalBytesRead, totalBytesExpectedToRead in print("bytesRead:\(bytesRead) totalBytesRead:\(totalBytesRead) totalBytesExpectedToRead:\(totalBytesExpectedToRead)") } .response { response, error in if let (metadata, url) = response { print() print("*** Downloaded file to disk ***") print("Downloaded file name: \(metadata.name)") print("Downloaded file url: \(url)") } else { print(error!) } } }
参考:swift – SwiftyDropbox download progress – Stack Overflow
リクエストをキャンセルする
ダウンロードのリクエストをキャンセルするには?
swifty dropbox download cancel – Dropbox Community
こちらのページを読むと、初期はダウンロードキャンセル機能はなかったようです。
最新版ではあるとのこと。
SwiftyDropbox 3.2.0ではありました。
import UIKit import SwiftyDropbox class ViewController: UIViewController { var dlRequest: DownloadRequestFile<Files.FileMetadataSerializer, Files.DownloadErrorSerializer>? override func viewDidLoad() { super.viewDidLoad() // Verify user is logged into Dropbox if let client = Dropbox.authorizedClient { // Download a file to disk // ルートフォルダにある"audio.mp3"ファイルをダウンロードする。 let destination : (NSURL, NSHTTPURLResponse) -> NSURL = { temporaryURL, response in let fileManager = NSFileManager.defaultManager() let directoryURL = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] // generate a unique name for this file in case we've seen it before let UUID = NSUUID().UUIDString let pathComponent = "\(UUID)-\(response.suggestedFilename!)" return directoryURL.URLByAppendingPathComponent(pathComponent) } print("Downloading") dlRequest = client.files.download(path: "/audio.mp3", destination: destination).progress{ bytesRead, totalBytesRead, totalBytesExpectedToRead in print("bytesRead:\(bytesRead) totalBytesRead:\(totalBytesRead) totalBytesExpectedToRead:\(totalBytesExpectedToRead)") }.response { response, error in if let (metadata, url) = response { print() print("*** Downloaded file to disk ***") print("Downloaded file name: \(metadata.name)") print("Downloaded file url: \(url)") } else { print(error!) } } } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } @IBAction func linkButtonPressed(sender: AnyObject) { if Dropbox.authorizedClient == nil { Dropbox.authorizeFromController(self) } } // (storyboard上にキャンセル用ボタンを配置し、actionでつないだ) @IBAction func cancelButtonPressed(sender: AnyObject) { if let request = dlRequest { request.cancel() dlRequest = nil } } }
こんな感じでしょうか。
Storyboard側にキャンセル用ボタンを配置してViewController.swiftのcancelButtonPressedとactionでつないであるものとします。
Dropboxにリンクしている状態で、viewDidLoadが呼ばれると、ルートフォルダの”audio.mp3″のダウンロードが開始されます。
キャンセルボタンを押すと、ダウンロードがキャンセルされます。
以上、SwiftyDropboxの使い方について、いくつか知った事柄について記しました。