How setup Google Drive Credentials within Android

2019-02-06 17:07发布

The app was registered in the "Google API console" as an "installed application" - seems that this is the right setting for an Android app, no?

So I do have a Client-Id and no Secret-Id. To make it clear: It's no Web-app and no Google Drive-App - it's an Android App accessing other users data in the Google Drive cloud.

Within the app I fetch the account (works) and I do request a token (works). Now I want to connect to Google Drive with that token and the Client-Id. The result is a "401, invalid credential". What's wrong with this code?

public class ActivityMain extends Activity implements DialogInterface.OnClickListener {

    // https://developers.google.com/drive/scopes
    private static final String AUTH_TOKEN_TYPE = "oauth2:https://www.googleapis.com/auth/drive";

    // https://code.google.com/apis/console/
    private static final String CLIENT_ID = "999999999999999.apps.googleusercontent.com";

    private AccountManager accountManager;
    private Account[] accounts;
    private String authName;
    private String authToken;

    @Override
    public void onClick(final DialogInterface dialogInterface, final int item) {

        processAccountSelected(accounts[item]);
    }

    @Override
    public void onCreate(final Bundle bundle) {
        super.onCreate(bundle);

        setContentView(R.layout.activitymain);

        accountManager = AccountManager.get(this);
        accounts = accountManager.getAccountsByType("com.google");

        if (accounts == null || accounts.length == 0) {
            // TODO
        } else if (accounts.length == 1) {
            processAccountSelected(accounts[0]);
        } else if (accounts.length > 1) {
            showDialog(MyConstants.DIALOG_ACCOUNTCHOSER);
        }
    }

    @Override
    protected Dialog onCreateDialog(final int id) {
        switch (id) {
            case MyConstants.DIALOG_ACCOUNTCHOSER:
                AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);

                String[] names = new String[accounts.length];

                for (int i = 0; i < accounts.length; i++) {
                    names[i] = accounts[i].name;
                }

                alertDialogBuilder.setItems(names, this);
                alertDialogBuilder.setTitle("Select a Google account");
                return alertDialogBuilder.create();
        }

        return null;
    }

    private void processAccountSelected(final Account account) {
        if (account != null) {
            authName = account.name.toString();
            if (!Tools.isEmpty(authName)) {
                Toast.makeText(this, authName, Toast.LENGTH_LONG).show();

                accountManager.getAuthToken(account, AUTH_TOKEN_TYPE, null, this,
                        new AccountManagerCallback<Bundle>() {

                            public void run(final AccountManagerFuture<Bundle> future) {
                                try {
                                    authToken = future.getResult().getString(
                                            AccountManager.KEY_AUTHTOKEN);
                                    processTokenReceived();
                                } catch (OperationCanceledException exception) {
                                    // TODO
                                } catch (Exception exception) {
                                    Log.d(this.getClass().getName(), exception.getMessage());
                                }
                            }
                        }, null);
            }
        }
    }

    private void processListFiles(final Drive drive) {
        List<File> result = new ArrayList<File>();
        Files.List request = null;
        try {
            request = drive.files().list();
        } catch (IOException exception) {
        }

        do {
            try {
                FileList files = request.execute();

                result.addAll(files.getItems());
                request.setPageToken(files.getNextPageToken());
            } catch (IOException exception) {
                // --> 401 invalid credentials
            }
        } while (request.getPageToken() != null && request.getPageToken().length() > 0);
    }

    private void processTokenReceived() {
        if (!Tools.isEmpty(authToken)) {
            final HttpTransport transport = AndroidHttp.newCompatibleTransport();
            final JsonFactory jsonFactory = new GsonFactory();
            GoogleCredential credential = new GoogleCredential();
            credential.setAccessToken(authToken);
            Drive drive = new Drive.Builder(transport, jsonFactory, credential)
                    .setApplicationName(getString(R.string.txt_appname))
                    .setJsonHttpRequestInitializer(new GoogleKeyInitializer(CLIENT_ID))
                    .build();

            if (drive != null) {
                processListFiles(drive);
            }
        }
    }
}

