web-dev-qa-db-fra.com

Android Ouvrir et enregistrer des fichiers vers / depuis le SDK Google Drive

J'ai passé les six dernières heures à fouiller dans les documents de Google et je ne sais toujours pas comment s'y prendre. Tout ce que je veux, c'est que mon application Android existante puisse lire les fichiers de Google Drive, télécharger de nouveaux fichiers sur Google Drive et modifier les fichiers existants sur Google Drive.

J'ai lu que Drive SDK v2 était uniquement destiné à faciliter son utilisation par les développeurs de Android (et de mobiles en général). Pourtant, leur documentation ne contient pratiquement rien.

Idéalement, j'aimerais que quelqu'un pointe vers une documentation décente, un exemple ou un tutoriel expliquant comment faire cela (n'oubliez pas que j'utilise Android. Ils ont plein de choses sur l'utilisation de Drive avec Google App Engine; je l'ai déjà regardé et je ne sais pas comment passer de cela à une application Android.)

J'ai besoin de savoir quelles bibliothèques je dois télécharger et ajouter à mon projet, ce que je dois ajouter à mon manifeste, et comment je peux finalement obtenir une liste de fichiers de Google Drive, en télécharger un, puis télécharger une version modifiée.

Idéalement, j'aimerais que les comptes soient gérés automatiquement, comme l'application officielle de Google Drive.

57
ArtOfWarfare

Selon Claudio Cherubino, les services Google Play sont désormais disponibles et faciliteront grandement ce processus. Cependant, il n'y a pas d'exemple de code disponible (pour l'instant, il dit que cela va bientôt arriver ... ils ont dit que les services Google Play étaient "bientôt disponibles" il y a 4 mois. Il y a donc de bonnes chances que cette réponse continue à être le seul exemple totalement fonctionnel d'accès Google Drive à partir de votre Android jusqu'en 2013.)

Edit 2X: On dirait que j'ai été absent environ un mois lorsque j'ai dit que Google n'aurait pas d'exemple en cours avant l'année prochaine. Le guide officiel de Google est ici:

https://developers.google.com/drive/quickstart-Android

Je n'ai pas encore testé leurs méthodes, il est donc possible que mes solutions de septembre 2012 (ci-dessous) restent les meilleures:

Les services Google Play ne sont pas nécessaires pour cela. C’est pénible, et j’ai passé plus de 50 heures (plus de 100 heures) à tout comprendre, mais voici beaucoup de choses qu’il sera bon de savoir:

LES BIBLIOTHÈQUES

Pour les services en ligne de Google en général, vous aurez besoin de ces bibliothèques dans votre projet: ( Instructions et lien de téléchargement )

  • google-api-client-1.11.0-beta.jar
  • google-api-client-Android-1.11.0-beta.jar
  • google-http-client-1.11.0-beta.jar
  • google-http-client-Android-1.11.0-beta.jar
  • google-http-client-jackson-1.11.0-beta.jar
  • google-oauth-client-1.11.0-beta.jar
  • guava-11.0.1.jar
  • jackson-core-asl-1.9.9.jar
  • jsr305-1.3.9.jar

Pour Google Drive en particulier, vous aurez également besoin de ceci:

CONFIGURATION DE LA CONSOLE

Ensuite, allez à Google Console . Faire un nouveau projet. Sous Services, vous devez activer deux choses: DRIVE API et DRIVE SDK ! Ils sont séparés, l’un n’allume pas automatiquement l’autre, et VOUS DEVEZ ACTIVER LES DEUX! (Trouver cette perte au moins 20 heures de mon temps seul.)

Toujours sur la console, accédez à API Access. Créez un client, faites-en un Android app. Donnez-lui votre identifiant de bundle. Je ne pense pas que le problème des empreintes digitales soit réellement important, car je suis à peu près sûr d'avoir utilisé le mauvais, mais essayez quand même de le faire correctement (Google fournit des instructions à ce sujet.)

Il va générer un ID client . Vous allez avoir besoin de ça. Tiens-toi dessus.

Edit: On m'a dit que je me trompais et qu'il suffisait d'activer l'API de lecteur, que le SDK de lecteur n'avait pas besoin d'être activé et que vous deviez simplement utiliser la clé API simple, non définie. quelque chose pour Android. Je suis en train de regarder cela et je vais probablement éditer cette réponse dans quelques minutes si je le découvre ...

THE Android CODE - Configuration et téléchargement

Commencez par obtenir un jeton d'authentification:

AccountManager am = AccountManager.get(activity);
am.getAuthToken(am.getAccounts())[0],
    "oauth2:" + DriveScopes.DRIVE,
    new Bundle(),
    true,
    new OnTokenAcquired(),
    null);

