如何在Android应用程序中设置Google驱动器凭据?

如何在Android应用程序中设置Google驱动器凭据?,android,oauth-2.0,google-drive-api,Android,Oauth 2.0,Google Drive Api,该应用程序在“谷歌API控制台”中注册为“已安装应用程序”-似乎这是Android应用程序的正确设置,不是吗 所以我确实有一个客户端Id,没有秘密Id。为了澄清这一点:它不是Web应用程序,也不是Google Drive应用程序——它是一个Android应用程序,可以访问Google Drive云中的其他用户数据 在应用程序中,我获取帐户(works),并请求令牌(works)。现在我想用这个令牌和客户端Id连接到Google Drive。结果是“401,无效凭证”。这个代码怎么了 public

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

所以我确实有一个客户端Id,没有秘密Id。为了澄清这一点:它不是Web应用程序,也不是Google Drive应用程序——它是一个Android应用程序,可以访问Google Drive云中的其他用户数据

在应用程序中,我获取帐户(works),并请求令牌(works)。现在我想用这个令牌和客户端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);
            }
        }
    }
}

是的,文档很难理解

换衣服

new GoogleKeyInitializer(CLIENT_ID)

它应该会起作用


您可以在Google的API访问页面的SIMPLE API访问部分(API键)下找到您的
SIMPLE API访问
。如果此部分不可用,您必须首先激活服务页面上的驱动器API访问。

我尝试了所有这些,最后发现此代码可用于google日历API。我过去每次使用谷歌认证并将其传递给构建时都会得到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();


}

您包含的代码段有两个问题

  • 在从AccountManager获取新的
    authToken
    之前,必须使旧的authToken无效

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

    • 可通过访问以下网站获取
    • 单击左侧菜单上的API访问
    • 查找简单API访问,并复制API密钥
    • 在构建驱动器对象时设置API键

      .setJsonHttpRequestInitializer(新的Google键初始值设定项(键))


  • 这里有一个小样本演示了令牌失效:

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

    使用我在答案中列出的方法,我可以确认您能够做到以下几点:

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

    对不起,这两个都不起作用。相同错误:401,凭证无效。简单API密钥部分提到“…当您不需要访问用户数据时…”,但我的Android应用程序也是如此。我不明白。是否没有人代表通过AccountManager和Google凭据授予权限的用户成功创建了一个连接到Google Drive数据的Android应用程序?您的代码和我当时看到的唯一区别是,他们正在调用
    credential.setAccessToken(authToken)
    在构建
    任务
    实例之后。也许交换这两行就行了?运气不好。好像有东西坏了。无论如何,谢谢。@HaraldWilhelm我想告诉你我非常广泛的答案,包括如何在没有401错误的情况下下载文件(我已经更新了它,在答案的Android代码部分末尾包含了下载代码),在这里:谢谢你的回答。它不起作用。我用简单的API键->401尝试了您的精确代码。我的应用程序是一个“已安装的应用程序”,其客户端Id取自API控制台。我怀疑一个简单的API密钥与一个“已安装的应用程序”结合使用是否有效。你是否成功地制作了一个可以从Google Drive下载文件的Android应用程序?如果是这样的话,你介意分享代码吗?据我所知,我有一个最完整的驱动应用程序,不是谷歌的,它可以在Android上运行,而且我无法下载文件(我总是会遇到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();
    
    
    }
    
    AccountManager.get(activity).invalidateAuthToken("com.google", authToken);
    accountManager.getAuthToken(...);