プログラムを書こう!

実務や自作アプリ開発で習得した役に立つソフトウェア技術情報を発信するブログ

SwiftのOneDrive APIでファイルをコピーする。

この記事は2018年07月04日に投稿しました。
この記事は2018年07月21日に更新しました。

f:id:paveway:20190914064630j:plain

目次

  1. はじめに
  2. ファイルコピー処理
  3. おわりに

現場のためのSwift4 Swift4.1+Xcode9.3対応

現場のためのSwift4 Swift4.1+Xcode9.3対応

1. はじめに

こんにちは、iOSのエディタアプリPWEditorの開発者の二俣です。

今回はOneDrive APIでファイルコピーをしてみます。

PWEditorでは、ドキュメント"Items in the OneDrive SDK for iOS"の"Copy an Item"を参考に実装しました。

ただしコピー用のAPIが用意されているので簡単と思いきや、罠がありました。

目次へ

2. ファイルコピー処理

OneDrive APIでコピー行うには、copyメソッドを使用します。
このメソッドで、ディレクトリもファイルもコピーできます。
ディレクトリをコピーする場合、配下のディレクトリやファイルもコピーされます。
コピー先に同名のディレクトリやファイルが存在する場合、エラーになります。

ただし、copyメソッドはコピー先がサブディレクトリの場合のみ使用できるようです。
実装した時は、コピー先がrootディレクトリの場合、うまく動作しませんでした(今はどうかわかりませんが)
そのためPWEditorではコピー先がrootディレクトリの場合、REST APIを使って別メソッドで実装してあります。

サブディレクトリへのコピーはこちらのメソッドを使用します。

import OneDriveSDK

/**
 サブディレクトリにコピーします。
 このメソッドでは、"root"ディレクトリへのコピーはできません。

 - Parameter parentId: コピー先のディレクトリのID
 - Parameter fileId: コピー元のディレクトリまたはファイルのID
 - Parameter fileName: コピー元のディレクトリまたはファイルの名前
 */
func copyFile(_ parentId: String, fileId: String, fileName: String) {
    // 認証済みクライアントオブジェクトを取得します。
    guard let client = ODClient.loadCurrent() else {
        // 認証済みクライアントオブジェクトが取得できない場合、処理を終了します。
        // 念のためのチェックです。
        // 必要に応じてエラー処理を行ってください。
        return
    }

    // アイテムオブジェクトを取得します。
    guard let drive = client.drive(), let items = drive.items(fileId) else {
        // アイテムオブジェクトが取得できない場合、処理を終了します。
        // 必要に応じてエラー処理を行ってください。
        return
    }

   // ODDItemReferenceオブジェクトにコピー先のディレクトリのIDを設定します。
    let parent = ODItemReference()
    parent.id = parentId
    
    // リクエストオブジェクトを取得します。
    let request = items.copy(withName: fileName, parentReference: parent).request()
    
    // コピーを実行します。
    let _ = request?.execute { (item: ODItem?, status: ODAsyncOperationStatus?, error: Error?) -> Void in
        if let error = error {
            // エラーの場合、処理を終了します。
            // 必要に応じてエラー処理を行ってください。
            return
        }
        
        // 正常終了の場合の処理を記述してください。
    }
}

"root"ディレクトリへのコピーはこちらのメソッドを使用します。

import OneDriveSDK

/**
 rootディレクトリにコピーします。
 
 - Parameter fileId: コピー元のディレクトリまたはファイルのID
 */
