GMail API Grant Permissions Before UserRecoverableAuthUIException
Asked Answered
F

3

7

I've followed the quickstart example from Google to setup the GMail API: https://developers.google.com/gmail/api/quickstart/android

My app successfully requests the GET_ACCOUNTS permission and allows the user to select his/her gmail account. The selected account is saved in SharedPreferences for later access.

Through an IntentService, my app sends an email. I have followed the instructions located here: https://developers.google.com/gmail/api/guides/sending and included the activation.jar, additional.jar, and mail.jar libraries as needed. When I send the email with the below code, I get a UserRecoverableAuthUIException:

message = service.users().messages().send(userId, message).execute();

When I catch the exception, get the intent stored with the exception, and start the intent as a new activity, I am shown a dialog giving me the chance to allow my app to send email with my GMail account:

UserRecoverableAuthIOException Intent Activity

After pressing 'Allow' on this dialog, my app sends emails without any further issues. My app also appears on my Google account's permissions page online saying it has permission to send email.

Is there a way to manually trigger this dialog when I first acquire the user's account name rather than waiting for the exception to occur?

UPDATE

I have been able to extract the action and data stored in the intent if that helps any:

  • action: com.google.android.gms.ui.UNPACKING_REDIRECT
  • data: intent://com.google.android.gms.auth.uiflows.common/KEY

where KEY is a series of characters, probably linked to my account or are a token.

EDIT:

The following is the code to create the Credentials object and starting the account picker activity which I'm using:

private GoogleAccountCredential mCredential;
private static final String[] SCOPES = { GmailScopes.GMAIL_COMPOSE };

Inside constructor:

mCredential = GoogleAccountCredential.usingOAuth2(
                getApplicationContext(), Arrays.asList(SCOPES))
                .setBackOff(new ExponentialBackOff());

Where I get the account:

private void chooseGMailAccount() {
        String accountName = this.getSharedPreferences(getString(R.string.shared_pref_main),
                Context.MODE_PRIVATE)
                .getString(getString(R.string.srd_pref_gmail_account), null);
        if (accountName != null) {
            mCredential.setSelectedAccountName(accountName);
            configureGMailAPI();
        } else {
            startActivityForResult(
                    mCredential.newChooseAccountIntent(),
                    REQUEST_ACCOUNT_PICKER);
        }
    }
Foggia answered 29/12, 2016 at 22:21 Comment(2)
Try to send a mail while registration i.e after user choose account. At this point it will catch exception, once u get this exception show this pop up. After this user is good to go. I guess there is no direct way to trigger this pop up. As per developers.google.com/drive/android/auth. Authorization happens in response to receiving an error when sending a request. Your app must be prepared to catch the UserRecoverableAuthIOException. This means the user needs toHaymaker
It's odd you can't trigger this directly. I feel like this would be the only route at this point. Rather than sending the email, I could attempt to create and delete an empty draft. I won't be able to implement this until later this week, but I'll update the original post with the results.Foggia
H
1

Try to send a mail while registration i.e after user choose account. At this point it will catch exception, once u get this exception show this pop up. After this user is good to go. I guess there is no direct way to trigger this pop up. As per developers.google.com/drive/android/auth. Authorization happens in response to receiving an error when sending a request. Your app must be prepared to catch the UserRecoverableAuthIOException. This means the user needs to authorize the app. Until your app is authorized by user, your app can't do anything.

Haymaker answered 11/1, 2017 at 7:57 Comment(0)
D
2

You could try to add a few permissions to your manifest

<uses-permission android:name="com.google.android.gm.permission.WRITE_GMAIL" />
<uses-permission android:name="com.google.android.gm.permission.AUTO_SEND" />

And it should still need oAuth for user authentication but will allow the intent automatically these permissions ...

Haven't tested it but it might work

Depriest answered 10/1, 2017 at 19:45 Comment(0)
H
1

Try to send a mail while registration i.e after user choose account. At this point it will catch exception, once u get this exception show this pop up. After this user is good to go. I guess there is no direct way to trigger this pop up. As per developers.google.com/drive/android/auth. Authorization happens in response to receiving an error when sending a request. Your app must be prepared to catch the UserRecoverableAuthIOException. This means the user needs to authorize the app. Until your app is authorized by user, your app can't do anything.

Haymaker answered 11/1, 2017 at 7:57 Comment(0)
P
0

To request the "managing drafts and sending emails" permission when the user is choosing an account, include GmailScopes.GMAIL_COMPOSE in the scopes when building GoogleAccountCredential.

   import com.google.api.services.gmail.GmailScopes;

   String[] SCOPES = { GmailScopes.GMAIL_COMPOSE, GmailScopes.GMAIL_LABELS };
   int REQUEST_ACCOUNT_PICKER = 1001;

   GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(
            getApplicationContext(), Arrays.asList(SCOPES))
            .setBackOff(new ExponentialBackOff());

   startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);

See the Gmail API Javadoc for a list of scopes.

Peckham answered 6/1, 2017 at 10:4 Comment(1)
Hmm, it appears this is what I've already got. The constructor of my activity creates the GoogleAccountCredential object exactly as shown in your snippet. I changed the scopes from what I had to just GMAIL_COMPOSE, and this did not resolve the issue. startActivityForResult is called outside of the constructor, but using the same credential object.Foggia

© 2022 - 2024 — McMap. All rights reserved.