Ensuite, OnTokenAcquired () doit être configuré comme ceci:

private class OnTokenAcquired implements AccountManagerCallback<Bundle> {
    @Override
    public void run(AccountManagerFuture<Bundle> result) {
        try {
            final String token = result.getResult().getString(AccountManager.KEY_AUTHTOKEN);
            HttpTransport httpTransport = new NetHttpTransport();
            JacksonFactory jsonFactory = new JacksonFactory();
            Drive.Builder b = new Drive.Builder(httpTransport, jsonFactory, null);
            b.setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() {
                @Override
                public void initialize(JSonHttpRequest request) throws IOException {
                    DriveRequest driveRequest = (DriveRequest) request;
                    driveRequest.setPrettyPrint(true);
                    driveRequest.setKey(CLIENT ID YOU GOT WHEN SETTING UP THE CONSOLE BEFORE YOU STARTED CODING)
                    driveRequest.setOauthToken(token);
                }
            });

            final Drive drive = b.build();

            final com.google.api.services.drive.model.File body = new com.google.api.services.drive.model.File();
            body.setTitle("My Test File");
    body.setDescription("A Test File");
    body.setMimeType("text/plain");

            final FileContent mediaContent = new FileContent("text/plain", an ordinary Java.io.File you'd like to upload. Make it using a FileWriter or something, that's really outside the scope of this answer.)
            new Thread(new Runnable() {
                public void run() {
                    try {
                        com.google.api.services.drive.model.File file = drive.files().insert(body, mediaContent).execute();
                        alreadyTriedAgain = false; // Global boolean to make sure you don't repeatedly try too many times when the server is down or your code is faulty... they'll block requests until the next day if you make 10 bad requests, I found.
                    } catch (IOException e) {
                        if (!alreadyTriedAgain) {
                            alreadyTriedAgain = true;
                            AccountManager am = AccountManager.get(activity);
                            am.invalidateAuthToken(am.getAccounts()[0].type, null); // Requires the permissions MANAGE_ACCOUNTS & USE_CREDENTIALS in the Manifest
                            am.getAuthToken (same as before...)
                        } else {
                            // Give up. Crash or log an error or whatever you want.
                        }
                    }
                }
            }).start();
            Intent launch = (Intent)result.getResult().get(AccountManager.KEY_INTENT);
            if (launch != null) {
                startActivityForResult(launch, 3025);
                return; // Not sure why... I wrote it here for some reason. Might not actually be necessary.
            }
        } catch (OperationCanceledException e) {
            // Handle it...
        } catch (AuthenticatorException e) {
            // Handle it...
        } catch (IOException e) {
            // Handle it...
        }
    }
}

THE Android CODE - Téléchargement

private Java.io.File downloadGFileToJFolder(Drive drive, String token, File gFile, Java.io.File jFolder) throws IOException {
    if (gFile.getDownloadUrl() != null && gFile.getDownloadUrl().length() > 0 ) {
        if (jFolder == null) {
            jFolder = Environment.getExternalStorageDirectory();
            jFolder.mkdirs();
        }
        try {

            HttpClient client = new DefaultHttpClient();
            HttpGet get = new HttpGet(gFile.getDownloadUrl());
            get.setHeader("Authorization", "Bearer " + token);
            HttpResponse response = client.execute(get);

            InputStream inputStream = response.getEntity().getContent();
            jFolder.mkdirs();
            Java.io.File jFile = new Java.io.File(jFolder.getAbsolutePath() + "/" + getGFileName(gFile)); // getGFileName() is my own method... it just grabs originalFilename if it exists or title if it doesn't.
            FileOutputStream fileStream = new FileOutputStream(jFile);
            byte buffer[] = new byte[1024];
            int length;
            while ((length=inputStream.read(buffer))>0) {
                fileStream.write(buffer, 0, length);
            }
            fileStream.close();
            inputStream.close();
            return jFile;
        } catch (IOException e) {        
            // Handle IOExceptions here...
            return null;
        }
    } else {
        // Handle the case where the file on Google Drive has no length here.
        return null;
    }
}

Une dernière chose ... si cette intention est renvoyée, vous devrez vous en occuper quand elle retournera avec un résultat.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == 3025) {
        switch (resultCode) {
            case RESULT_OK:
                AccountManager am = AccountManager.get(activity);
                am.getAuthToken(Same as the other two times... it should work this time though, because now the user is actually logged in.)
                break;
            case RESULT_CANCELED:
                // This probably means the user refused to log in. Explain to them why they need to log in.
                break;
            default:
                // This isn't expected... maybe just log whatever code was returned.
                break;
        }
    } else {
        // Your application has other intents that it fires off besides the one for Drive's log in if it ever reaches this spot. Handle it here however you'd like.
    }
}

