Google Drive API - 名称不得为空:null(但我已将有效的帐户名称传递给GoogleAccountCredential)

时间:2016-01-06 18:13:08

标签: android google-drive-api

最近,我有Android代码访问Google云端硬盘。我使用 Google API Client Library for Java 而不是 Google Play服务客户端库

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();

如果我使用targetSdkVersion 21,则代码可以正常工作几年。

最近,我将我的应用迁移到targetSdkVersion 23,对Google云端硬盘相关代码进行了0次更改。

然而,代码在FileList fileList = request.execute();崩溃了,但有以下例外。

使用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) 

如果我谷歌,我会得到Google Drive on android error: java.lang.IllegalArgumentException: the name must not be empty: null,其中说明帐户名称未传递给凭据对象。

但是,我非常确定我的凭证对象是以有效的帐户名传递的(格​​式为xxx@gmail.com)

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();
}

此外,我非常确定通过Google Developers Console正确使用我的OAuth 2.0(适用于调试密钥库和生产密钥库) 最近,Android 6引入了运行时权限。我在想,这个例外可以与此相关吗?

我进一步尝试使用最新的库版本1.21.0。但是,我仍然得到类似的错误日志

使用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) 

我的进一步测试更新

我在使用Nexus 5,Android版本6.0.1进行测试时会生成以上2个错误日志

但是,如果我使用Nexus 4,Android版本5.1.1进行相同的测试,则不会发生错误! 1.18.0-rc和1.21.0都正常工作

因此,似乎崩溃与Android版本密切相关。

5 个答案:

答案 0 :(得分:13)

看起来,用于Java的Drive API客户端库调用GoogleAuthUtil.getToken(),这需要GET_ACCOUNTS权限。您需要在清单中拥有该权限,并在运行时根据需要请求它。

答案 1 :(得分:4)

我遇到了同样的问题,所有权限都被授予了,但我仍然遇到了这个错误。

我的简单问题是googleSignInAccount.getSignInAccount().getAccount()null。如果您不请求电子邮件权限(GoogleSignInOptions.Builder.requestEmail),则会出现这种情况。似乎此帐户无法在没有用户电子邮件的情况下创建。

因此,请务必将此权限添加到GoogleSignInOptions ...

答案 2 :(得分:2)

这是因为从stdout开始,您需要在调用Google端点之前获取“联系”权限。

您可以在此处查看完整的详细信息 - https://developer.android.com/training/permissions/requesting.html

仅适用于危险权限和权限组(基于它们与用户隐私的关联程度)。更多详情 - https://developer.android.com/guide/topics/security/permissions.html#perm-groups

答案 3 :(得分:1)

就我而言(Google Drive REST API v3),ProGuard是罪魁祸首,因为代码在调试模式下运行良好。

只需在ProGuard规则中添加d = { key: value } | d 即可解决问题。

PS:我必须打-keep class com.google.** { *;},但我没有要求任何requestEmail()许可。

答案 4 :(得分:1)

我使用google api客户端

remote
// 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(); 的源代码中看到它

android.accounts.Account