简体   繁体   English

使用Google Drive API时无限的“选择帐户”循环

[英]Infinite “Choose an account” loop when using Google Drive API

I'm trying to set up an Android app that can manipulate files stored on my personal Google Drive account using the guidelines at Google Drive REST API Overview . 我正在尝试设置一个Android应用,该应用可以使用Google Drive REST API概述中的指南来操纵存储在我的Google Drive个人帐户中的文件。

I've followed the sample code to allow a user to connect to the account, but the "Choose an account" dialog reappears continually regardless of whether an account name is chosen or the cancel button is pressed. 我遵循了示例代码,以允许用户连接到该帐户,但是无论选择帐户名还是按下取消按钮,“选择帐户”对话框都会反复出现。

I believe the problem is that the refreshResults() method keeps returning null when testing for mCredential.getSelectedAccountName() even after an account name has been selected from the account chooser dialog. 我认为问题在于,即使在从帐户选择器对话框中选择了帐户名称之后,在测试mCredential.getSelectedAccountName()时, refreshResults()方法仍会返回null。 However don't know why this is happening or how to fix it. 但是不知道为什么会这样或如何解决。 I'd greatly appreciate it if someone more experienced could advise me. 如果有经验的人可以建议我,我将不胜感激。 Thanks. 谢谢。

My code is as follows: 我的代码如下:

import android.accounts.AccountManager;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.googleapis.extensions.android.gms.auth.GooglePlayServicesAvailabilityIOException;
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.ExponentialBackOff;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.FileList;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


public class HomeActivity extends AppCompatActivity{

    GoogleAccountCredential mCredential;
    ProgressDialog mProgress;

    static final int REQUEST_ACCOUNT_PICKER = 1000;
    static final int REQUEST_AUTHORIZATION = 1001;
    static final int REQUEST_GOOGLE_PLAY_SERVICES = 1002;
    private static final String PREF_ACCOUNT_NAME = "accountName";
    private static final String[] SCOPES = { DriveScopes.DRIVE_METADATA_READONLY };