I have to say that this is a full load of mess. There are so many pages in the web showing parts only and there are so many pages using deprecated, missing or different methods to do the same. There are, in my opinion, not two pages showing the same way to get data from Google Drive from within an Android app.

Any help is highly appreciated.

EDIT: I could solve it myself. It was a combination of different changes:

  • Had to set android:minSdkVersion="11" as a requirement
  • Had to use this current libraries: google-api-client-1.11.0-beta.jar, google-api-client-android-1.11.0-beta.jar, google-api-services-drive-v2-rev9-1.8.0-beta.jar, google-http-client-1.11.0-beta.jar, google-http-client-android-1.11.0-beta.jar, google-http-client-gson-1.11.0-beta.jar, google-http-client-jackson2-1.11.0-beta.jar, google-oauth-client-1.11.0-beta.jar, gson-2.1.jar, guava-11.0.1.jar, jackson-core-2.0.5.jar, jsr305-1.3.9.jar

This is the current part to get the Drive Object:

    GoogleCredential credential = new GoogleCredential();
    credential.setAccessToken(authToken);

    HttpTransport transport = AndroidHttp.newCompatibleTransport();

    JsonFactory jsonFactory = new AndroidJsonFactory();

    drive = new Drive.Builder(transport, jsonFactory, credential)
            .setApplicationName(getString(R.string.txt_appname))
            .setJsonHttpRequestInitializer(
                    new GoogleKeyInitializer(APIKEY_SIMPLE))
            .build();
    if (drive != null) {
    }

4条回答
对你真心纯属浪费
2楼-- · 2019-02-06 17:35

I tried all this and finally found this code to work with the google Calendar api. I used to get a 401 every time i used GoogleCredentials and passed it to the build.

HttpTransport transport = AndroidHttp.newCompatibleTransport();;
    JsonFactory jsonFactory = new GsonFactory();
    HttpRequestInitializer httpRequestInitializer;

    Log.i("Reached calendar builder", "Reached calendar builder"+accessToken);

    //GoogleCredential credential = new GoogleCredential();

     httpRequestInitializer = new HttpRequestInitializer(){
        public void initialize(HttpRequest request) throws IOException
        {
                request.getHeaders().setAuthorization(GoogleHeaders.getGoogleLoginValue(accessToken));
        }
    };

    Calendar service = new Calendar.Builder(transport, jsonFactory, httpRequestInitializer)
    .setApplicationName("Meetrbus/1.0")
    .setJsonHttpRequestInitializer(new GoogleKeyInitializer("API_KEY"))
    .build();


}
查看更多
狗以群分
3楼-- · 2019-02-06 17:40

There are 2 issues with the snippet you included.

  1. You must invalidate the old authToken before fetching a new authToken from the AccountManager.

    AccountManager.get(activity).invalidateAuthToken("com.google", authToken);
    accountManager.getAuthToken(...);
    
  2. The call to setJsonHttpRequestInitializer must use the Simple API Key declared in the APIs Console for your project.

    • It can be obtained by visiting the APIs Console.
    • Click API Access on the left menu.
    • Look for Simple API Access, and copy the API key.
    • Set the API key when building the Drive object.

      .setJsonHttpRequestInitializer(new GoogleKeyInitializer(KEY))

There is a small sample demonstrating the token invalidation here: http://chiarg.com/?p=429

查看更多
我想做一个坏孩纸
4楼-- · 2019-02-06 17:43

Yeah, the documentation is quite hard to catch on.

Just change

new GoogleKeyInitializer(CLIENT_ID)

to

new GoogleKeyInitializer(SIMPLE_API_ACCESS_KEY)

and it should work.

You can find your SIMPLE_API_ACCESS_KEY in Google's APIs Console under the Simple API Access section of the API Access page (the API key). If this section is not available, you have to first activate Drive API access on the Services page.

查看更多
Juvenile、少年°
5楼-- · 2019-02-06 17:55

I gave an extensive answer on using Google Drive on Android over here:

Android Open and Save files to/from Google Drive SDK

Using the methods I lay out in that answer, I can confirm that you're able to do the following:

  • Set and Access Meta-data
  • Upload Files
  • Download Files
  • Move files between Google Drive directories
  • Delete files off of the drive entirely
查看更多
登录 后发表回答