I have an iOS 11 application that can currently query the Google Sheets spreadsheet to retrieve all the data from any named worksheet (tab), assuming the spreadsheet is public (i.e. no authentication or authorization is required). Here is a simplified version of my current code that works great:
-(void)fetchSheet { if (self.service == nil) { self.service = [[GTLRSheetsService alloc] init]; self.service.APIKey = @"MY_API_KEY"; }
Now I would like to make changes so that the owner of the sheet can optionally restrict the sheet only to my application, but I do not want the user to need a Google account or log in to Google. My application should just read the spreadsheet without user intervention. Any user can use a spreadsheet with my application, providing read-only access to the user MyApp@gmail.com (which my application knows about). The best idea I can find is How do I resolve an application (website or installed) without user intervention? , which uses Google OAuthPlayground for initial authentication and then ends with an authorization token and an update token. (Of course, I use the GTLRSheetsService instead of the Drive service shown on this page.) The idea is that my application can use the update token at any time in the future, and Google client libraries will use this token update to get a new authorization token and then make a request.
I understand that the consequences of this approach are related to security. Suppose my application receives the update token through iCloud or from the server on which I host. (This is especially convenient if I ever need to change the update token.) For now, I'm just trying to get it to work with a hard-coded update token.
I followed the instructions in the accepted answer on this page and as a result, an update token appeared (as well as a client identifier, etc.). But now I do not know how to use it. After searching many times, I found code that uses GTMOAuth2Authentication , but I think GTMAppAuth should be used GTMAppAuth (right?). Here is my new version of fetchSheet :
-(void)fetchSheet { if (self.service == nil) { self.service = [[GTLRSheetsService alloc] init]; // note that I am no longer setting service.APIKey // Create GTMOAuth2Authentication object to hold the refresh_token GTMOAuth2Authentication *auth = [[GTMOAuth2Authentication alloc] init]; auth.clientID = @"MY_CLIENT_ID"; auth.clientSecret = @"MY_CLIENT_SECRET"; auth.userEmail = @" MyApp@gmail.com "; auth.userID = @"myapp"; auth.refreshToken = @"MY_REFRESH_TOKEN"; // Save and use self.googleAuth = auth; self.service.authorizer = self.googleAuth; } // Build the query NSString *range = @"MainSheet!A1:E"; GTLRSheetsQuery_SpreadsheetsValuesGet *query = [GTLRSheetsQuery_SpreadsheetsValuesGet queryWithSpreadsheetId:self.spreadsheetId range:range]; // Execute the query [self.service executeQuery:query delegate:self didFinishSelector:@selector(parseAboutSheetWithTicket:finishedWithObject:error:)]; } // fetchSheet
When I run this code, it fails and prints: "At the beginning of debugging, a request with a URL is required." What kind of URL does he have in mind, and why do I need to install it now when I haven't done it before?
I also tried using GTMAppAuthFetcherAuthorization (with OIDServiceConfiguration , OIDAuthorizationRequest and OIDAuthState ) instead of GTMOAuth2Authentication , but then I got the error "Unable to open Safari", indicating that he was trying to use standard authentication and authorization from Google users.
Does anyone know how to make this work? If the approach I'm following should work, then I assume that I just need to create some object that implements GTMFetcherAuthorizationProtocol and which contains the update token. This seems conceptually simple, but the process on this page does not describe how to actually use the update token (and what else is required or not required to install). There seem to be many other things about using other libraries, but I would like to continue to use GTLRSheetsService (because it allows me to use certain result classes such as GTLRSheets_ValueRange ).