【问题标题】:Android Open and Save files to/from Google Drive SDKAndroid 打开和保存文件到/从 Google Drive SDK
【发布时间】:2012-08-23 05:48:50
【问题描述】:

过去六个小时,我一直在翻阅来自 Google 的文档,但我仍然不知道如何开始。我想做的就是让我现有的 Android 应用程序可以从 Google Drive 读取文件,将新文件上传到 Google Drive,并编辑 Google Drive 上的现有文件。

我了解到 Drive SDK v2 只专注于让 Android(以及一般的移动设备)开发人员更容易使用它,但他们的文档中似乎几乎没有关于它的任何内容。

理想情况下,我希望有人指出一些体面的文档、示例或教程,涵盖如何执行此操作(请记住,我使用的是 Android。他们有很多关于如何将云端硬盘与 Google 应用一起使用的资料引擎;我已经看过它,但我不知道如何从它转到 Android 应用程序。)

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

理想情况下,我希望它能够像官方的 Google Drive 应用那样自动处理帐户。

【问题讨论】:

    标签: android google-drive-api


    【解决方案1】:

    观看 Google I/O 的此视频,了解如何将您的 Android 应用与云端硬盘集成:

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

    请注意,您在视频中看到的内容基于 Google Play 服务:

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

    【讨论】:

    • 感谢您的视频!我还没有看过它,但标题表明它会非常有用。 Google Play 服务尚未向公众推出这一事实意味着什么?目前,并且可能永远,该应用仅供内部使用......这会改变什么吗?
    • 这意味着您将无法使用视频中描述的授权机制,但不用担心,它应该很快就会启动。
    • 是否有可以在 Eclipse 中打开和拆分的示例项目?由于 Google Play 服务尚未启动,如何测试应用程序是否正常工作?
    • Google Play 服务启动时会发布样例
    • Google Play 服务现已推出,示例即将推出
    【解决方案2】:

    编辑:Claudio Cherubino 说 Google Play 服务现已推出,这将使这一过程变得更加容易。但是,没有可用的示例代码(但是,他说它即将推出......他们说 Google Play 服务在 4 个月前“即将推出”,所以这个答案很有可能继续成为唯一完全有效的访问示例Google Drive 从您的 Android 应用程序到 2013 年。)

    Edit 2X:当我说谷歌要到明年才会有一个可行的例子时,我好像提前了一个月。来自 Google 的官方指南在这里:

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

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

    此操作不需要 Google Play 服务。真是让人头疼,我花了 50 多个小时(编辑:100 多个小时)来弄清楚这一切,但这里有很多事情需要了解:

    图书馆

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

    • 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

    特别是对于 Google Drive,您还需要这个:

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

    设置控制台

    接下来,转到Google Console。做一个新项目。在服务下,您需要打开两件事:DRIVE APIDRIVE SDK!它们是分开的,一个不会自动打开另一个,并且您必须同时打开!(弄清楚这一点浪费了我至少 20 个小时的时间。)

    仍然在控制台上,转到 API 访问。创建一个客户端,使其成为 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...
            }
        }
    }
    

    安卓代码 - 下载

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

    安卓代码 - 更新

    关于更新 Google Drive 上文件的最后修改日期的两个快速说明:

    1. 您必须提供一个完全初始化的 DateTime。如果不这样做,您将收到来自 Google Drive 的“错误请求”响应。
    2. 您必须对来自 Google Drive 的文件使用 setModifiedDate() 并在更新请求本身上使用 setSetModifiedDate(true)。 (有趣的名字,嗯?“setSet[...]”,人们不可能打错那个...)

    下面是一些简短的示例代码,展示了如何进行更新,包括更新文件时间:

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

    清单

    您将需要以下权限:GET_ACCOUNTS、USE_CREDENTIALS、MANAGE_ACCOUNTS、INTERNET,并且很有可能您还需要 WRITE_EXTERNAL_STORAGE,具体取决于您希望将文件的本地副本存储在何处。

    您的构建目标

    右键单击您的项目,进入它的属性,如果需要,在 Android 下将构建目标更改为 Google API。如果它们不存在,请从 android 下载管理器下载它们。

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

    您需要在测试设备上设置一个 Google 帐户。所编写的代码将自动使用它找到的第一个 Google 帐户(这就是 [0] 的含义)。如果您需要下载 Google Drive 应用程序才能使其正常工作,请使用 IDK。我使用的是 API Level 15,我不知道这段代码还能运行多久。

    其余部分

    以上内容应该可以帮助您入门,并希望您能从那里找到出路……老实说,这就是我到目前为止所获得的。我希望这可以帮助很多人,并为他们节省很多时间。我相当肯定我刚刚编写了最全面的设置指南来设置 Android 应用程序以使用 Google Drive。 Google 感到羞耻,因为他们在至少 6 个不同的页面上传播了必要的材料,而这些页面根本没有相互链接。

    【讨论】:

    • +1 表示出色的回答者。三周以来,我一直在努力通过 Google Play 访问 Google Drive(我不断收到 403 Forbidden 错误)。我现在想试试你的方法。你会碰巧有一个小的工作示例应用程序,我可以下载它让我走上正轨吗?我真的很感激。
    • 很高兴听到我能提供帮助。我使用此代码的应用程序包含在我公司的 NDA 中......我被允许分享我在帖子中的内容(我们发布了一个赏金来尝试看看这是否有助于加快同步服务的速度工作,)但我很确定共享足够代码以使其实际编译并且工作将被击落的请求......所以我担心我不能共享比我已经拥有的更多的代码。我很乐意回答您的任何具体问题。
    • 感谢您的及时回复。我理解并尊重您的 NDA 情况。我将尽我所能按照您的上述指示进行操作,如果我有任何问题,我会告诉您。
    • 嘿伙计,我遇到了一些问题。你能帮帮我吗?:stackoverflow.com/questions/13577100/google-drive-sdk-error
    • @ChrisUK - 自 2013 年初以来我没有接触过 Android 或 Google Drive,所以我不能肯定,但可能不会。我可能会尝试以“现在是 2015 年,情况发生了变化!”开头的答案
    【解决方案3】:

    现在是 2015 年,情况发生了变化!

    使用 gradle 获取“Drive API for Android”:

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

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

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

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

    【讨论】:

    • 我正在尝试在我的 Android 应用程序中使用 Google Drive Android API 从 Google Drive 下载文件,但它无法正常工作。我应该使用 REST API 还是其他?我如何从这里拿走它?
    • @Bot 我建议您针对您的特定案例创建一个新问题。
    【解决方案4】:

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

    .

    附言

    很抱歉恢复了这个,但是新的Google Drive Android API 不支持完整的云端硬盘访问权限,只有 drive.filedrive.appdata authorization scopes,所以如果你需要完全访问权限,你必须回到好的 'ol Google API's Client for Java(DrEdit 示例使用)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-24
      • 1970-01-01
      • 1970-01-01
      • 2013-03-29
      • 1970-01-01
      相关资源
      最近更新 更多