android - Always get 401 log in required from Gmail API -
ok, had working @ 1 point, wanted add silent login (optional) @ app startup. going crazy , getting following error
com.google.api.client.googleapis.json.googlejsonresponseexception: 401 unauthorized { "code": 401, "errors": [ { "domain": "global", "location": "authorization", "locationtype": "header", "message": "login required", "reason": "required" } ], "message": "login required" }
this occurs on line (should using "me"?)
message messageresult = mgmailservice.users().messages().send("me", message).execute();
whenever try send (in case above) or read email (not shown). ultimately, want app read user emails , send on behalf. app registered, has keys, permissions, etc.
i setting data (you can see various comments tried things working):
mgso = new googlesigninoptions.builder(googlesigninoptions.default_sign_in) .requestemail() .requestscopes(new scope(scopes.profile)) .requestscopes(new scope(gmailscopes.gmail_readonly)) .requestscopes(new scope(gmailscopes.gmail_send)) .requestscopes(new scope(gmailscopes.gmail_compose)) .requestscopes(new scope(gmailscopes.gmail_labels)) .requestscopes(plus.scope_plus_login) .requestscopes(new scope(scopes.email)) .requestscopes(new scope(scopes.plus_me)) .build(); // set google client // mgoogleapiclient = new googleapiclient.builder(this) // .addconnectioncallbacks(this) // .addonconnectionfailedlistener(this) // .addapi(plus.api) // .addapi(auth.google_sign_in_api, mgso) // .build(); mgoogleapiclient = new googleapiclient.builder(this) // .enableautomanage(this, this) .addconnectioncallbacks(this) .addonconnectionfailedlistener(this) .addapi(plus.api) .addapi(auth.google_sign_in_api, mgso) .build(); //mgoogleapiclient.connect(googleapiclient.sign_in_mode_required); // try connect right away mgmailservice = new com.google.api.services.gmail.gmail.builder( androidhttp.newcompatibletransport(), gsonfactory.getdefaultinstance(), null) .setapplicationname("com.company.appname") .build();
the silent login done in onstart() method of embedded fragment as:
// try silently sign in ... optionalpendingresult<googlesigninresult> pendingresult = auth.googlesigninapi.silentsignin(mgoogleapiclient); if (pendingresult.isdone()) { // there's immediate result available. msigninacct = pendingresult.get().getsigninaccount(); memailacct = msigninacct.getemail(); } else { // there's no immediate result ready, wait async callback. pendingresult.setresultcallback(new resultcallback<googlesigninresult>() { @override public void onresult(@nonnull googlesigninresult result) { msigninacct = result.getsigninaccount(); memailacct = msigninacct.getemail(); } // if fails, forget , force real login later. }); } mgoogleapiclient.connect(googleapiclient.sign_in_mode_optional); boolean b = mgoogleapiclient.isconnected();
which connects right away valid user account , not. see b ...isconnected() call false, although isconnected() returns true later in later calls.
login button code:
gmail_signin_button = (com.google.android.gms.common.signinbutton) rootview.findviewbyid(r.id.gmail_sign_in_button); gmail_signin_button.setscopes(mgso.getscopearray()); gmail_signin_button.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { // user clicked sign-in button, begin sign-in process , automatically // attempt resolve errors occur. mshouldresolve = true; // connect if unconnected... if (!mgoogleapiclient.isconnected()) { mgoogleapiclient.connect(); tv_email_status.settext("g+ connecting"); // show message user signing in. log.d(constants.tag, "google api connecting ..."); } else { // sign in anew ... intent signinintent = auth.googlesigninapi.getsigninintent(mgoogleapiclient); startactivityforresult(signinintent, constants.rc_sign_in); } } });
onactivityresult code (in part):
public void onactivityresult(int requestcode, int resultcode, intent data) { super.onactivityresult(requestcode, resultcode, data); // g+ if (requestcode == constants.rc_sign_in) { // if error resolution not successful should not resolve further. googlesigninresult result = auth.googlesigninapi.getsigninresultfromintent(data); if (!result.issuccess()) { mshouldresolve = false; log.d(constants.tag, "error: code: " + resultcode); tv_email_status.settext("error: code: " + resultcode); } else { msigninacct = result.getsigninaccount(); memailacct = msigninacct.getemail(); log.d(constants.tag, "gmail signin ok - " + memailacct); tv_email_status.settext("email: " + memailacct); } misresolving = false; if(!mgoogleapiclient.isconnected()) { mgoogleapiclient.connect(googleapiclient.sign_in_mode_optional); } } else if (requestcode == constants.request_account_picker) { if (resultcode == result_ok && data != null && data.getextras() != null) { memailacct = data.getstringextra(accountmanager.key_account_name); if (memailacct != null) { //mcredential.setselectedaccountname(accountname); sharedpreferences settings = mactivity.getpreferences(context.mode_private); sharedpreferences.editor editor = settings.edit(); editor.putstring(constants.pref_account_name, memailacct); editor.commit(); log.d(constants.tag, "gmail: account: " + memailacct); tv_email_status.settext("gmail: account: " + memailacct); } } else if (resultcode == result_canceled) { tv_email_status.settext("account unspecified."); } } //else if (requestcode == constants.request_authorization) { //if (mcredential != null && resultcode != result_ok) { // startactivityforresult(mcredential.newchooseaccountintent(), constants.request_account_picker); //} //}
ok, onactivityresult , valid signinacct , emailacct values. it seems logged in fine, gmail service fails 401 error explained above.
to silent login made me have add google_sign_in_api seems require googleapiclient connect sign_in_mode_optional doesn't make sense me.
i see accountpicker nothing well. story/problem, said thought had working until tried add silent feature.
whew, have made harder is, can steer me in right direction? said want is:
- silently log in if user has done so
- allow user log in or re-log in if needed
- read users emails , contacts
- send email on behalf.
ok, figured out, usual simple wrong. credential in gmailservice constructor must set, don't have until try connect. have code this
void setgmailaccess(googlesigninresult result) { msigninacct = result.getsigninaccount(); memailacct = msigninacct.getemail(); final thread task = new thread() { @override public void run() { try { // run in background thread string token = googleauthutil.gettoken(mainactivity.this, plus.accountapi.getaccountname(mgoogleapiclient), "oauth2:profile email"); googlecredential credential = new googlecredential().setaccesstoken(token); mgmailservice = new com.google.api.services.gmail.gmail.builder( androidhttp.newcompatibletransport(), gsonfactory.getdefaultinstance(), credential) .setapplicationname("com.company.appname") .build(); } catch (exception e) { // ignore errors string error = e.getmessage(); } } }; task.start(); }
to set gmailservice object. called onconnected, have code in result success block:
try { // try silently sign in ... optionalpendingresult<googlesigninresult> pendingresult = auth.googlesigninapi.silentsignin(mgoogleapiclient); if (pendingresult.isdone()) { // there's immediate result available. setgmailaccess(pendingresult.get()); } else { // there's no immediate result ready, wait async callback. pendingresult.setresultcallback(new resultcallback<googlesigninresult>() { @override public void onresult(@nonnull googlesigninresult result) { setgmailaccess(result); } // if fails, forget , force real login later. }); } } catch(exception e) { string me = e.getlocalizedmessage(); }
and in activity result starting new login. seems work.
Comments
Post a Comment