Google Drive API - the name must not be empty: null (But I had passed valid account name to GoogleAccountCredential)
Solution 1
It looks like the Drive API Client Library for Java calls into GoogleAuthUtil.getToken()
, which requires the GET_ACCOUNTS
permission. You need to have that permission in your manifest and request it at runtime, as appropriate.
UPDATE:
With Google Drive REST v3 API, GET_ACCOUNTS
permission is not required. Instead, Email permission is required. You can ask for it by calling GoogleSignInOptions.Builder.requestEmail
.
Solution 2
I had the same problem, all permissions were granted and still I got this error.
My simple problem was, that the googleSignInAccount.getSignInAccount().getAccount()
was null
. This is the case, if you do NOT request the email permissions (GoogleSignInOptions.Builder.requestEmail
). Seems like this account can't be created without the user email.
So make sure to add this permission to the GoogleSignInOptions
...
Solution 3
This is because from Android 6.0 (API level 23)
you need to get the Contacts permission before you invoke google endpoints.
You can see complete details here - https://developer.android.com/training/permissions/requesting.html
This is true only for Dangerous permissions and permission groups (based on how much they are related to user privacy). More details - https://developer.android.com/guide/topics/security/permissions.html#perm-groups
Solution 4
In my case (Google Drive REST API v3), ProGuard was the culprit, as the code was working fine in debug mode.
Just adding -keep class com.google.** { *;}
to ProGuard rules got rid of the issue.
PS: I had to call requestEmail()
but I did not ask for any GET_ACCOUNTS
permission.
Solution 5
I use google api client
// Dependency of Google Api client
implementation 'com.google.api-client:google-api-client:1.30.9'
implementation 'com.google.api-client:google-api-client-android:1.30.9'
implementation 'com.google.apis:google-api-services-drive:v3-rev20200413-1.30.9'
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestScopes(new Scope(Scopes.DRIVE_APPFOLDER))
//requestEmail required
.requestEmail()
.build();
GoogleSignInClient mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
// in onActivityResult method
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
GoogleSignInAccount account = completedTask.getResult(ApiException.class);
// androidAccount will be null if no email
android.accounts.Account androidAccount = account.getAccount();
You can see it from the source code of android.accounts.Account
private String zag;
@Field(
id = 4,
getter = "getEmail"
)
private String zah;
@Nullable
public Account getAccount() {
// getEmail required
return this.zah == null ? null : new Account(this.zah, "com.google");
}
Related videos on Youtube
Lumii
WeNote - Notes, To-do lists, Reminders & Calendar JStock Android JStock - Free Stock Market Software WeFocus - Focus, Pomodoro, Do one thing at a time
Updated on September 15, 2022Comments
-
Lumii over 1 year
Recently, I have Android code which accesses to Google Drive. I'm using Google APIs Client Library for Java instead of Google Play services client library
private static GoogleCloudFile searchFromGoogleDrive(Drive drive, String qString, HandleUserRecoverableAuthIOExceptionable h, PublishProgressable p) { try { Files.List request = drive.files().list().setQ(qString); do { if (p.isCancelled()) { return null; } FileList fileList = request.execute();
The code works 100% fine for several years, if I use
targetSdkVersion 21
.Recently, I migrate my app to
targetSdkVersion 23
, with 0 change on Google Drive related code.However, the code crashes mystery at
FileList fileList = request.execute();
, with the following exception.Error log while using 1.18.0-rc
Process: org.yccheok.jstock.gui, PID: 30317 java.lang.RuntimeException: An error occurred while executing doInBackground() at android.os.AsyncTask$3.done(AsyncTask.java:309) at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354) at java.util.concurrent.FutureTask.setException(FutureTask.java:223) at java.util.concurrent.FutureTask.run(FutureTask.java:242) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) at java.lang.Thread.run(Thread.java:818) Caused by: java.lang.IllegalArgumentException: the name must not be empty: null at android.accounts.Account.<init>(Account.java:48) at com.google.android.gms.auth.zzd.getToken(Unknown Source) at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source) at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential.getToken(GoogleAccountCredential.java:255) at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential$RequestHandler.intercept(GoogleAccountCredential.java:279) at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:859) at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410) at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343) at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460) at org.yccheok.jstock.gui.Utils.searchFromGoogleDrive(Utils.java:208) at org.yccheok.jstock.gui.Utils._loadFromGoogleDrive(Utils.java:277) at org.yccheok.jstock.gui.Utils.loadFromGoogleDrive(Utils.java:344) at org.yccheok.jstock.gui.LoadFromCloudTask.doInBackground(LoadFromCloudTask.java:23) at org.yccheok.jstock.gui.LoadFromCloudTask.doInBackground(LoadFromCloudTask.java:9) at android.os.AsyncTask$2.call(AsyncTask.java:295) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) at java.lang.Thread.run(Thread.java:818)
If I google, I get Google Drive on android error: java.lang.IllegalArgumentException: the name must not be empty: null , which states that account name is not passed to credential object.
However, I'm pretty much sure that my credential object is passed with valid account name (in format [email protected])
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { switch (requestCode) { case RequestCode.REQUEST_ACCOUNT_PICKER_LOAD_FROM_CLOUD: if (resultCode == RESULT_OK && data != null && data.getExtras() != null) { String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME); Log.i("CHEOK", "accountName = " + accountName); if (accountName != null) { JStockApplication.instance().getJStockOptions().setUsername(accountName); Utils.getGoogleAccountCredential().setSelectedAccountName(accountName);
Utils.java
public static GoogleAccountCredential getGoogleAccountCredential() { return googleAccountCredential; } private static final GoogleAccountCredential googleAccountCredential = GoogleAccountCredential.usingOAuth2(JStockApplication.instance(), Arrays.asList( DriveScopes.DRIVE_APPDATA, // Legacy. Shall be removed after a while... DriveScopes.DRIVE ) ); private Drive getDriveService() { return new Drive.Builder(AndroidHttp.newCompatibleTransport(), new GsonFactory(), Utils.getGoogleAccountCredential()).build(); }
Also, I'm pretty sure that my OAuth 2.0 correctly through Google Developers Console (For both debug keystore & production keystore) Recently, Android 6 introduces run-time permissions. I was wondering, can this exception related to that?
I further try with latest library version 1.21.0. However, I still get similar error log
Error log while using 1.21.0
java.lang.RuntimeException: An error occurred while executing doInBackground() at android.os.AsyncTask$3.done(AsyncTask.java:309) at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354) at java.util.concurrent.FutureTask.setException(FutureTask.java:223) at java.util.concurrent.FutureTask.run(FutureTask.java:242) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) at java.lang.Thread.run(Thread.java:818) Caused by: java.lang.IllegalArgumentException: the name must not be empty: null at android.accounts.Account.<init>(Account.java:48) at com.google.android.gms.auth.zzd.getToken(Unknown Source) at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source) at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential.getToken(GoogleAccountCredential.java:255) at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential$RequestHandler.intercept(GoogleAccountCredential.java:279) at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:859) at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419) at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352) at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469) at org.yccheok.jstock.gui.Utils.searchFromGoogleDrive(Utils.java:208) at org.yccheok.jstock.gui.Utils._loadFromGoogleDrive(Utils.java:277) at org.yccheok.jstock.gui.Utils.loadFromGoogleDrive(Utils.java:344) at org.yccheok.jstock.gui.LoadFromCloudTask.doInBackground(LoadFromCloudTask.java:23) at org.yccheok.jstock.gui.LoadFromCloudTask.doInBackground(LoadFromCloudTask.java:9) at android.os.AsyncTask$2.call(AsyncTask.java:295) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) at java.lang.Thread.run(Thread.java:818)
Update on my further testing
The above 2 error logs are generated while I'm testing using Nexus 5, Android version 6.0.1
However, if I conduct the same testing using Nexus 4, Android version 5.1.1, no error occurs! Both 1.18.0-rc and 1.21.0 are working fine
Hence, it seems the crash is strongly related to Android version.
-
Lumii over 8 yearsOh well. I don't think I can explain to user clearly, why I need to access their contacts information in order to access their Google Drive content. I rather not take the risk of having to trigger the nuclear option (Don't ask again). Do you think Google can provide a way to by-pass such restriction? Meanwhile, going to try to migrate the code to Play services to see it helps.
-
ianhanniballake over 8 years@CheokYanCheng - yes, I'd encourage you to manually grant yourself the 'Contacts' permission group (which includes
GET_ACCOUNTS
) to ensure that is the issue, but using Google Play services is definitely highly recommended for Android apps (particularly for easy authentication). -
Lumii over 8 yearsAfter testing by manual granting, I can pretty confirm this problem is caused by not having GET_ACCOUNTS permission. Is there any way which Google Drive team can design the API in the way which doesn't require GET_ACCOUNTS run-time permission? The reason I'm asking so is that, after experimenting for few days, I realize GDAA doesn't handle some edge cases as good as REST Api such as stackoverflow.com/q/33248420/72437 This makes migration to GDAA difficult.
-
ianhanniballake over 8 yearsFrom the Google Api Client page on supported devices: " if a Google Play Services library is available for the Google service you need, use that library instead of this one."
-
chenghuayang almost 7 yearsI just met this problem when setting the automatically uploading function on one app. Once I saw the answer, I logged out and signed in again. It works. Just add this as a reminder for those who just meet the problem dialog when using app.
-
Jürgen Jatzkowski over 6 yearsIn my case it was required (beside requesting email permissions) to switch from
credential.setSelectedAccountName()
tocredential.setSelectedAccount()
-
Roman Samoilenko almost 6 yearsIt would still crash on Android Oreo because GET_ACCOUNTS became deprecated. What to do in such case?
-
Alin about 5 yearsThanks! It seems like the GET_ACCOUNTS permission is NOT required for Google Drive REST v3 API. But calling requestEmail() is required
-
Merk over 4 yearsThis is not a sensible explanation. My app is using its own Drive AppData folder only. The associated scope is not one of the ones marked dangerous, and there is no good reason why the REST v3 API should require the user email when the deprecated Android Drive SDK does not. Isn't one of the purposes of OAuth (where the problem is triggered) to hide certain properties of agents (e.g., ultimate email address) to systems that don't need to know? Seems like a design problem on Google's part.