I want to create an application in which some type of data would be sync to google drive in app specific folder and further it can be accessible to retrieve the data and populate to the app. If somehow users mobile is lost and user use another mobile and when user logged in same google account then that data should be fetch.
My problem is I am not aware the steps to follow to do this, I am able to create the app folder over google drive and this is showing to end user over drive
Now when I am trying to insert the data in it got scope error. My used code is:
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)
}
}
}
And for login and used below class is used
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 {}
Whenever I have try to upload any file the error coming:
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.}
You need to setup scope for google drive configuration,
GIDSignIn.sharedInstance().scopes = [kGTLRAuthScopeDriveAppData]
Reference Drive scope