プログラムを書こう!

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

SwiftのGoogleDrive APIでファイル一覧を取得する。

この記事は2018年07月25日に投稿しました。
この記事は2018年11月29日に更新しました。

f:id:paveway:20190914064630j:plain

目次

  1. はじめに
  2. 前提
  3. ファイル一覧取得処理
  4. おわりに

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

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

1. はじめに

こんにちは、iOSのエディタアプリPWEditorの開発者の二俣です。
今回はGoogleDrive APIでファイル一覧を取得してみます。

PWEditorでは、GoogleDrive APIのドキュメントSearch for Files and Team Drivesを参考に実装しました。

目次へ

2. 前提

以下の記事を参考にGoogleDrive APIを使用する準備を行ってください。

paveway.hatenablog.com

paveway.hatenablog.com

paveway.hatenablog.com

3. ファイル一覧取得処理

GoogleDrive APIでファイル一覧を取得するには、以下のような手順になります。

  1. ファイル一覧を取得するクエリオブジェクトを取得します。
  2. クエリオブジェクトに検索条件を設定します。
    2-1. 1回の検索で取得する件数を指定します。
    2-2. 検索で取得する項目を指定します。
    2-3. 検索するディレクトリのIDを指定します。
    ルートディレクトリの場合、"root"を指定してください。
    サブディレクトリの場合、ファイル一覧取得処理で取得したディレクトリのIDを指定してください。
    ディレクトリのIDは後述の"driveFile.identifier"で取得できます。
    2-4. 取得順を指定します。
    2-5. 次ページのトークンをセットします。
    2-6. クエリを実行した結果を処理するコールバックメソッドを登録します。
  3. クエリを実行します。
  4. クエリの実行結果はコールバックメソッドに返却されます。

ポイントが3つあります。

  1. 1回のクエリで取得できる件数が決まっています。
    最大件数を超える場合、nextPageTokenが設定されます。
    そのためnextPageTokenがある場合、再帰的にクエリを実行して続きのファイル情報を取得します。
  2. 取得できるファイルの項目を指定する必要があります。
    GoogleDrive APIでファイル情報を取得する場合、取得したいファイル情報の項目をクエリで指定する必要があります。
  3. 削除済みのディレクトリやファイルも取得されます。
    削除済みのディレクトリやファイルのファイル情報も取得されてしまいます。
    そのため取得するファイル項目に削除済みか否かを示すtrashedを加えておきます。
    ファイル情報を取得後にこのtrashedをチェックして、削除されていないディレクトリまたはファイルのみ取得対象にします。
import UIKit
import GoogleAPIClientForREST

class GoogleDriveFileListViewController: UIViewController {
    /// GooleDriveファイル情報リスト
    var fileInfoList = [GTLRDrive_File]()

    /// 次ページ取得用トークン
    var nextPageToken: String?

    /**
     画面が表示される前に呼び出されれます。

     - Parameter animated: アニメーション指定
     */
    override func viewWillAppear(_ animated: Bool) {
        // ファイル情報リストをクリアします。
        fileInfoList.removeAll(keepingCapacity: false)

        // ファイル情報リストを取得します。
        getFileInfoList()
    }

    /**
     GoogleDrive APIで、ファイル情報リストを取得します。
     */
    func getFileInfoList() {
        // 1. クエリオブジェクトを取得します。
        let query = GTLRDriveQuery_FilesList.query()

        // 2.クエリオブジェクトに検索条件を設定します。

        // 2-1. 1回の検索で取得する件数を指定します。
        //    ドキュメントには1000件まで指定できるとあります。
        //    しかし実際1000に指定して実行しても、1回で1000件は取得できませんでした。
        //    そのためデフォルトの100を指定して、何回かに分けて取得するようにしました。
        query.pageSize = 100
        
        // 2-2. 検索で取得する項目を指定します。
        query.fields = "nextPageToken, files(id, name, size, mimeType, fileExtension, createdTime, modifiedTime, starred, trashed, iconLink, parents, properties, permissions)"
        
        // 2-3. 検索するディレクトリのIDを指定します。
        // ルートディレクトリの場合は"root"を指定してください。
        // サブディレクトリの場合は、ファイル一覧取得処理で取得したディレクトリのIDを指定してください。
        // ディレクトリのIDは後述の"driveFile.identifier"で取得できます。 
        query.q = "'\(id)' in parents"
        
        // 2-4.取得順を指定します。
        query.orderBy = "folder,name"
        
        // 2-5. 次ページのトークンをセットします。
        //    nextPageTokenがnilならば、無視されます。
        query.pageToken = nextPageToken
        nextPageToken = nil

        // 2-6. クエリを実行した結果を処理するコールバックメソッドを登録します。
        let selector = #selector(displayResultWithTicket(_:finishedWithObject:error:))
        let appDelegate = EnvUtils.getAppDelegate()
        let serviceDrive = appDelegate.googleDriveServiceDrive
        
        // 3. クエリを実行します。
        serviceDrive.executeQuery(query, delegate: self, didFinish: selector)
    }