func copyFileToRoot(_ fileId: String) {
    guard let client = ODClient.loadCurrent() else {
        // 認証済みクライアントオブジェクトが取得できない場合、処理を終了します。
        // 念のためのチェックです。
        // 必要に応じてエラー処理を行ってください。
        return
    }

    // ベースURLを取得します。
    guard let baseURL = client.baseURL else {
        // ベースURLが取得できない場合、処理を終了します。
        // 必要に応じてエラー処理を行ってください。
        return
    }

    // アカウントセッションを取得します。
    guard let accountSession = client.authProvider.accountSession?() else {
        // アカウントセッションが取得できない場合、処理を終了します。
        // 必要に応じてエラー処理を行ってください。
        return
    }
    
    // アクセストークンを取得します。
    guard let accessToken = accountSession.accessToken else {
        // アクセストークンが取得できない場合、処理を終了します。
        // 必要に応じてエラー処理を行ってください。
        return
    }

    // URL文字列を生成します。
    let urlString = "\(baseURL)/drive/items/\(fileId)/action.copy"
    // URLを生成します。
    guard let url = URL(string: urlString) else {
        // URLが生成できない場合、処理を終了します。
        // 必要に応じてエラー処理を行ってください。
        return
    }

    // HTTPリクエストを生成します。
    let request = NSMutableURLRequest(url: url)

    // キャッシュをオフにします。
    request.cachePolicy = .reloadIgnoringLocalCacheData

    // HTTPメソッドを設定します。
    // 今回は"POST"を使用します。
    request.httpMethod = ”POST"

    // Content-Typeを設定します。
    // HTTPパラメータを設定するため、"Content-Type"に"application/json"を設定します。
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")

    // Authorizationを設定します。
    // ここでアクセストークンを設定します。
    let bearer = String(format: "Bearer %@", accessToken)
    request.setValue(bearer, forHTTPHeaderField: "Authorization")

    // Preferを設定します。
    request.setValue("respond-async", forHTTPHeaderField: "Prefer")

    // HTTPパラメータを生成し、設定します。
    let params = ["path": "/drive/root"]
    let parentReference = ["parentReference": params]
    do {
        request.httpBody = try JSONSerialization.data(withJSONObject: parentReference, options: JSONSerialization.WritingOptions())
    } catch {
        // HTTPパラメータの設定でエラーの場合、処理を終了します。
        // 必要に応じてエラー処理を行ってください。
        return
    }

    // HTTP通信タスクを生成します。
    let task = URLSession.shared.dataTask(with: request as URLRequest, completionHandler: { (data: Data?, response: URLResponse?, error: Error?) -> Void in
        if let error = error {
            // エラーの場合、処理を終了します。
            // 必要に応じてエラー処理を行ってください。
            return
        }

        // HTTPステータスコードを取得します。
        guard let httpURLResponse = response as? HTTPURLResponse else {
            // HTTPステータスコードが取得できない場合、処理を終了します。
            // 必要に応じてエラー処理を行ってください。
            return
        }
        let statusCode = httpURLResponse.statusCode
        // HTTPステータスコード別に処理を振り分けます。
        switch statusCode {
        case 202:
            // 正常終了の場合、正常時に行う処理を記述してください。
            break

        default:
            // 上記以外のHTTPステータスコードはエラーとして、処理を終了します。
            // 必要に応じてエラー処理を行ってください。
            break
        }
    })
    // HTTP通信タスクを実行します。
    task.resume()
}

目次へ

3. おわりに

copyメソッドも用意されているし、このメソッドでディレクトリもファイルもコピーできるので、簡単に実装できると思っていましたが、はまりました。 実装した後テストしてみると、"root"ディレクトリへのコピーがどうしてもうまく動作しませんでした。
copyメソッドでいろいろ試しましたがどうしても解決しないため、またもやREST APIを使って自分で実装するはめになりました。

OneDrive APIは用意されているAPIは割と使いやすいようになっていますが、全機能がそろっていないのが玉に傷です。

とりあえず稼ぎたいなら、ITエンジニア【IT派遣テクノウェイブ】

[改訂新版]Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語 (WEB+DB PRESS plus)

[改訂新版]Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語 (WEB+DB PRESS plus)

紹介している一部の記事のコードはGitlabで公開しています。
興味のある方は覗いてみてください。

目次へ


私が勤務しているニューラルでは、主に組み込み系ソフトの開発を行っております。
弊社製品のハイブリッドOS Bi-OSは高い技術力を評価されており、特に制御系や通信系を得意としています。
私自身はiOSモバイルアプリウィンドウズアプリを得意としております。
ソフトウェア開発に関して相談などございましたら、お気軽にご連絡ください。

また一緒に働きたい技術者の方も随時募集中です。
興味がありましたらご連絡ください。

EMAIL : info-nr@newral.co.jp / m-futamata@newral.co.jp
TEL : 042-523-3663
FAX : 042-540-1688

目次へ