¿Cómo configurar las credenciales de Google Drive en la aplicación de Android?

La aplicación se registró en la "Consola de API de Google" como una "aplicación instalada" – parece que este es el ajuste correcto para una aplicación para Android, ¿no?

Así que tengo un Id de cliente y no secreto Id. Para dejarlo en claro: no es una aplicación web ni una aplicación de Google Drive: es una aplicación de Android que accede a los datos de otros usuarios en la nube de Google Drive.

Dentro de la aplicación busco la cuenta (works) y solicito un token (works). Ahora quiero conectarme a Google Drive con ese token y el Client-Id. El resultado es una "credencial 401 inválida". ¿Qué tiene de malo este código?

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

Tengo que decir que esto es una carga llena de lío. Hay tantas páginas en la web que muestra sólo partes y hay tantas páginas que utilizan métodos obsoletos, desaparecidos o diferentes para hacer lo mismo. En mi opinión, no hay dos páginas que muestren la misma forma de obtener datos de Google Drive desde una aplicación de Android.

Cualquier ayuda es muy apreciada.

EDIT: Podría resolverlo yo mismo. Fue una combinación de diferentes cambios:

  • Tenía que establecer android: minSdkVersion = "11" como requisito
  • Tuvieron que usar las bibliotecas actuales: 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

Esta es la parte actual para obtener el objeto Drive:

  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) { } 

Sí, la documentación es muy difícil de captar.

Solo cambia

 new GoogleKeyInitializer(CLIENT_ID) 

a

 new GoogleKeyInitializer(SIMPLE_API_ACCESS_KEY) 

Y debería funcionar.

Puede encontrar su SIMPLE_API_ACCESS_KEY en la Consola de API de Google en la sección Acceso a API Simple de la página de Acceso a API (la API key ). Si esta sección no está disponible, primero debe activar el acceso a la API de unidad en la página Servicios .

Hay 2 problemas con el fragmento incluido.

  1. Debe invalidar el antiguo authToken antes de buscar un nuevo authToken desde AccountManager.

     AccountManager.get(activity).invalidateAuthToken("com.google", authToken); accountManager.getAuthToken(...); 
  2. La llamada a setJsonHttpRequestInitializer debe utilizar la clave de API simple declarada en la consola de API para su proyecto.

    • Se puede obtener visitando la Consola de API .
    • Haga clic en Acceso API en el menú de la izquierda.
    • Busque el acceso simple a la API y copie la clave de la API .
    • Establezca la clave de API al crear el objeto Drive.

      .setJsonHttpRequestInitializer (nuevo GoogleKeyInitializer (KEY))

Hay una pequeña muestra que demuestra la invalidación del token aquí: http://chiarg.com/?p=429

He intentado todo esto y finalmente encontré este código para trabajar con la api de Google Calendar. Solía ​​obtener un 401 cada vez que utilicé GoogleCredentials y lo pasé a la compilación.

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

He dado una respuesta extensa sobre el uso de Google Drive en Android por aquí:

Abrir y guardar archivos de Android en / desde el SDK de Google Drive

Utilizando los métodos que establezco en esa respuesta, puedo confirmar que puede hacer lo siguiente:

  • Establecer y acceder a los metadatos
  • Subir archivos
  • Descargar archivos
  • Mover archivos entre directorios de Google Drive
  • Eliminar completamente los archivos de la unidad
  • "FirebaseError: Se proporcionan credenciales de autenticación no válidas" al configurar el inicio de sesión de Google en Android
  • Android: verifica el nombre de la cuenta google del dispositivo en el servidor
  • Google http / oauth2 api siempre lanza EOFException para segundo HTTPRequest
  • Añadir Retrofit Requestinterceptor con Dagger en tiempo de ejecución
  • Librería / marco apropiado de Oauth2 del androide
  • Oauth 2.0: identificación del cliente y secreto del cliente expuestos, ¿es un problema de seguridad?
  • C2DM con PHP usando OAuth2.0 (ClientLogin está obsoleto!)
  • SampleSyncAdapter que almacena la contraseña de texto sin formato?
  • Acceso a Linkedin para una aplicación de Cordova
  • No se redirecciona a la URL de devolución de llamada al autenticarse en Instagram
  • ¿Cómo obtener la huella digital del certificado de firma (SHA1) para OAuth 2.0 en Android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.