    /**
     4. GoogleDriveファイルの取得結果を表示します。

     - Parameter ticket: チケット
     - Parameter response: レスポンス
     - Parameter error: エラー情報
     */
    func displayResultWithTicket(_ ticket: GTLRServiceTicket, finishedWithObject response: GTLRDrive_FileList, error: Error?) {
        if let error = error {
            // エラーの場合、処理を終了します。
            // 必要に応じてエラー処理を行ってください。
            return
        }

        // GoogleDriveファイルリストを更新します。
        // 今回取得した分のファイルリストを取得します。
        var tempDriveFileList = [GTLRDrive_File]()
        if let driveFiles = response.files, !driveFiles.isEmpty {
            if let temp = driveFiles as? [GTLRDrive_File] {
                tempDriveFileList = temp
            }
        }

        // 取得済みのファイル情報を一時ファイルリストに追加します。
        for driveFile in fileInfoList {
            tempDriveFileList.append(driveFile)
        }

        // ファイル情報リストをクリアします。
        fileInfoList.removeAll(keepingCapacity: false)

        // 全ファイル情報分繰り返します。
        for driveFile in tempDriveFileList {
            // 名称を取得します。
            guard let name = driveFile.name else {
                // 名称が取得できない場合、次のファイルを処理します。
                continue
            }

            // IDを取得します。
            guard let id = driveFile.identifier else {
                // IDが取得できない場合、次のファイルを処理します。
                continue;
            }

            // 削除済みか判定します。
            let isTrashed = GoogleDriveUtils.isTrashed(driveFile)
            if isTrashed {
                // 削除済みの場合、次のファイルを処理します。
                continue
            }

            let dir = GoogleDriveUtils.isDir(driveFile)
            if dir {
                // ディレクトリの場合

            } else {
                // ファイルの場合
            }
        }

        // 次ページのトークンがある場合
        if let token = response.nextPageToken {
            // 次ページのファイル一覧を取得します。
            nextPageToken = token
            getFileInfoList()
        }
    }

    /**
     ディレクトリか判定します。

     - Parameter file: ファイルオブジェクト
     - Returns: true:ディレクトリ / false:ファイル
     */
    func isDir(_ file: GTLRDrive_File) -> Bool {
        var result = false
        if let mimeType = file.mimeType {
            let mimeTypes = mimeType.components(separatedBy: ".")
            let lastIndex = mimeTypes.count - 1
            let type = mimeTypes[lastIndex]
            if type == "folder" {
                result = true
            }
        }
        return result
    }

    /**
     削除済みか判定します。
 
     - Parameter file: ファイルオブジェクト
     - Returns: true:削除済み / false:削除されていない
     */
    func isTrashed(_ file: GTLRDrive_File) -> Bool {
        if let trashed = file.trashed, trashed == 1 {
            return true
        }
        return false
    }
}

目次へ

4. おわりに

GoogleDrive APIでファイル一覧を取得する処理ですが、なんとなくデータベースのSQLで検索する感じに似ている気がします。

TECH::EXPERT

本気ではじめるiPhoneアプリ作り Xcode 9.x+Swift 4.x対応 (「ヤフー黒帯」シリーズ)

本気ではじめるiPhoneアプリ作り Xcode 9.x+Swift 4.x対応 (「ヤフー黒帯」シリーズ)

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

目次へ


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

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

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

目次へ