Google Drive Android API Developer Preview

Di - 7 February 2014 - in
Post image for Google Drive Android API Developer Preview

Abbiamo parlato delle novità introdotte dalla versione 4.1 dei Google Play Services e di come sia eccitato dall’introduzione di Google Drive fra le API accessibili dai Google Play Services. Ora avendo avuto tempo di giocarci un po’, posso riportarvi in dettaglio cosa cambia.

Activity Builder per Aprire e Salvare file

Se vogliamo permettere all’utente di selezionare dove salvare un file generato con la nostra applicazione, abbiamo ora la possibilità di utilizzare un activity con la stessa UX dell’applicazione ufficiale di Google Drive.

Precedentemente dovevamo gestire manualmente il caricamento della lista dei folder e mostrarli all’utente, con risultati che dipendevano dalla capacità grafica dello sviluppatore; ora, con poco più di una decina di righe di codice, riusciamo a fare tutto.

Selezione della cartella in NoteToGDocs

UI di selezione della cartella di destinazione di NoteToGDocs

Nuova interfaccia di selezione cartella

La nuova interfaccia di selezione Cartella

Di seguito tutto il codice necessario per aprire l’activity di selezione di un folder:

IntentSender is = Drive.DriveApi.newOpenFileActivityBuilder()
                    .setActivityTitle("Select a Folder")
                    //.setActivityStartFolder(DriveId.createFromResourceId("0B0CnV_gvF2TgMTJhcFFZX3NtZGc"))//TODO: set the folder from the properties, for now it's fixed for debug
                    .setMimeType(new String[]{"application/vnd.google-apps.folder"})
                    .build(mGoogleApiClient);
            try{
                startIntentSenderForResult(is, REQUEST_CODE_OPENER, null, 0, 0, 0);
            }catch (Exception ex){

            }

Nell’activity dobbiamo solo ricordarci di creare l’oggetto che gestisce l’autenticazione e la funzione onActivity result per ottenere il folder selezionato dall’utente:

protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
        switch (requestCode) {

            case REQUEST_CODE_OPENER:
                if (resultCode == RESULT_OK){
                    DriveId saveToFolder= (DriveId) data.getParcelableExtra(
                            OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);
                    Log.i(TAG,saveToFolder.getResourceId());

                }
                break;
            ...
        }
    }

Per permettere ad un’utente di specificare nome e cartella dove creare il file il codice non differisce molto:

IntentSender intentSender = Drive.DriveApi
             .newCreateFileActivityBuilder()
             .setInitialMetadata(metadataChangeSet)
             .setInitialContents(result.getContents())
             .build(getGoogleApiClient());
    try {
        startIntentSenderForResult(
                intentSender, REQUEST_CODE_CREATOR, null, 0, 0, 0);
    } catch (SendIntentException e) {
        Log.w(TAG, "Unable to send intent", e);
    }

Ed otterremo un activity di selezione come la seguente (che ben conosciamo se facciamo “Invia A… Google Drive” per salvare i file dal nostro device Android).

Activity di selezione

Activity di selezione

Autenticazione Semplificata

L’ autenticazione, o meglio autorizzazione ad utilizzare Google Drive, è stata semplificata.

Con la versione Java della Google Drive API Client Library era necessario accedere alle informazioni di account dell’utente e salvarsi parte di queste informazioni per i successivi accessi; l’operazione non era molto complessa, ma molti utenti non si capacitavano del fatto che un’applicazione per salvare dei file avesse bisogno di accedere alle informazioni del proprio account.

Attraverso l’oggetto GoogleApiClient possiamo richiedere all’utente di autorizzare la nostra applicazione ad accedere ai suoi dati di Google Drive senza nessun permesso aggiuntivo.

Il seguente codice è tutto quello che necessitiamo di scrivere in onCreate per far autorizzare la nostra applicazione dall’utente:

        //Authorize the Application
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(Drive.API)
                .addScope(Drive.SCOPE_FILE)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();

Ricordiamci di effettuare il .connect durante onStart e la nostra applicazione sarà autorizzata.

Il cambiamento di gestione dell’autorizzazione porta però a dover fare delle diverse considerazioni durante l’aggiornamento di un’applicazione: per accedere alle informazioni dell’utente non abbiamo più un oggetto strutturato (Credential) ma dobbiamo utilizzare le informazioni “Extra” che riceviamo quando l’utente ci autorizza (maggiori informazioni in questa risposta su StackOverflow)
Al momento l’unico scope supportato è SCOPE_FILE che permette di accedere alle sole cartelle e file creati dall’applicazione.

Modifica Oggetti File e Folder

Sono sicuro che ci siano delle motivazioni relative alla gestione della funzionalità Offline, ma le classi DriveFile e DriveFolder sono cambiate totalmente rispetto alla Java API e la HTML API.

Nella Java API, una volta ottenuto il file, possiamo accedere a tutte le sue proprietà attraverso getter e setter; ad esempio per ottenere un file dal suo id e leggere il titolo/nome di un file mi bastava questo codice:

File file = service.files().get(fileId).execute();

String fileTitle=file .getTitle();

Ora il tutto si fà più complicato.

Prima di tutto, dall’Id (Es. “0B0CnV_gvF2TgMTJhcFFZX3NtZGc”) dobbiamo ottenere un oggetto di tipo DriveId:

DriveId fileIdObj = DriveId.createFromResourceId("0B0CnV_gvF2TgMTJhcFFZX3NtZGc");

Poi possiamo ottenere l’oggetto DriveFile, da cui successivamente ottenere Contents (il contenuto) o Metadata (il titolo e altri metadati del file):

DriveFile df =Drive.DriveApi.getFile(_apiClient,fileIdObj);

Visto che vogliamo stampare il titolo, otteniamo ora l’oggetto Metadata:

Metadata fileMeta = df.getMetadata(_apiClient).await().getMetadata();

String fileTitle = fileMeta.getTitle();

Con il doppio delle righe di codice abbiamo ottenuto lo stesso risultato.

Però c’è una cosa importante che non abbiamo tenuto in considerazione.

La Java API ha sostanzialmente tutte chiamate sincrone, per cui la mia applicazione deve attendere fino a che non ho ricevuto tutte le informazioni del file prima di poter procedere con la prossima operazione.

Un buon sviluppatore sa che è meglio rendere queste operazioni di I/O asincrone per non bloccare l’interfaccia utente ma, per svariati motivi, lo sviluppatore tenderà ad utilizzare le chiamate sincrone se queste sono quelle più semplici da scrivere.

Nell’esempio riportato sopra, con la Java API, la prima riga di codice già si collega alla rete e blocca l’esecuzione dell’applicazione (con .execute()); la Android API non esegue nessuna richiesta di I/O fino a che non eseguiamo .getMetadata().await(), dove await() specifica che l’esecuzione sia sincrona, ma normalmente avremmo usato .addResultCallBack(callBack) per specificare quale oggetto deve essere notificato che la richiesta di metatadi è stata completata.

Tirando le somme, l’Android API è stata leggermente complicata per indirizzare gli sviluppatori verso la creazione di applicazioni più fluide e asincrone, garantendo agli utenti una migliore esperienza.

Ricerca

La ricerca è cambiata anch’essa.

Nella Java API è stato effettuato un porting 1 a 1 delle proprietà di ricerca della HTML API, qundi per cercare un file per titolo in una cartella specifica.

Files.List request = service.files().list();
request.setQ("'FOLDER_ID' in parents and title = 'hello'");
FileList files = request.execute();

Con l’oggetto Query abbiamo diverse funzioni per aggiungere i filtri da applicare, rendendo più difficili le occorrenze di typo, ma complicando leggermente la sintassi.

Replichiamo la richiesta fatta precedentemente con la nuova API

Query qry = new Query.Builder()
                .addFilter(Filters.and(
                        Filters.eq(SearchableField.TITLE,"hello"),
                        Filters.in(SearchableField.PARENTS,DriveId.createFromResourceId("FOLDER_ID"))
                )).build();
        Drive.DriveApi.query(_apiClient,qry)
                .addResultCallback(new OnChildrenRetrievedCallback() {
                    @Override
                    public void onChildrenRetrieved(MetadataBufferResult metadataBufferResult) {
                        //Cicliamo sul buffer di risultati
                        for(Iterator i =
                                    metadataBufferResult.getMetadataBuffer().iterator();
                                    i.hasNext();){
                            Metadata curFile = i.next();
                        }
                    }
                });

Questa volta al posto di una chiamata sincrona ho associato la funzione di callback per gestire asincronamente le operazioni sul risultato della ricerca.

Utilizzo Offline

Nel precedente articolo abbiamo detto che la Android API permette l’accesso Offline ai file, cosa dobbiamo fare per utilizzare questo accesso Offline?

Niente, Nada, Nichts, Nothing.

La nuova API fa tutti i controlli per noi, ed è per questo che è consigliato vivamente di utilizzare l’approccio asincrono; ogni richiesta potrebbe essere istantanea (sta usando la  cache) o impiegarci alcuni secondi (reti mobile lente).

Lifecycle di un file Drive

Lifecycle di un file Drive

Ulteriori spiegazioni sul lifecyle dei file sono disponibili nella documentazione ufficiale.

Developer Preview

Tutte queste funzionalità e ottimizzazioni fanno saltare tutti di gioia, ma guardando in dettaglio nella documentazione ci si accorge che Developer preview non è stato messo per precauzione:

  • Vogliamo settare o leggere il metadato “descrizione” di un file? Non si può.
  • Vogliamo utilizzare la funzione i conversione dei documenti durante l’upload? Non si può.
  • Vogliamo ottenere un link da inviare via mail per la condivisione o il download? Non si può.
  • Vogliamo richiedere l’accesso in sola lettura a tutti i metadati dei file? Non si può.

Le funzionalità attualmente implementate nella API sono quelle strettamente necessarie al corretto funzionamento per effettuare il backup dei file e l’accesso ad un file binario come “dato puro” e non come parte di centrale di un set più ampio di informazioni (descrizione, custom properties sui file, commenti, etc…).

Sono sicuro che nelle prossime release verranno rilasciate anche le altre funzionalità più avanzate che fanno la differenza fra Google Drive e gli altri sistemi di Storage in Cloud, ma per il momento, se avete necessità di queste funzionalità avanzate, consiglio di utilizzare la Java API, oppure cercare un modo per implementare un approccio misto che usi la Android API il più possibile e la Java API per le funzionalità avanzate.

 

Leave a Reply

Articolo scritto da

Techy, sviluppatore .Net per professione, sviluppatore Android per passione. All Around Android Lover e Google Enthusiast

Contatta l'autore

Previous post:

Next post: