miércoles, 25 de junio de 2014

Integrando Google Drive en android

Cualquier dueño de un dispositivo Android con acceso a Google Play tiene forzosamente una cuenta de google activa. Toda cuenta de google activa tiene acceso a los servicios de Google Drive: almacenamiento, documentos, etc. Es por ello que me pareció particularmente interesante acceder desde una app a dichos recursos. Debido a la variedad de servicios que ofrece, haré de esto una serie de artículos. Investigué esta página (gracias @spcoder, porque yo había encontrado tropocientas diferentes pero no ésta) y di con un howto para crear una app sencillita con la que tomar fotos y guardarlas en el espacio de almacenamiento de Google Drive. Tras sufrir y corregir los errores que me encontré, pensé que sería una buena idea compilarlo todo en un post. Sin embargo, y para no arrollar con demasiadas cosas a la vez, dedicaremos este artículo principalmente a la preparación necesaria para que tu app pueda acceder a los servicios de Google Drive.

1. Preparar el entorno

Estos preparativos afectan al IDE (Eclipse, en nuestro caso) y a nuestro espacio de trabajo o Workspace.

Preparativos en Eclipse.

Necesitaremos que Eclipse disponga de lo siguiente:
  • El google plugin for eclipse.
  • La librería google_play_services
El plugin ‘google plugin for eclipse’ se puede instalar siguiendo las instrucciones de esta página. Este plugin sirve, principalmente, para facilitar la tarea de añadir las librerías cliente necesarias a nuestro proyecto con un par de clicks. Ya hemos visto en otra ocasión cómo instalar un plugin en Eclipse desde el propio Eclipse (el plugin ADT fue en ese caso), así que lo único que tenemos que hacer en la página de google es buscar nuestra versión de eclipse y tomar la url que debemos emplear, esperar a que cargue la lista y elegir el google plugin for eclipse. Una vez listo, instalamos (saldrá el aviso de “software no firmado” que tendremos que confirmar, estos de google…) y reiniciamos eclipse. Al volver a arrancar deberíamos tener un icono redondo azul con la g de google en nuestra barra de herramientas. A mí me salió a la izquierda del SDK Manager.
Y hablando del SDK Manager, tenemos que usarlo ahora. En la ventana que se abre, iremos al fondo hasta que veamos “extras” en el lado izquierdo. Ahí dentro tenemos que buscar Google Play Services e instalarlo.

Preparativos en el workspace

Cuando Google Play Services esté instalado, tocará importar el proyecto librería (la página de google decía que bastaba con el jar, pero no es cierto, en el próximo post os cuento), lo cual haremos con File > New > Import > Existing Android Code into Workspace > navegamos a dónde tengamos nuestra carpeta con el SDK (si no lo recordamos, en Window > Preferences > Android tenemos la SDK Location que es dónde tenemos que ir) buscar dentro de extras/google/google_play_services/libproject y aceptar. Se importará el proyecto, el cual está marcado como is Library, que tendremos que emplear en nuestras aplicaciones que quieran acceder a estos servicios.

Anotar la Huellas del Certificado de Firmas

Por último, tenemos que encontrar y anotar las Huellas del Certificado de Firmas, que necesitaremos para acceder a las API de Google. Para ello haremos lo siguiente en sistemas Linix (es el sistema que manejo, pero seguramente habrá un equivalente para otros sistemas a un vistazo en Google =3):
En un Terminal ejecutaremos el siguiente comando keytool:
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v
La keystore o almacén de claves de android está normalmente en /home/usuario/.android/debug-keystore. Esto nos dará una lista de Huellas que tiene la firma que el sistema da automáticamente a todas nuestras aplicaciones, la firma de debug. Cuando queramos publicar la app, tendremos que firmarla con una firma privada, pero eso es otro tema.
En lo que nos devuelve ese comando tenemos que buscar la línea que comienza por “SHA-1″ y dejarla apuntada, ya que la necesitaremos mas adelante.

2. Preparar el proyecto

Los siguientes preparativos se refieren al proyecto o aplicación que tengamos entre manos y ha de repetirse para cada aplicación en la que queramos integrar los servicios de Google Drive.

Obtener el permiso para que nuestra app pueda acceder a los servicios de la API de Google Drive.

Crear el API Project en la consola de APIs de google. Le daremos el nombre de la app a la que queramos que Google de paso cuando usemos las llamadas de sus APIs. Una vez creado, seguimos los siguientes pasos dentro de la misma consola:
  1. En el desplegable, elegimos Services. Saldrá un listado con las API de Google a las que querremos que tenga acceso nuestra app, así que buscaremos Drive API y la activaremos.
  2. En el desplegable, elegimos API Access. Accedemos a Create an OAuth 2.0 client ID y lo cumplimentamos con la siguiente información:
    • En Branding Information ponemos el nombre de nuestra aplicación. El resto de campos son opcionales, por lo que pulsaremos Next.
    • En Client ID Settings:
      • En Application type: Installed application
      • En Installed Application Type: Android
      • En Package Name: el package name de nuestro proyecto (ejemplo: com.alberovalley.gdrivetutorial)
      • En Signing Certificate fingerprint: la cadena de texto que copiamos de nuestra clave de debug (sin el SHA-1).
      • Clickamos en Create Client ID.

Librerías y dependencias del proyecto

Usando el plugin de google para Eclipse, elegimos del desplegable Add Google APIs. En la nueva ventana, buscaremos Drive API v2. Con esto habremos añadido la librería cliente de Google Drive.
En el proyecto Properties > Android añadimos el proyecto librería google_play_services que dejamos preparado en el punto 1. El quickstart de Google sólo habla de añadir el jar que viene ahí, pero si se hace como dice, al ejecutar la app te dará un NoClassDefFoundError porque necesita el código y los recursos que están definidos en el proyecto, no sólo el jar.

3. Empezar a programar


Cuando hemos llegado a este punto, ya sólo queda empezar a programar nuestra app. haremos una app muy sencilla (una única Activity y sin usar siquiera su layout) que nos pedirá que nos loguemos con nuestra cuenta de Google, nos permitirá tomar fotografías y las subirá a nuestro Google Drive, tal como dije en la introducción.

Vamos ahora con la app de subir fotos. Proviene de un quickstar de google developers y, como ellos mismos dicen, se trata de una aplicación rápida y sencilla para que vayamos aprendiendo cómo se hace, por lo que puede no estar todo lo bien hecha que cabría, pero funciona y hace lo que debe.

Partimos de la base que todos los preparativos nombrados en el primer artículo de esta serie han sido tomados correctamente. Una vez todo ello listo, vamos al turrón.

Permisos

En el Manifest tenemos que añadir los permisos convenientes para poder acceder a los servicios de Google Drive. Estos son
  • INTERNET, obviamente, para tener acceso a los servidores de Google.
  • GET_ACCOUNTS, que es el que nos permite trastear con las cuentas ID (Google, Twitter, Facebook, etc).
El código a añadir al xml (por si os da pereza meteros en el desplegable interminable de la interfaz en Eclipse) es el siguiente


El código

Sólo necesitaremos una clase, la MainActivity (o el nombre que le hayamos dado) que genera Eclipse cuando creamos el proyecto Android. Ni siquiera usaremos el layout, ya que todo se hará a través de Intents del sistema (el de gestión de cuentas, el de la cámara…).
El código de la actividad es este. Procederemos a despiezarlo para intentar entenderlo.
1
2
3
4
5
6
7
@Override
 public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   credential = GoogleAccountCredential.usingOAuth2(this, DriveScopes.DRIVE);
   startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);
 }
El familiar método onCreate. Aquí ya se empiezan a usar las clases de Google, Credential en este caso. Se inicializa la misma y se arranca la Actividad del gestor de cuentas ForResult, vaya, devolviéndonos información que recibiremos en el onActivityResult.
Veamos ahora los casos del onActivityResult
1
2
3
4
5
6
7
8
9
10
case REQUEST_ACCOUNT_PICKER:
     if (resultCode == RESULT_OK && data != null && data.getExtras() != null) {
       String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
       if (accountName != null) {
         credential.setSelectedAccountName(accountName);
         service = getDriveService(credential);
         startCameraIntent();
       }
     }
     break;
