Android打开和保存往返于Google Drive SDK的文件

时间:2012-08-28 16:57:30

标签: android google-drive-api

我花了最后六个小时倾注来自谷歌的文件,我仍然不知道如何开始这个。我想做的就是让我现有的Android应用可以从Google云端硬盘读取文件,将新文件上传到Google云端硬盘,以及修改Google云端硬盘上的现有文件。

我已经读过Drive SDK v2专注于让Android(以及一般移动设备)开发人员轻松使用它,但是他们的文档中几乎没有关于它的内容。

理想情况下,我希望有人指出一些体面的文档,示例或教程,介绍如何执行此操作(请记住,我正在使用Android。他们有很多关于如何使用Google App驱动器的东西引擎;我已经看过了,我不知道如何从那个应用程序转到Android应用程序。)

我需要知道我需要下载哪些库并添加到我的项目中,我需要添加到我的清单中,以及如何最终从Google云端硬盘获取文件列表,下载一个,然后上传修改后的文件版本

理想情况下,我希望它能自动处理帐户,就像正式的Google云端硬盘应用程序所做的那样。

4 个答案:

答案 0 :(得分:78)

编辑:克劳迪奥·切鲁比诺说,Google Play服务现已推出,这将使这一过程变得更加容易。但是,没有可用的示例代码(但是,他说它即将推出......他们说Google Play服务是#34;很快就会出现#34; 4个月前,所以'很有可能这个答案将继续成为从Android应用程序访问Google Drive到2013年的唯一完整工作示例。)

编辑2X:看起来我已经离开了大约一个月,当时我说Google直到明年都没有工作实例。谷歌的官方指南就在这里:

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

我还没有测试过他们的方法,所以从2012年9月(下面)我的解决方案仍然是最好的:

不需要Google Play服务。这是一个痛苦的屁股,我花了超过50个小时(编辑:100多个小时)搞清楚,但这里有很多事情,它有助于知道:

图书馆

对于Google的在线服务,您在项目中需要这些库:(Instructions and Download Link

  • 谷歌-API的客户端 - 1.11.0-beta.jar
  • 谷歌-API的客户端 - 机器人-1.11.0-beta.jar
  • 谷歌-HTTP-客户1.11.0-beta.jar
  • 谷歌-HTTP-客户机器人-1.11.0-beta.jar
  • 谷歌-HTTP-客户杰克逊-1.11.0-beta.jar
  • 谷歌OAuth的客户端 - 1.11.0-beta.jar
  • 番石榴11.0.1.jar
  • 杰克逊核-ASL-1.9.9.jar
  • jsr305-1.3.9.jar

对于Google云端硬盘,您还需要:

  • google-api-services-drive-v2-rev9-1.8.0-beta.jar(Download Link

设置控制台

接下来,转到Google Console。制作一个新项目。在“服务”下,您需要启用两项内容: DRIVE API DRIVE SDK !它们是分开的,一个不会自动转动另一个,而且你必须同时开启!(弄清楚这个浪费了我至少20个小时的时间。)

仍然在控制台上,转到API Access。创建一个客户端,使其成为Android应用程序。给它你的包ID。我不认为指纹的东西实际上很重要,因为我很确定我使用了错误的指纹,但是无论如何都要尝试做到这一点(Google为它提供了说明。)

它会生成客户端ID 。你需要那个。抓住它。

编辑:我被告知我错了,你只需要开启Drive API,Drive SDK根本不需要打开,而你只是需要使用Simple API Key,而不是为Android设置一些东西。我现在正在研究这个问题,如果我弄明白的话,可能会在几分钟后编辑这个答案......

ANDROID代码 - 设置和上传

首先,获取身份验证令牌:

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

接下来,OnTokenAcquired()需要设置如下:

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...
        }
    }
}

ANDROID CODE - 正在下载

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

最后一件事......如果该意图被发送出去,你需要在返回结果时进行处理。

@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.
    }
}

ANDROID CODE - 正在更新

有关更新Google云端硬盘上文件上次修改日期的两个简要说明:

  1. 您必须提供完全初始化的DateTime。如果您不这样做,您将收到“错误请求”#34;来自Google云端硬盘。
  2. 您必须同时使用来自Google云端硬盘的文件中的setModifiedDate()和更新请求本身上的setSetModifiedDate(true)。 (有趣的名字,嗯?&#34; setSet [...]&#34;,人们不可能错误地输入那个......)
  3. 这里有一些简短的示例代码,展示了如何进行更新,包括更新文件时间:

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

    THE MANIFEST

    您需要以下权限:GET_ACCOUNTS,USE_CREDENTIALS,MANAGE_ACCOUNTS,INTERNET,并且您很可能也需要WRITE_EXTERNAL_STORAGE,具体取决于您要存储的位置你文件的本地副本。

    您的构建目标

    右键单击您的项目,进入其属性,然后在Android下将构建目标更改为Google API(如果必须)。如果他们不在那里,请从android下载管理器下载。

    如果您要在模拟器上进行测试,请确保其目标是Google API,而非通用Android。

    您需要在测试设备上设置Google帐户。所写的代码将自动使用它找到的第一个Google帐户(这是[0]的内容。)IDK,如果您需要下载Google云端硬盘应用程序才能使用此帐户。我使用的是API Level 15,我不知道这段代码能用多久。

    REST

    上面的内容应该让你开始,希望你能从那里找到出路...老实说,这就是我到目前为止所取得的成果。我希望这可以帮助很多人并为他们节省很多时间。我非常肯定我已经编写了最全面的设置指南来设置Android应用以使用Google云端硬盘。谷歌羞于在至少6个不同的页面上传播必要的材料,这些页面根本不相互链接。

答案 1 :(得分:4)

从Google I / O查看此视频,了解如何将您的Android应用与云端硬盘整合:

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

请注意,您在视频中看到的内容基于Google Play服务,尚未向公众发布

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

答案 2 :(得分:4)

2015年,情况发生了变化!

使用gradle获取'Android的Android API':

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

有一些新的doco(虽然IMO仍然乏善可陈):

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

对于那些即将崩塌的人......到目前为止我遇到的最大问题是,绝对没有办法区分已经从正常文件夹中永久删除的文件夹...你可以找到它们,你可以在其中创建文件夹和文件,只写入文件DriveContents将始终失败。

答案 3 :(得分:2)

查看Google的DrEdit Example,其中有一个名为android/的文件夹。复制它,按照readme,它应该可以正常工作(适用于带有KitKat的Android模拟器)。

<强> P.S。

很抱歉要恢复此功能,但新的Google Drive Android API不支持完全云端硬盘访问权限,只支持drive.filedrive.appdata authorization scopes,因此如果您需要完全访问权限,则需要回到好的'ol Google API's Client for Java(DrEdit示例使用)。