Dropbox API v1からv2への移行

作成した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の使い方について、いくつか知った事柄について記しました。

コメントする

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください