【问题标题】:How setup Google Drive Credentials within Android App?如何在 Android 应用程序中设置 Google Drive Credentials?
【发布时间】:2012-09-06 11:33:13
【问题描述】:

该应用程序在“Google API 控制台”中注册为“已安装应用程序”——这似乎是 Android 应用程序的正确设置,不是吗?

所以我确实有一个 Client-Id 而没有 Secret-Id。明确一点:它既不是 Web 应用,也不是 Google Drive-App——它是一个访问 Google Drive 云中其他用户数据的 Android 应用。

在应用程序中,我获取帐户(有效)并请求令牌(有效)。现在我想使用该令牌和 Client-Id 连接到 Google Drive。结果是“401,无效凭证”。这段代码有什么问题?

public class ActivityMain extends Activity implements DialogInterface.OnClickListener {

    // https://developers.google.com/drive/scopes
    private static final String AUTH_TOKEN_TYPE = "oauth2:https://www.googleapis.com/auth/drive";

    // https://code.google.com/apis/console/
    private static final String CLIENT_ID = "999999999999999.apps.googleusercontent.com";

    private AccountManager accountManager;
    private Account[] accounts;
    private String authName;
    private String authToken;

    @Override
    public void onClick(final DialogInterface dialogInterface, final int item) {

        processAccountSelected(accounts[item]);
    }

    @Override
    public void onCreate(final Bundle bundle) {
        super.onCreate(bundle);

        setContentView(R.layout.activitymain);

        accountManager = AccountManager.get(this);
        accounts = accountManager.getAccountsByType("com.google");

        if (accounts == null || accounts.length == 0) {
            // TODO
        } else if (accounts.length == 1) {
            processAccountSelected(accounts[0]);
        } else if (accounts.length > 1) {
            showDialog(MyConstants.DIALOG_ACCOUNTCHOSER);
        }
    }

    @Override
    protected Dialog onCreateDialog(final int id) {
        switch (id) {
            case MyConstants.DIALOG_ACCOUNTCHOSER:
                AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);

                String[] names = new String[accounts.length];

                for (int i = 0; i < accounts.length; i++) {
                    names[i] = accounts[i].name;
                }

                alertDialogBuilder.setItems(names, this);
                alertDialogBuilder.setTitle("Select a Google account");
                return alertDialogBuilder.create();
        }

        return null;
    }

    private void processAccountSelected(final Account account) {
        if (account != null) {
            authName = account.name.toString();
            if (!Tools.isEmpty(authName)) {
                Toast.makeText(this, authName, Toast.LENGTH_LONG).show();

                accountManager.getAuthToken(account, AUTH_TOKEN_TYPE, null, this,
                        new AccountManagerCallback<Bundle>() {

                            public void run(final AccountManagerFuture<Bundle> future) {
                                try {
                                    authToken = future.getResult().getString(
                                            AccountManager.KEY_AUTHTOKEN);
                                    processTokenReceived();
                                } catch (OperationCanceledException exception) {
                                    // TODO
                                } catch (Exception exception) {
                                    Log.d(this.getClass().getName(), exception.getMessage());
                                }
                            }
                        }, null);
            }
        }
    }

    private void processListFiles(final Drive drive) {
        List<File> result = new ArrayList<File>();
        Files.List request = null;
        try {
            request = drive.files().list();
        } catch (IOException exception) {
        }

        do {
            try {
                FileList files = request.execute();

                result.addAll(files.getItems());
                request.setPageToken(files.getNextPageToken());
            } catch (IOException exception) {
                // --> 401 invalid credentials
            }
        } while (request.getPageToken() != null && request.getPageToken().length() > 0);
    }

    private void processTokenReceived() {
        if (!Tools.isEmpty(authToken)) {
            final HttpTransport transport = AndroidHttp.newCompatibleTransport();
            final JsonFactory jsonFactory = new GsonFactory();
            GoogleCredential credential = new GoogleCredential();
            credential.setAccessToken(authToken);
            Drive drive = new Drive.Builder(transport, jsonFactory, credential)
                    .setApplicationName(getString(R.string.txt_appname))
                    .setJsonHttpRequestInitializer(new GoogleKeyInitializer(CLIENT_ID))
                    .build();

            if (drive != null) {
                processListFiles(drive);
            }
        }
    }
}

我不得不说这是一团糟。网络中有很多页面只显示部分,并且有很多页面使用已弃用、丢失或不同的方法来做同样的事情。在我看来,没有两个页面显示了从 Android 应用程序中从 Google 云端硬盘获取数据的相同方式。

非常感谢任何帮助。

编辑:我可以自己解决。这是不同变化的组合:

  • 必须将 android:minSdkVersion="11" 设置为要求
  • 必须使用当前的库:google-api-client-1.11.0-beta.jar、google-api-client-android-1.11.0-beta.jar、google-api-services-drive-v2- rev9-1.8.0-beta.jar、google-http-client-1.11.0-beta.jar、google-http-client-android-1.11.0-beta.jar、google-http-client-gson-1.11。 0-beta.jar,google-http-client-jackson2-1.11.0-beta.jar,google-oauth-client-1.11.0-beta.jar,gson-2.1.jar,guava-11.0.1.jar, jackson-core-2.0.5.jar,jsr305-1.3.9.jar

这是获取Drive Object的当前部分:

    GoogleCredential credential = new GoogleCredential();
    credential.setAccessToken(authToken);

    HttpTransport transport = AndroidHttp.newCompatibleTransport();

    JsonFactory jsonFactory = new AndroidJsonFactory();

    drive = new Drive.Builder(transport, jsonFactory, credential)
            .setApplicationName(getString(R.string.txt_appname))
            .setJsonHttpRequestInitializer(
                    new GoogleKeyInitializer(APIKEY_SIMPLE))
            .build();
    if (drive != null) {
    }

【问题讨论】:

    标签: android oauth-2.0 google-drive-api


    【解决方案1】:

    是的,文档很难理解。

    只是改变

    new GoogleKeyInitializer(CLIENT_ID)
    

    new GoogleKeyInitializer(SIMPLE_API_ACCESS_KEY)
    

    它应该可以工作。

    您可以在 API 访问 页面(API key)的简单 API 访问 部分下的 Google 的 APIs Console 中找到您的 SIMPLE_API_ACCESS_KEY。如果此部分不可用,您必须先在服务页面上激活 Drive API 访问权限。

    【讨论】:

    • 对不起,也没有用。同样的错误:401,无效的凭据。简单的 API 密钥部分提到“......当您不需要访问用户数据时......”但对于我的 Android 应用程序来说确实如此。我不明白。没有人代表通过 AccountManager 和 Google Credentials 授权的用户成功创建了连接到 Google Drive 数据的 Android 应用程序吗?
    • 那么你的代码和我看到的Tasks API example 之间的唯一区别是他们在构建Tasks 实例之后调用credential.setAccessToken(authToken) 。那么也许交换这两条线就可以了?
    • 不走运。好像有什么坏了。无论如何,谢谢。
    • @HaraldWilhelm 我想向您介绍我非常广泛的答案,包括如何在没有 401 错误的情况下下载文件(我已对其进行了更新,以在 Android 代码末尾包含下载代码部分答案),在这里:stackoverflow.com/questions/12164024/…
    【解决方案2】:

    我尝试了所有这些,最后发现此代码可以与 google Calendar api 一起使用。每次我使用 GoogleCredentials 并将其传递给构建时,我都会得到 401。

    HttpTransport transport = AndroidHttp.newCompatibleTransport();;
        JsonFactory jsonFactory = new GsonFactory();
        HttpRequestInitializer httpRequestInitializer;
    
        Log.i("Reached calendar builder", "Reached calendar builder"+accessToken);
    
        //GoogleCredential credential = new GoogleCredential();
    
         httpRequestInitializer = new HttpRequestInitializer(){
            public void initialize(HttpRequest request) throws IOException
            {
                    request.getHeaders().setAuthorization(GoogleHeaders.getGoogleLoginValue(accessToken));
            }
        };
    
        Calendar service = new Calendar.Builder(transport, jsonFactory, httpRequestInitializer)
        .setApplicationName("Meetrbus/1.0")
        .setJsonHttpRequestInitializer(new GoogleKeyInitializer("API_KEY"))
        .build();
    
    
    }
    

    【讨论】:

    • 感谢您的回答。它没有用。我使用简单 API 密钥 - > 401 尝试了您的确切代码。我的应用程序是一个“已安装的应用程序”,其客户端 ID 取自 API 控制台。我怀疑 Simple API Key 是否可以与“已安装的应用程序”结合使用。
    【解决方案3】:

    您包含的 sn-p 存在 2 个问题。

    1. 必须在从 AccountManager 获取新的authToken 之前使旧的 authToken 无效。

      AccountManager.get(activity).invalidateAuthToken("com.google", authToken);
      accountManager.getAuthToken(...);
      
    2. setJsonHttpRequestInitializer 的调用必须使用在您的项目的 API 控制台中声明的简单 API 密钥。

      • 可通过访问APIs Console获取。
      • 点击左侧菜单中的API访问
      • 查找 Simple API Access,然后复制 API 密钥
      • 在构建 Drive 对象时设置 API 密钥。

        .setJsonHttpRequestInitializer(new GoogleKeyInitializer(KEY))

    这里有一个小示例演示令牌失效:http://chiarg.com/?p=429

    【讨论】:

    • 你有没有制作一个可以从 Google Drive 下载文件的 Android 应用程序?如果是这样,你介意分享它的代码吗?据我所知,我有最完整的云端硬盘应用程序,不是来自谷歌,在 Android 上运行,我无法下载文件(我总是收到 401 错误......不知何故,我有权完全删除文件, 或者完全改变他们的内容,但不下载当前的内容?)我的代码在这里:stackoverflow.com/questions/12164024/…
    【解决方案4】:

    我在这里给出了关于在 Android 上使用 Google Drive 的广泛答案:

    Android Open and Save files to/from Google Drive SDK

    使用我在该答案中列出的方法,我可以确认您能够执行以下操作:

    • 设置和访问元数据
    • 上传文件
    • 下载文件
    • 在 Google Drive 目录之间移动文件
    • 完全从驱动器中删除文件

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-17
      • 1970-01-01
      • 1970-01-01
      • 2013-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多