Por aquí pasa cuando, la primera vez que se ejecuta, sale el gestor de cuentas y nosotros le hemos dicho que sí, que hacemos login con la cuenta X de la lista que tenemos. Actualiza el campo SelectedAccountName de credential con el valor adecuado que devolvió el gestor de cuentas, inicializa el servicio Drive con los credenciales ahora cumplimentados y arranca el Intent de la cámara.
1
2
3
4
5
6
7
case REQUEST_AUTHORIZATION:
      if (resultCode == Activity.RESULT_OK) {
        saveFileToDrive();
      } else {
        startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);
      }
      break
Por aquí pasa tras hacer la primera foto, cuando tiene que pedir permiso la app para gestionar (en este caso, guardar las fotos allí) el Google Drive del usuario. Si se obtienen, guarda la foto; si no, a pedirlo tocan.
1
2
3
4
case CAPTURE_IMAGE:
      if (resultCode == Activity.RESULT_OK) {
        saveFileToDrive();
      }
Y por aquí cuando ha hecho una foto y hemos pulsado en guardarla. Llama al método con el que guardamos la foto en Google Drive y listos.
1
2
3
4
5
6
7
8
9
10
11
private void startCameraIntent() {
    String mediaStorageDir = Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES).getPath();
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
    fileUri = Uri.fromFile(new java.io.File(mediaStorageDir + java.io.File.separator + "IMG_"
        + timeStamp + ".jpg"));
    Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
    startActivityForResult(cameraIntent, CAPTURE_IMAGE);
  }
Con este método llama al Intent de la cámara. Así se ahorra tener que escribir una actividad que lleve el tema de las cámaras y, además, tener que pedir permiso CAMERA en el Manifest. Muestra algo de lo que comenté de ser una app “no todo lo bien hecha que cabría”: El Locale para el formato de tiempo lo pone a pelo de Estados Unidos, en vez de usar el default para que tome el que tenga configurado el móvil. Habrá mas cosas “no del todo bien hechas” en toda la app, pero esta es una bastante llamativa.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private void saveFileToDrive() {
    Thread t = new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          // File's binary content
          java.io.File fileContent = new java.io.File(fileUri.getPath());
          FileContent mediaContent = new FileContent("image/jpeg", fileContent);
          // File's metadata.
          File body = new File();
          body.setTitle(fileContent.getName());
          body.setMimeType("image/jpeg");
          File file = service.files().insert(body, mediaContent).execute();
          if (file != null) {
            showToast("Photo uploaded: " + file.getTitle());
            startCameraIntent();
          }
        } catch (UserRecoverableAuthIOException e) {
          startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    });
    t.start();
  }


Y con esto, por último, guarda la foto en Google Drive. Si no estuviera autorizada la app para ello (como ocurre en el caso de la primera foto) se producirá la excepción UserRecoverableAuthIOException y solicitará permisos lanzando el Intent adecuado. Y esto es todo. Con tan solo los permisos y esta actividad ya se puede probar la app en el móvil o tablet. La pantalla del gestor de cuentas y la de petición de permiso sólo aparecerán en la primera ejecución y el primer guardado de foto (salvo que se diga “no” al permiso, claro). A partir de ahí sólo tomará fotos, las subirá y volverá a sacar la actividad de la cámara. Tomad un par de fotos de ejemplo y luego mirad en vuestro Google Drive, en Recientes, para ver que se han subido correctamente. Y ya está. Como siempre, tenéis disponible el código de este tutorial en el repositorio de github.

Fuente: http://alberovalley.wordpress.com/2013/01/21/integrando-google-drive-en-nuestras-apps-ii-primera-app-integrada-con-drive/

No hay comentarios:

Publicar un comentario