Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Google sign in to access Google spreadsheets (or other Google apps) on Android

I'm developing an Android app and added a google sign in feature by following the tutorial here: https://developers.google.com/identity/sign-in/android/sign-in

Now that the user is logged in I want to be able to read and write to their Google Spreadsheets. I have looked at the spreadsheets API and tells you to use OAuth to authorize requests: https://developers.google.com/google-apps/spreadsheets/?hl=en

From the sign in page tutorial:

The Google Sign-In button authenticates the user and manages the OAuth 2.0 flow, which simplifies your integration with the Google APIs.

I'm trying to use the Google sign in page for the authorization process. I can successfully log in and out of my Google account now using the GoogleApiClient, so I tried adding the following code to access my spreadsheets which I call when the user is signed in:

private class RetrieveFeedTask extends AsyncTask<String, Void, Void> {

        @Override
        protected Void doInBackground(String... urls) {
            SpreadsheetService service = new SpreadsheetService("MySpreadsheetIntegration-v1");

            try {
                URL SPREADSHEET_FEED_URL = new URL(urls[0]);
                SpreadsheetFeed feed = service.getFeed(SPREADSHEET_FEED_URL, SpreadsheetFeed.class);
                List<SpreadsheetEntry> spreadsheets = feed.getEntries();

                for (SpreadsheetEntry spreadsheet : spreadsheets) {
                    System.out.println(spreadsheet.getTitle().getPlainText());
                }

            } catch (ServiceException | IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

I call it using this line:

new RetrieveFeedTask().execute("https://spreadsheets.google.com/feeds/spreadsheets/private/full");

But on the service.getFeed call I'm getting the following error:

com.google.gdata.util.ParseException: Unrecognized content type:application/binary
    at com.google.gdata.client.Service.parseResponseData(Service.java:2136)
    at com.google.gdata.client.Service.parseResponseData(Service.java:2098)
    at com.google.gdata.client.Service.getFeed(Service.java:1136)
    at com.google.gdata.client.Service.getFeed(Service.java:998)
    at com.google.gdata.client.GoogleService.getFeed(GoogleService.java:645)
    at com.google.gdata.client.Service.getFeed(Service.java:1017)
    at com.zarwanhashem.ideatrackr.MainActivity$RetrieveFeedTask.doInBackground(MainActivity.java:320)
    at com.zarwanhashem.ideatrackr.MainActivity$RetrieveFeedTask.doInBackground(MainActivity.java:312)
    at android.os.AsyncTask$2.call(AsyncTask.java:292)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
    at java.lang.Thread.run(Thread.java:818)

The solutions I found by looking at past questions did not work. One of them was to do service.setUserCredentials(user, password) before the call, but I don't know how to get that information as I didn't personally implement the OAuth part.

How can I resolve this error and use the google sign in page as my authentication?


like image 214
Zarwan Avatar asked Oct 31 '22 22:10

Zarwan


1 Answers

First, I'd suggest to set the authorization header containing the access token.

String accountname = Plus.AccountApi.getAccountName(mGoogleApiClient);
String scope = "oauth2:" + Scopes.PLUS_LOGIN + " " + "https://spreadsheets.google.com/feeds"; // add more scopes here
String accessToken = GoogleAuthUtil.getToken(context, accountname, scope);
service.setHeader("Authorization", "Bearer " + accessToken);

Also, please note that if you want to create new sheets you will need more scopes added:

Additionally, if an application needs to create spreadsheets, or otherwise manipulate their metadata, then the application must also request a Google Drive API scope; see Choose Auth Scopes in the Google Drive API docs for information about the available scopes.

Another thing to try is to use the setOAuth2Credentials method, as described below, shamelessly stolen from Create Spreadsheet using Google Spreadsheet API in Google drive in Java.

   HttpTransport httpTransport = new NetHttpTransport();
   JacksonFactory jsonFactory = new JacksonFactory();
   String [] scopesArray= {"https://spreadsheets.google.com/feeds", "https://docs.google.com/feeds"}; // add more scopes here
   final List SCOPES = Arrays.asList(scopesArray);
   GoogleCredential credential = new GoogleCredential.Builder()
     .setTransport(httpTransport)
     .setJsonFactory(jsonFactory)
     .setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
     .setServiceAccountScopes(SCOPES)
     .setServiceAccountPrivateKeyFromP12File(SERVICE_ACCOUNT_PKCS12_FILE)
     .build();

   SpreadsheetService service = new SpreadsheetService("MySpreadsheetIntegration-v1");
   service.setOAuth2Credentials(credential);

Regarding the P12 key file, see https://webapps.stackexchange.com/questions/58411/how-where-to-obtain-a-p12-key-file-from-the-google-developers-console

Other references: https://developers.google.com/google-apps/spreadsheets/authorize https://developers.google.com/drive/web/scopes https://developers.google.com/android/reference/com/google/android/gms/common/api/Scope

like image 102
Alin Pandichi Avatar answered Nov 15 '22 04:11

Alin Pandichi