THE Android CODE - Mise à jour

Deux notes rapides sur la mise à jour de la dernière date de modification d'un fichier sur Google Drive:

  1. Vous devez fournir un DateTime entièrement initialisé. Si vous ne le faites pas, vous recevrez une réponse "Demande incorrecte" de Google Drive.
  2. Vous devez utiliser setModifiedDate () sur le fichier de Google Drive et setSetModifiedDate (true) sur la demande de mise à jour elle-même. (Nom amusant, hein? "SetSet [...]", il n'y a aucun moyen que les gens puissent mal écrire celui-là ...)

Voici un bref exemple de code montrant comment effectuer une mise à jour, y compris la mise à jour de l'heure du fichier:

public void updateGFileFromJFile(Drive drive, File gFile, Java.io.File jFile) throws IOException {
    FileContent gContent = new FileContent("text/csv", jFile);
    gFile.setModifiedDate(new DateTime(false, jFile.lastModified(), 0));
    gFile = drive.files().update(gFile.getId(), gFile, gContent).setSetModifiedDate(true).execute();
}

LA MANIFESTE

Vous aurez besoin des autorisations suivantes: GET_ACCOUNTS, USE_CREDENTIALS, MANAGE_ACCOUNTS, INTERNET et il est fort probable que vous ayez également besoin de WRITE_EXTERNAL_STORAGE, en fonction de l'emplacement où vous souhaitez stocker les copies locales de vos fichiers.

VOTRE CIBLE DE CONSTRUCTION

Cliquez avec le bouton droit de la souris sur votre projet, accédez à ses propriétés, puis sous Android, si vous le souhaitez, modifiez la cible de génération en API Google. Si ce n’est pas le cas, téléchargez-les à partir de Android gestionnaire de téléchargement.

Si vous effectuez des tests sur un émulateur, assurez-vous que sa cible est Google API, et non pas Android générique.

Vous aurez besoin d'un compte Google configuré sur votre appareil de test. Le code tel qu'il est écrit utilisera automatiquement le premier compte Google trouvé (c'est ce que le [0] est.) Si vous devez avoir téléchargé l'application Google Drive pour que cela fonctionne. J'utilisais l'API niveau 15, je ne sais pas jusqu'où ce code fonctionnera.

LE REPOS

Ce qui précède devrait vous aider à démarrer et j'espère que vous pourrez vous en sortir ... honnêtement, c'est à peu près tout ce que j'ai eu jusqu'à présent. J'espère que cela aide beaucoup de gens et leur fait gagner beaucoup de temps. Je suis presque certain que je viens d'écrire le guide de configuration le plus complet pour configurer une Android permettant d'utiliser Google Drive. Honte à Google de diffuser le matériel nécessaire sur au moins six pages différentes. qui ne sont pas liés du tout.

78
ArtOfWarfare

C'est 2015, les choses ont changé!

Obtenez le 'Drive API for Android' avec gradle:

compile 'com.google.Android.gms:play-services-drive:7.8.0'

Il y a un nouveau doco (bien que toujours IMO terne):

https://developers.google.com/drive/web/quickstart/Android

Et pour ceux qui sont sur le point de faire de la spéléologie ... le problème le plus important que j’ai rencontré jusqu’à présent est qu’il n’ya absolument aucun moyen de distinguer les dossiers supprimés de façon permanente des dossiers normaux ... vous pouvez les trouver, vous pouvez créer des dossiers et fichiers qu’ils contiennent, seule l’écriture dans le fichier DriveContents échouera toujours.

4
straya

Consultez cette vidéo de Google I/O pour savoir comment intégrer votre Android avec Drive:

http://www.youtube.com/watch?v=xRGyzqD-vRg

Sachez que ce que vous voyez dans la vidéo est basé sur les services Google Play., qui n'a pas encore lancé au grand public:

https://developers.google.com/Android/google-play-services/

4
Claudio Cherubino

Jetez un coup d'œil à Google Exemple DrEdit , qui contient un dossier nommé Android/. Copiez-le, suivez le readme, et cela devrait fonctionner (fonctionne pour moi sur un émulateur Android avec KitKat).

.

P.S.

Désolé de le réactiver, mais la nouvelle Google Drive Android API ne prend pas en charge l'accès complet à Drive, mais uniquement drive.file et drive.appdataétendues d’autorisation , si vous avez besoin d’un accès complet, vous devez revenir au bon 'ol Le client pour Java de l'API Google (que l'exemple de DrEdit utilise ).

2
woojoo666