La aplicación se registró en la "Consola de API de Google" como una "aplicación instalada": parece que esta es la configuración correcta para una aplicación de Android, ¿no?¿Cómo configuró las Credenciales de Google Drive dentro de la aplicación de Android?
Por lo tanto, tengo una Id. De cliente y ninguna ID secreta. 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, obtengo la cuenta (funciona) y solicito un token (funciona). Ahora quiero conectarme a Google Drive con ese token y el Id. Del cliente. El resultado es una "401, credencial no válida". ¿Qué pasa con 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 un montón de desorden. Hay tantas páginas en la web que muestran solo partes y hay tantas páginas que usan métodos obsoletos, faltantes 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: Pude resolverlo yo solo. Fue una combinación de diferentes cambios:
- tuvo que establecer androide: minSdkVersion = "11" como requisito
- tenido que utilizar esta bibliotecas actuales: google-api-cliente-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, guayaba-11.0.1.jar, Jackson-core-2.0.5.jar, jsr305-1.3.9.jar
Este es el curren t parte para obtener el objeto de accionamiento:
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) {
}
lo sentimos, no funcionó tampoco. Mismo error: 401, credencial no válida. La sección de la clave de API simple menciona "... cuando no es necesario acceder a los datos del usuario ...", pero esto es cierto para mi aplicación de Android. No lo entiendo ¿No hay nadie que haya creado correctamente una aplicación de Android que se conecte a datos de Google Drive en nombre de un usuario que dio permiso para hacerlo a través de AccountManager y Google Credentials? –
Bueno, la única diferencia entre su código y el [Ejemplo de la API de tareas] (https://code.google.com/p/google-api-java-client/source/browse/tasks-android-sample/src/main/ java/com/google/api/services/samples/tasks/android/TasksSample.java? repo = samples) Veo entonces, es que están llamando 'credential.setAccessToken (authToken)' * después de * compilar 'Tasks' ejemplo. Entonces, ¿tal vez el intercambio de esas 2 líneas sea el truco? –
Sin suerte. Parece que hay algo roto. Gracias de cualquier manera. –