swift - 如何访问特定于应用程序的文件夹并将其用于备份或某些特定于应用程序的数据?在 swift

标签 swift google-drive-api backup

我想创建一个应用程序,其中某些类型的数据将同步到应用程序特定文件夹中的谷歌驱动器,并且可以访问它来检索数据并填充到应用程序。如果用户手机以某种方式丢失并且用户使用另一部手机并且当用户登录同一个谷歌帐户时则应该获取该数据。

我的问题是我不知道执行此操作的步骤,我能够通过谷歌驱动器创建应用程序文件夹,这通过驱动器向最终用户显示 enter image description here

现在,当我尝试向其中插入数据时出现范围错误。 我使用的代码是:

import Foundation
import GoogleAPIClientForREST

enum GDriveError: Error {
    case NoDataAtPath
 }

class ATGoogleDrive {

private let service: GTLRDriveService

init(_ service: GTLRDriveService) {
    self.service = service
}

public func listFilesInFolder(_ folder: String, onCompleted: @escaping (GTLRDrive_FileList?, Error?) -> ()) {
    search(folder) { (folderID, error) in
        guard let ID = folderID else {
            onCompleted(nil, error)
            return
        }
        self.listFiles(ID, onCompleted: onCompleted)
    }
}

private func listFiles(_ folderID: String, onCompleted: @escaping (GTLRDrive_FileList?, Error?) -> ()) {
    let query = GTLRDriveQuery_FilesList.query()
    query.pageSize = 100
    query.q = "'\(folderID)' in parents"

    service.executeQuery(query) { (ticket, result, error) in
        onCompleted(result as? GTLRDrive_FileList, error)
    }
}

public func uploadFile(_ folderName: String, data: Data, MIMEType: String, onCompleted: ((String?, Error?) -> ())?) {

    search("config.json") { (folderID, error) in

        if let ID = folderID {
            self.upload(ID, data: data, MIMEType: MIMEType, onCompleted: onCompleted)
        } else {
            self.createFolder(folderName, onCompleted: { (folderID, error) in
                self.upload("", data: data, MIMEType: MIMEType, onCompleted: onCompleted)
            })
        }
    }
}

private func upload(_ parentID: String, data: Data, MIMEType: String, onCompleted: ((String?, Error?) -> ())?) {

    let metadata: GTLRDrive_File = GTLRDrive_File()
    metadata.name = "config.json"
    metadata.parents = ["appDataFolder"]

    let uploadParameters: GTLRUploadParameters = GTLRUploadParameters(data: data, mimeType: "application/json") 
    uploadParameters.shouldUploadWithSingleRequest = true;
    let query: GTLRDriveQuery_FilesCreate = GTLRDriveQuery_FilesCreate.query(withObject: metadata, uploadParameters: uploadParameters)//[GTLRDriveQuery_FilesCreate queryWithObject:metadata
     query.fields = "id"
     self.service.executeQuery(query) { (ticket, fileN, error) in
        print(ticket)
        print(fileN)
        print(error)
        if let f = fileN as? GTLRDrive_File {
            if (error == nil) {
                print("File ID %@", f.identifier);
            } else {
                print("An error occurred: %@", error);
            }
        } 
      }
    }

public func listFromAppFolder(_ parentID: String, data: Data, MIMEType: String, onCompleted: ((String?, Error?) -> ())?) {
    let file = GTLRDrive_File()
    file.name = "\(Date().timeIntervalSince1970)"
    file.parents = ["appfolder"]

    let uploadParams = GTLRUploadParameters.init(data: data, mimeType: MIMEType)
    uploadParams.shouldUploadWithSingleRequest = true

    let query = GTLRDriveQuery_FilesCreate.query(withObject: file, uploadParameters: uploadParams)
    query.fields = "id"

    self.service.executeQuery(query, completionHandler: { (ticket, file, error) in
        print(ticket)
        print(file)
        print(error)
        onCompleted?((file as? GTLRDrive_File)?.identifier, error)
    })
}

public func download(_ fileID: String, onCompleted: @escaping (Data?, Error?) -> ()) {
    let query = GTLRDriveQuery_FilesGet.queryForMedia(withFileId: fileID)
    service.executeQuery(query) { (ticket, file, error) in
        onCompleted((file as? GTLRDataObject)?.data, error)
    }
}

public func search(_ fileName: String, onCompleted: @escaping (String?, Error?) -> ()) {
    let query = GTLRDriveQuery_FilesList.query()
    query.pageSize = 1
    query.q = "name contains '\(fileName)'"

    service.executeQuery(query) { (ticket, results, error) in
        onCompleted((results as? GTLRDrive_FileList)?.files?.first?.identifier, error)
    }
}

public func createFolder(_ name: String, onCompleted: @escaping (String?, Error?) -> ()) {
    let file: GTLRDrive_File = GTLRDrive_File()
    file.name = "config.json"
    file.parents = ["appfolder"]
    let query = GTLRDriveQuery_FilesCreate.query(withObject: file, uploadParameters: nil)
    query.fields = "id"

    service.executeQuery(query) { (ticket, folder, error) in
        onCompleted((folder as? GTLRDrive_File)?.identifier, error)
    }
}

public func delete(_ fileID: String, onCompleted: ((Error?) -> ())?) {
    let query = GTLRDriveQuery_FilesDelete.query(withFileId: fileID)
    service.executeQuery(query) { (ticket, nilFile, error) in
        onCompleted?(error)
    }
  }
 }

并且用于登录和使用下面的类

import UIKit
import GoogleSignIn
import GoogleAPIClientForREST

class ViewController: UIViewController {

@IBOutlet weak var resultsLabel: UILabel!

fileprivate let service = GTLRDriveService()
private var drive: ATGoogleDrive?

override func viewDidLoad() {
    super.viewDidLoad()

    setupGoogleSignIn()

    drive = ATGoogleDrive(service)

    view.addSubview(GIDSignInButton())
}

private func setupGoogleSignIn() {
    GIDSignIn.sharedInstance().delegate = self
    GIDSignIn.sharedInstance().uiDelegate = self
    GIDSignIn.sharedInstance().scopes = [kGTLRAuthScopeDriveFile]
    GIDSignIn.sharedInstance().signInSilently()
}


@IBAction func uploadAction(_ sender: Any) {
    if let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last {
        let dataImg: Data = UIImageJPEGRepresentation(UIImage(named: "logo.png")!, 1.0)!
        drive?.uploadFile("config.json", data: dataImg, MIMEType: "image/png") { (fileID, error) in
            print("Upload file ID: \(fileID); Error: \(error?.localizedDescription)")
        }
       }
     }

    @IBAction func listAction(_ sender: Any) {
    drive?.listFilesInFolder("config.json") { (files, error) in
        guard let fileList = files else {
            print("Error listing files: \(error?.localizedDescription)")
            return
        }

        self.resultsLabel.text = fileList.files?.description
        print(fileList)
        for nFile in fileList.files! {
            if nFile.mimeType == "image/jpeg" {
                self.drive?.download(nFile.identifier!, onCompleted: { (data, error) in
                    print(data)
                    print(error)
                })
              }
            }
          }
        }
      }

     // MARK: - GIDSignInDelegate
     extension ViewController: GIDSignInDelegate {
     func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
    if let _ = error {
        service.authorizer = nil
    } else {
        service.authorizer = user.authentication.fetcherAuthorizer()
        service.shouldFetchNextPages = true
    }
  } 
 }

    // MARK: - GIDSignInUIDelegate
    extension ViewController: GIDSignInUIDelegate {}

每当我尝试上传任何文件时都会出现错误:

Error Domain=com.google.GTLRErrorObjectDomain Code=403 "The granted scopes do not allow use of the Application Data folder." UserInfo={GTLRStructuredError=GTLRErrorObject 0x281515d10: {message:"The granted scopes do not allow use of the Application Data folder." errors:[1] code:403}, NSLocalizedDescription=The granted scopes do not allow use of the Application Data folder.}

最佳答案

您需要为 google drive 配置设置范围,

GIDSignIn.sharedInstance().scopes = [kGTLRAuthScopeDriveAppData]

引用 Drive scope

关于swift - 如何访问特定于应用程序的文件夹并将其用于备份或某些特定于应用程序的数据?在 swift ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56867026/

相关文章:

swift - CABasicAnimation 看似执行两个动画

google-api - 如何获取完整文件获得Google Drive V3的响应

c# - 如何在 google drive api 中进行一次身份验证

solr - 如何通过 SolrJ 客户端执行远程 Solr 核心备份?

linux - 在一定大小的预文件夹中备份文件

swift - 符合协议(protocol)时类型别名声明的冗余重复(第 2 部分)

swift - 如何固定 certificate.pem 和 private_key.pem 文件以在 Swift 中签署 http 请求

ios - UIScrollViewDelegate 中的委托(delegate)方法不响应 TableView 滚动事件

python - 如何加快 Google Drive API 搜索速度

python - 带有转储数据和迁移的 Django 备份策略