    public TextView mOutputText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Initialize credentials and service object.
        SharedPreferences settings = getPreferences(Context.MODE_PRIVATE);
        mCredential = GoogleAccountCredential.usingOAuth2(
                getApplicationContext(), Arrays.asList(SCOPES))
                .setBackOff(new ExponentialBackOff())
                .setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null));

        mProgress = new ProgressDialog(this);
        mProgress.setMessage("Calling Drive API ...");

        setContentView(R.layout.activity_home);
        mOutputText = (TextView) findViewById(R.id.textStatus);

    @Override
    protected void onResume() {
        super.onResume();

            if (isGooglePlayServicesAvailable()) {
                refreshResults();
            } else {
                mOutputText.setText("Google Play Services required: " +
                        "after installing, close and relaunch this app.");
            }
        }

    /**
     * Called when an activity launched here (specifically, AccountPicker
     * and authorization) exits, giving you the requestCode you started it with,
     * the resultCode it returned, and any additional data from it.
     * @param requestCode code indicating which activity result is incoming.
     * @param resultCode code indicating the result of the incoming
     *     activity result.
     * @param data Intent (containing result data) returned by incoming
     *     activity result.
     */
    @Override
    protected void onActivityResult(
            int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        switch(requestCode) {
            case REQUEST_GOOGLE_PLAY_SERVICES:
                if (resultCode != RESULT_OK) {
                    isGooglePlayServicesAvailable();
                }
                break;
            case REQUEST_ACCOUNT_PICKER:
                if (resultCode == RESULT_OK && data != null &&
                        data.getExtras() != null) {

                    String accountName =
                            data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);

                    if (accountName != null) {
                        mCredential.setSelectedAccountName(accountName);
                        SharedPreferences settings =
                                getPreferences(Context.MODE_PRIVATE);
                        SharedPreferences.Editor editor = settings.edit();
                        editor.putString(PREF_ACCOUNT_NAME, accountName);
                        editor.apply();
                    }
                } else if (resultCode == RESULT_CANCELED) {
                    mOutputText.setText("Account unspecified.");
                }
                break;
            case REQUEST_AUTHORIZATION:
                if (resultCode != RESULT_OK) {
                    chooseAccount();
                }
                break;
        }

        super.onActivityResult(requestCode, resultCode, data);
    }

    /**
     * Attempt to get a set of data from the Drive API to display. If the
     * email address isn't known yet, then call chooseAccount() method so the
     * user can pick an account.
     */
    private void refreshResults() {
        if (mCredential.getSelectedAccountName() == null) {
            chooseAccount();
        } else {
            if (isDeviceOnline()) {
                new MakeRequestTask(mCredential).execute();
            } else {
                mOutputText.setText("No network connection available.");
            }
        }
    }

    /**
     * Starts an activity in Google Play Services so the user can pick an
     * account.
     */
    private void chooseAccount() {
        startActivityForResult(
                mCredential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);
    }

    /**
     * Checks whether the device currently has a network connection.
     * @return true if the device has a network connection, false otherwise.
     */
    private boolean isDeviceOnline() {
        ConnectivityManager connMgr =
                (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
        return (networkInfo != null && networkInfo.isConnected());
    }

    /**
     * Check that Google Play services APK is installed and up to date. Will
     * launch an error dialog for the user to update Google Play Services if
     * possible.
     * @return true if Google Play Services is available and up to
     *     date on this device; false otherwise.
     */
    private boolean isGooglePlayServicesAvailable() {
        final int connectionStatusCode =
                //GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
                GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this);
        if (GoogleApiAvailability.getInstance().isUserResolvableError(connectionStatusCode)) {
            showGooglePlayServicesAvailabilityErrorDialog(connectionStatusCode);
            return false;
        } else if (connectionStatusCode != ConnectionResult.SUCCESS ) {
            return false;
        }
        return true;
    }

    /**
     * Display an error dialog showing that Google Play Services is missing
     * or out of date.
     * @param connectionStatusCode code describing the presence (or lack of)
     *     Google Play Services on this device.
     */
    void showGooglePlayServicesAvailabilityErrorDialog(
            final int connectionStatusCode) {
        //Dialog dialog = GooglePlayServicesUtil.getErrorDialog(
        Dialog dialog = GoogleApiAvailability.getInstance().getErrorDialog(
                HomeActivity.this,
                connectionStatusCode,
                REQUEST_GOOGLE_PLAY_SERVICES);
        dialog.show();
    }

    /**
     * An asynchronous task that handles the Drive API call.
     * Placing the API calls in their own task ensures the UI stays responsive.
     */
    private class MakeRequestTask extends AsyncTask<Void, Void, List<String>> {
        private com.google.api.services.drive.Drive mService = null;
        private Exception mLastError = null;

        public MakeRequestTask(GoogleAccountCredential credential) {
            HttpTransport transport = AndroidHttp.newCompatibleTransport();
            JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
            mService = new com.google.api.services.drive.Drive.Builder(
                    transport, jsonFactory, credential)
                    .setApplicationName("Media Vault")
                    .build();
        }

        /**
         * Background task to call Drive API.
         * @param params no parameters needed for this task.
         */
        @Override
        protected List<String> doInBackground(Void... params) {
            try {
                return getDataFromApi();
            } catch (Exception e) {
                mLastError = e;
                cancel(true);
                return null;
            }
        }

        /**
         * Fetch a list of up to 10 file names and IDs.
         * @return List of Strings describing files, or an empty list if no files
         *         found.
         * @throws IOException
         */
        private List<String> getDataFromApi() throws IOException {
            // Get a list of up to 10 files.
            List<String> fileInfo = new ArrayList<String>();
            FileList result = mService.files().list()
                    .setPageSize(10)
                    .setFields("nextPageToken, items(id, name)")
                    .execute();
            List<File> files = result.getFiles();
            if (files != null) {
                for (File file : files) {
                    fileInfo.add(String.format("%s (%s)\n",
                            file.getName(), file.getId()));
                }
            }
            return fileInfo;
        }

        @Override
        protected void onPreExecute() {
            mOutputText.setText("");
            mProgress.show();
        }

        @Override
        protected void onPostExecute(List<String> output) {
            mProgress.hide();
            if (output == null || output.size() == 0) {
                mOutputText.setText("No results returned.");
            } else {
                output.add(0, "Data retrieved using the Drive API:");
                mOutputText.setText(TextUtils.join("\n", output));
            }
        }

        @Override
        protected void onCancelled() {
            mProgress.hide();
            if (mLastError != null) {
                if (mLastError instanceof GooglePlayServicesAvailabilityIOException) {
                    showGooglePlayServicesAvailabilityErrorDialog(
                            ((GooglePlayServicesAvailabilityIOException) mLastError)
                                    .getConnectionStatusCode());
                } else if (mLastError instanceof UserRecoverableAuthIOException) {
                    startActivityForResult(
                            ((UserRecoverableAuthIOException) mLastError).getIntent(),
                            HomeActivity.REQUEST_AUTHORIZATION);
                } else {
                    mOutputText.setText("The following error occurred:\n"
                            + mLastError.getMessage());
                }
            } else {
                mOutputText.setText("Request cancelled.");
            }
        }
    }


}

