Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Spreadsheets APIS, confused

I had this working before but now it seems to have stopped. I am trying to run various googlesheets APIS such as read/write/create. I have installed the appropriate cocoa pods:

platform :ios, '10.0'

target 'Safety_App-Prototype' do
  
  use_frameworks!

    pod 'GoogleAnalytics'
    pod 'GoogleAPIClientForREST/Sheets'
    pod 'GoogleAPIClientForREST/Drive'
    pod 'GoogleSignIn'
    pod 'SVProgressHUD'
    pod 'Firebase/Core'
    pod 'Firebase/Analytics'
    pod 'Firebase/Auth'
    pod 'Firebase/Firestore'
end

I have created a google developer console project and included all relevant information into my app. (this includes the URL type under projects -> info tab as well as in my app delegate shown below:

//
//  AppDelegate.swift
//  Created by Michael Szabo on 2021-01-28.
//

import UIKit
import GoogleSignIn

@main
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {



    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        GIDSignIn.sharedInstance().clientID = "FORMYEYESONLY.apps.googleusercontent.com"
        GIDSignIn.sharedInstance().delegate = self
        return true
    }
    
    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
   
        
        return GIDSignIn.sharedInstance().handle(url as URL?,
                                                 sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
                                                 annotation: options[UIApplication.OpenURLOptionsKey.annotation])

    
    }

    func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
        if let error = error {
          if (error as NSError).code == GIDSignInErrorCode.hasNoAuthInKeychain.rawValue {
            print("The user has not signed in before or they have since signed out.")
          } else {
            print("\(error.localizedDescription)")
          }
          return
        }
        // Perform any operations on signed in user here.
        let userId = user.userID                  // For client-side use only!
        let idToken = user.authentication.idToken // Safe to send to the server
        let fullName = user.profile.name
        let givenName = user.profile.givenName
        let familyName = user.profile.familyName
        let email = user.profile.email
        // ...
        print(fullName)
    }
    
    func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
       // Perform any operations when the user disconnects from app here.
        print("User has disconnected")
    }
    
    // MARK: UISceneSession Lifecycle

    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // Called when the user discards a scene session.
        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    }


}

I have added a google signing button which allows me to sign in and asks for permission to read/write to sheets and added functions in my script to create/read/write to sheets as seen below:


//  Created by Michael Szabo on 2021-02-21.
//


import GoogleAPIClientForREST
import GoogleSignIn
import UIKit

class JHA_pg1: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UITextFieldDelegate, GIDSignInUIDelegate, GIDSignInDelegate {
    

    var rowstart:NSNumber = 0
    var rowend:NSNumber = 0
    var columnstart:NSNumber = 0
    var columnend:NSNumber = 0
    var red:NSNumber = 1
    var blue:NSNumber = 1
    var green:NSNumber = 1

    var range1 = ""
    var text1 = ""
    var text2 = ""
    var text3 = ""
    var bordertype = "SOLID"
    var borderthick:NSNumber = 3
    var inbortype = "NONE"
    var inborthick:NSNumber = 0
        
    var spreadsheetId = ""
    
   
    @IBOutlet weak var BeginAssessment: UIButton! //SubmitButton
 
    let today = Date()
    let formatter1 = DateFormatter()
    let formatter = DateFormatter()
    var date = String()
    var buttontitle = String()
        
    let defaults = UserDefaults.standard
        
        
    private let scopes = [kGTLRAuthScopeSheetsSpreadsheets]
    private let service = GTLRSheetsService()
   

    
//=========================================================================================================
//=========================================================================================================

    
    
    override func viewDidLoad() {
        super.viewDidLoad()

        
        
//=========================================================================================================
// Configure Google Sign-in.

        GIDSignIn.sharedInstance().delegate = self
        GIDSignIn.sharedInstance().uiDelegate = self
        GIDSignIn.sharedInstance().scopes = scopes
        GIDSignIn.sharedInstance().signInSilently()

        
    }
    
    
//=========================================================================================================
//=========================================================================================================
    //Submit Function

    @IBAction func BeginAssessment(_ sender: Any) {
   
        
        if(GIDSignIn.sharedInstance()?.currentUser != nil)
        {
        print("loggedIn")
        }
        else
        {
        print("not loggedIn")
        }
        

        
        spreadsheetId = "SOME ID"
        rowstart = 0
        rowend = 5
        columnstart = 0
        columnend = 7
  
        unmergecell()
        
  

        CreateSpreadSheet()
        
        print(spreadsheetId)
        
     
 
    }
        

    //========================================================================================================
    //Write To Sheet Function
        
        func write() {
            let range = range1
            let updateValues = [[text1,text2,text3]]
            let valueRange = GTLRSheets_ValueRange() // GTLRSheets_ValueRange holds the updated values and other params
            valueRange.majorDimension = "ROWS" // Indicates horizontal row insert
            valueRange.range = range
            valueRange.values = updateValues
            let query = GTLRSheetsQuery_SpreadsheetsValuesAppend.query(withObject: valueRange, spreadsheetId: spreadsheetId, range: range)
            query.valueInputOption = "USER_ENTERED"
            
            service.executeQuery(query) { ticket, object, error in}
        }
      
   
    //========================================================================================================
    //Unmerge Cell Function

            func unmergecell() {
                
                let request = GTLRSheets_Request.init()

                let test = GTLRSheets_GridRange.init()
                    
                test.startRowIndex = rowstart
                test.endRowIndex = rowend
                test.startColumnIndex = columnstart
                test.endColumnIndex = columnend

                request.unmergeCells = GTLRSheets_UnmergeCellsRequest.init()
                request.unmergeCells?.range = test

                

                let batchUpdate = GTLRSheets_BatchUpdateSpreadsheetRequest.init()
                
                batchUpdate.requests = [request]
               
            
                let createQuery = GTLRSheetsQuery_SpreadsheetsBatchUpdate.query(withObject: batchUpdate, spreadsheetId: spreadsheetId)
              
                
            service.executeQuery(createQuery) { (ticket, result, NSError) in
                   
                   }
                  }
        

                       }
        
    //========================================================================================================
    //Create Spreadsheet Function

        
        func CreateSpreadSheet()
        {
            
            print("==============================================")
            print("Createsheet Function")
            
            let newSheet = GTLRSheets_Spreadsheet.init()
            let properties = GTLRSheets_SpreadsheetProperties.init()

            properties.title = "Daily JHA Form - "+date
            newSheet.properties = properties
            
            let query = GTLRSheetsQuery_SpreadsheetsCreate.query(withObject:newSheet)
            query.fields = "spreadsheetId"

            query.completionBlock = { (ticket, result, NSError) in

                if let error = NSError {
                    print("error!!!!!!!!!!!!!!!!!!!!!!!!!!")
                    print(error)
                }
                else {
                    let response = result as! GTLRSheets_Spreadsheet
                    let identifier = response.spreadsheetId
                    self.spreadsheetId = identifier!
                    GlobalVariable1.sheetID = self.spreadsheetId
                    print(self.spreadsheetId)
                }
            }
            service.executeQuery(query, completionHandler: nil)
        
        }


 
  //=========================================================================================================
    
    func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
        if let error = error {
          if (error as NSError).code == GIDSignInErrorCode.hasNoAuthInKeychain.rawValue {
            print("The user has not signed in before or they have since signed out.")
          } else {
            print("\(error.localizedDescription)")
          }
          return
        }
        // Perform any operations on signed in user here.
        let userId = user.userID                  // For client-side use only!
        let idToken = user.authentication.idToken // Safe to send to the server
        let fullName = user.profile.name
        let givenName = user.profile.givenName
        let familyName = user.profile.familyName
        let email = user.profile.email
        // ...
        print(fullName)
    }
    
    
    //=========================================================================================================
    // Display (in the UITextView) the names and majors of students in a sample
    // spreadsheet:
    //https://docs.google.com/spreadsheets/d/e/2PACX-1vTxKKu-0BwyOPq9HTYH237jGlMrf3q8kLwe5R2eH2dbkGqNbk3D7L9_MKxpO4b3g9cy09w2davohJzq/pubhtml
            
            func listMajors() {

        let range = "A1:Q"
        let query = GTLRSheetsQuery_SpreadsheetsValuesGet
                    .query(withSpreadsheetId: spreadsheetId, range:range)
                service.executeQuery(query) { (ticket, result, error) in
        if let error = error {
        self.showAlert(title: "Error", message: error.localizedDescription)
        return
                    }
        guard let result = result as? GTLRSheets_ValueRange else {
        return
                    }
        let rows = result.values!
        if rows.isEmpty {
    //    self.output.text = "No data found."
        return
                    }
    //    self.output.text = "Number of rows in sheet: \(rows.count)"
                }
            }
            

    // Process the response and display output
        func displayResultWithTicket(ticket: GTLRServiceTicket,
    finishedWithObject result : GTLRSheets_ValueRange,
    error : NSError?) {
    if let error = error {
    showAlert(title: "Error", message: error.localizedDescription)
    return
            }
    var majorsString = ""
    let rows = result.values!
    if rows.isEmpty {
    //           output.text = "No data found."
    return
            }
            majorsString += "Name, Major:\n"
    for row in rows {
    let name = row[0]
    let major = row[4]
                majorsString += "\(name), \(major)\n"
            }
    //        output.text = majorsString
        }
        
        
        
    // Helper for showing an alert
        func showAlert(title : String, message: String) {
    let alert = UIAlertController(
    title: title,
    message: message,
    preferredStyle: UIAlertController.Style.alert
            )
    let ok = UIAlertAction(
    title: "OK",
    style: UIAlertAction.Style.default,
    handler: nil
            )
            alert.addAction(ok)
    present(alert, animated: true, completion: nil)
        }


}


struct GlobalVariable1
{
    static var sheetID = ""
}


extension UIViewController {
    func hideKeyboardWhenTappedAround() {
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
        tap.cancelsTouchesInView = false
        view.addGestureRecognizer(tap)
    }

    @objc func dismissKeyboard() {
        view.endEditing(true)
    }

}


HOWEVER I get the following error:

Optional(Error Domain=com.google.GTLRErrorObjectDomain Code=401 "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project." UserInfo={GTLRStructuredError=GTLRErrorObject 0x600001182310: {errors:[1] message:"Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project." code:401 status:"UNAUTHENTICATED"}, NSLocalizedDescription=Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.})"

What am I doing wrong?

like image 710
Michael Szabo Avatar asked Oct 14 '22 21:10

Michael Szabo


1 Answers

Looking to the error generated by your code, and the scopes you try to require, it seems they are not enough. Indeed you set only:

private let scopes = [kGTLRAuthScopeSheetsSpreadsheets]

According to this google official doc about scopes you can find more details about all the scopes. In the middle part of your code you read profile informations and these info could be readed adding scopes about google sign in:

  • profile
  • email
like image 140
Alessandro Ornano Avatar answered Oct 20 '22 21:10

Alessandro Ornano