通过一键登录获取 GoogleCredentials

lor*_*nzo 5 android google-drive-api google-oauth

我正在尝试将文件上传到 Google 云端硬盘,并让用户选择用于上传的 Google 帐户。

我正在遵循本指南: https ://developers.google.com/drive/api/guides/manage-uploads

如前所述,它需要一些 OAuth 凭据才能连接到 Drive API:

// Load pre-authorized user credentials from the environment.
// TODO(developer) - See https://developers.google.com/identity for
// guides on implementing OAuth2 for your application.
Run Code Online (Sandbox Code Playgroud)

我已设法从 One Tap 客户端获取一个SignInCredential对象,但现在我尝试将其转换为GoogleCredentialsGoogle Drive API 的对象。

使用指南中的代码

GoogleCredentials.getApplicationDefault()
        .createScoped(Arrays.asList(DriveScopes.DRIVE_FILE))
Run Code Online (Sandbox Code Playgroud)

...最终导致崩溃:

应用程序默认凭据不可用。

如果我尝试自己创建凭据

    val accessToken = AccessToken(token, Date(0L))
    val credentials: GoogleCredentials = GoogleCredentials.create(accessToken)
Run Code Online (Sandbox Code Playgroud)

我也最终陷入崩溃:

java.lang.IllegalStateException:OAuth2Credentials实例不支持刷新访问令牌。应使用具有新访问令牌的实例,或支持刷新的派生类型。

我们在这里应该做什么?

ava*_*cha 3

嗯,我正在尝试做同样的事情,并且这是一个让这个工作成功的旅程。几个单独的文档是必要的,位于完全不同的地方,有时彼此不一致,有时严重过时,链接到已弃用或丢失的资源以及陈旧的代码和依赖项。

如果您只想查看代码,请看这里

以下是我将其拼凑在一起的最大努力 - 在一个最小的示例中,使用现代代码 - 但我知道身份验证和授权是微妙的主题,所以我敦促任何读者请评论我在下面的代码中存在的任何安全缺陷

1. 设置谷歌云

一般来说,我们会首先学习本教程,有时我们会需要其他链接。

  • 在Google Cloud 控制台中设置项目
    • 对我来说,项目类型是“外部”
    • 只有“应用程序名称”、“用户支持电子邮件”和“开发人员联系电子邮件”是必填的。我总是只会提到完成这项工作所需的最低限度
    • 对于下一页“范围”,我们将需要此文档,您可以在其中找到您需要的范围。我使用了https://www.googleapis.com/auth/drive.appdata,请确保稍后将您的选择与代码相匹配。请注意,此文档也对此有所帮助,特别是如果您稍后需要编辑的话
    • 作为测试用户,我只添加了我自己。请注意,所有这些都适用于未发布和未经审查的项目
  • 本教程建议立即在 OAuth 同意屏幕上设置法律文档,但目前没有必要
  • 现在严格按照凭证设置操作,创建一个 Android 客户端 ID(您可以通过 获取 SHA-1 签名gradle signingReport确保获取debug密钥,而不是debugAndroidTestkey,并且请注意,如果您愿意,这将验证您的调试应用程序)要稍后发布版本,您还必须向该客户端的 Google Cloud 控制台添加另一个客户端 ID)和一个 WebClient ID

2. 设置代码

现在我们结合这个这个来遵循这个文档

  • 将这些依赖项添加到您的应用程序中
implementation 'com.google.auth:google-auth-library-oauth2-http:1.16.0'
implementation 'com.google.android.gms:play-services-auth:20.4.1'
implementation 'com.google.http-client:google-http-client-gson:1.42.3'
implementation('com.google.api-client:google-api-client-android:2.2.0') {
    exclude group: 'org.apache.httpcomponents'
}
implementation ('com.google.apis:google-api-services-drive:v3-rev20230212-2.0.0') {
    exclude group: 'org.apache.httpcomponents'
}
Run Code Online (Sandbox Code Playgroud)

我在这里结合了 One-Tap 和 Google Drive 依赖项。这些在撰写本文时是最新的。不要采用本文档中的版本,它们已经过时,甚至不能相互编译。我们还需要一个 Android API 客户端,而不是 Java“Jetty”设置

  • 像教程中一样设置oneTapClient和 请求,确保使用您的 WebClientId,并且不要像 Lint 建议的那样将 strings.xml 中的连字符替换为长破折号。检查我的 Github 代码 startOneTapSignIn- 方法,使用 ActivityResultContract 而不是startActivityForResult处理更现代的实现
  • 现在我们需要 aandroid.accounts.Account才能使用您上面提到的方法来获取 a GoogleAccountCredential(这只是一个幻想HttpRequestInitializer,我们稍后可以将其用于驱动服务)。
val credentials = GoogleAccountCredential.usingOAuth2(context, 
    Collections.singleton(DriveScopes.DRIVE_APPDATA)
).setSelectedAccount(account)
Run Code Online (Sandbox Code Playgroud)
  • 这就是我陷入困境的地方,也是我提出这个问题的原因。旧版登录(用于所有 Google Drive 示例)通过以下方式提供了开箱即用的功能:
GoogleSignIn.getSignedInAccountFromIntent(data)
   .addOnSuccessListener { googleAccount: GoogleSignInAccount ->
Run Code Online (Sandbox Code Playgroud)
  • 但我们可以解决这个问题。这个 Stackoverflow 答案将我推向了正确的方向,我们可以自己创建一个帐户实例!经过一番尝试和错误后,我发现 Google 需要用户电子邮件,我们可以在oneTapCredential.id
val oneTapCredential: SignInCredential = oneTapClient.getSignInCredentialFromIntent(data)
Log.d(TAG, "Signed in as " + oneTapCredential.displayName)
saveLoginSuccess(this, Account(oneTapCredential.id, packageName))
Run Code Online (Sandbox Code Playgroud)
  • 就是这样,现在您可以将其与结合使用来设置 Google Drive 服务,如下所示
@WorkerThread
fun download(credentials: HttpRequestInitializer): String? {
    val service =
        Drive.Builder(
            NetHttpTransport(),
            GsonFactory.getDefaultInstance(),
            credentials
        ).setApplicationName("OneTapDrive")
            .build()
Run Code Online (Sandbox Code Playgroud)

有关上传和下载的完整示例,请再次参阅 Github