I got the exact same problem, in my case the loop was due to the fact that I did not create my credentials for my app... 我遇到了完全相同的问题,在我的情况下,循环是由于我没有为我的应用程序创建凭据而导致的。

The details are described here: https://developers.google.com/drive/android/get-started 有关详细信息,请参见以下网址https : //developers.google.com/drive/android/get-started

You must retrieve your SHA-1 keys for both the debug and production environments and add them in your credentials in the Google Developers Console as described in the guide. 您必须针对调试和生产环境都检索SHA-1密钥,然后按照指南中的说明将其添加到Google Developers Console的凭据中。

Once I added these credentials, the loop stopped right away. 添加这些凭据后,循环立即停止。

One thing I can think of is that the value of setSelectedAccountName will default in to null if no PREF_ACCOUNT_NAME was retrieved, so this may contribute to the issue. 我能想到的一件事是,如果未检索到PREF_ACCOUNT_NAMEsetSelectedAccountName的值将默认为null ,因此这可能会导致问题。

The only difference I can see that you did was how you instantiated the mCredential . 我可以看到的唯一区别是实例化了mCredential Try to check out the Authorizing requests for Android (using GoogleApiClient instead of GoogleAccountCredential . 尝试检查Android的授权请求 (使用GoogleApiClient而不是GoogleAccountCredential

You must be using the official Google Drive Api Quickstart by Google. 您必须使用Google的官方Google Drive Api快速入门。 Link . 链接 I can confirm that it doesn't work unfortunately as of now. 我可以确认到目前为止,它仍然无法正常工作。 It leads to an infinite login loop even if I have only one gmail account on my device. 即使我的设备上只有一个gmail帐户,也会导致无限登录循环。 Maybe consider using the code at their Drive Api page as a starting point. 也许考虑以其Drive Api页面上的代码为起点。 That should work 那应该工作

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 选择Google云端硬盘API的帐户屏幕会不断重复。 在这里尝试了所有其他解决方案 - Choose Account Screen for Google Drive API keeps repeating. Tried every other solution on here Google云端硬盘Api的帐户授权 - Account Authorization for Google Drive Api Google云端硬盘API / SDK,使用服务帐户更改所有者失败 - Google Drive API / SDK, change owner using service account fails 使用Google API从Android应用程序取消驱动器帐户的链接 - Unlink drive account from android app using google api 如何使用Android API和特定帐户连接到Google云端硬盘? - How to connect to Google Drive using the Android API and a specific account? Google 登录“选择一个帐户以继续”循环 - Google sign in "Choose an account to continue" loop 如何从Google帐户登出并使用Google Drive Android Api再次显示帐户选择器 - how to sign out from Google Account and show account chooser again using Google Drive Android Api 在Android中无法通过Google云端硬盘“选择帐户”屏幕 - Can't get passed Google Drive “Choose Account” screen in Android 谷歌驱动器选择帐户对话框没有在背面被解雇 - Google drive choose account dialog not dismissed on back press 访问特定帐户的Google Drive API - Accesing google drive API for a specific account
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM