gpt4 book ai didi

android - 如何使用其REST API在Android上的Google云端硬盘上访问应用程序数据

转载 作者:搜寻专家 更新时间:2023-11-01 09:22:08 24 4
gpt4 key购买 nike

谷歌正在搁置其用于访问谷歌服务(即Google云端硬盘)的Android API,并将其替换为REST。

尽管有“迁移指南”,但由于“重复类定义”之类的原因,它无法构建可供安装的APK软件包。

由于某种原因,要找到关于如何通过Android使用REST(最好使用OS固有的方法)访问Google服务的全面信息非常困难。

最佳答案

经过大量的搜索,困惑,挠头,偶尔的咒骂以及对我真正不想关心的事情的大量学习之后,我想分享一些实际上对我有用的代码。

免责声明:我是一名菜鸟Android程序员(他的确不怎么挑衅),因此,如果这里有真正的Android向导摇头的事情,希望您能原谅我。

所有代码示例均使用Kotlin和Android Studio编写。

值得注意的是:在本小教程中仅查询“应用程序数据文件夹”,如果要执行其他操作,则需要调整请求的scopes

必要的准备工作

按照here所述为您的应用程序创建一个项目和一个OAuth密钥。我收集的许多授权信息都来自那个地方,因此希望能找到一些相似之处。

您的项目的仪表板可以在https://console.developers.google.com/apis/dashboard中找到

implementation "com.google.android.gms:play-services-auth:16.0.1"添加到您的应用程序gradle文件中。此依赖关系将用于身份验证目的。

为您的应用程序 list 添加“互联网”支持

<uses-permission android:name="android.permission.INTERNET"/>

验证

认证的起点是我们的旅程。
为此,我使用了 GoogleSignIn框架。

创建一个 Activity (或使用您的主要 Activity ,您的选择)并在那里覆盖 onActivityResult方法。

添加如下所示的块:
if (requestCode == RC_SIGN_IN) {
GoogleSignIn.getSignedInAccountFromIntent(data)
.addOnSuccessListener(::evaluateResponse)
.addOnFailureListener { e ->
Log.w(RecipeList.TAG, "signInResult:failed =" + e.toString())
evaluateResponse(null)
}
}
RC_REQUEST_CODE是在随播对象中定义为常量的任意选择的ID值。

一旦您想要执行身份验证(即通过单击按钮),就需要开始我们刚刚为其声明回调的 Activity 。

为此,您需要先准备身份验证请求。
GoogleSignIn.getClient(this, GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken("YourClientIDGoesHere.apps.googleusercontent.com")
.requestScopes(Scope(Scopes.DRIVE_APPFOLDER))
.build())

该请求为您提供了一个客户端对象,您可以通过调用直接使用它。
startActivityForResult(client.signInIntent, RC_SIGN_IN)

此调用将导致授权屏幕弹出(如有必要),允许用户选择一个帐户,然后再次关闭自身,将数据传递给 onActivityResult
要获取先前登录的用户(不启动新 Activity ),还可以在后台使用 GoogleSignIn.getLastSignedInAccount(this);方法。

一旦失败,这些方法中的任何一个都将返回 null,因此请准备好进行处理。

现在我们有了经过身份验证的用户,我们该如何处理?

我们要求一个身份验证 token 。
现在,我们的帐户对象中只有一个idToken,对于我们想做的事情绝对是没有用的,因为它不允许我们调用API。

但是Google再次进行了救援,并向我们提供了 GoogleAuthUtil.getToken(this, account.account, "oauth2:https://www.googleapis.com/auth/drive.appdata")调用。

如果一切正常,此调用将转发帐户信息并返回String:我们需要的auth token 。

需要注意的是:此方法执行网络请求,这意味着,如果您尝试在UI线程中执行它,它将在您的面前抛出。

我创建了一个帮助程序类,该类模仿Google的“任务”对象的行为(和API),该类解决了在线程上调用方法并通知调用线程已完成操作的烦恼。

将auth token 保存在可以再次找到的位置,(最终)完成授权。

查询API

这部分比上一部分简单得多,并且与 the Google Drive REST API并驾齐驱

所有网络请求都需要在“非UI”线程上执行,这就是为什么我将它们包装在助手类中以在有数据显示时通知我的原因。
private fun performNet(url: String, method: String, onSuccess: (JSONObject) -> Unit)
{
ThreadedTask<String>()
.addOnSuccess { onSuccess(JSONObject(it)) }
.addOnFailure { Log.w("DriveSync", "Sync failure $it") }
.execute(executor) {
val url = URL(url)
with (url.openConnection() as HttpURLConnection)
{
requestMethod = method
useCaches = false
doInput = true
doOutput = false
setRequestProperty("Authorization", "Bearer $authToken")

processNetResponse(responseCode, this)
}
}
}

private fun processNetResponse(responseCode: Int, connection: HttpURLConnection) : String
{
var responseData = "No Data"
val requestOK = (responseCode == HttpURLConnection.HTTP_OK)

BufferedReader(InputStreamReader(if (requestOK) connection.inputStream else connection.errorStream))
.use {
val response = StringBuffer()

var inputLine = it.readLine()
while (inputLine != null) {
response.append(inputLine)
inputLine = it.readLine()
}
responseData = response.toString()
}

if (!requestOK)
throw Exception("Bad request: $responseCode ($responseData)")

return responseData
}

该代码块是我从各种来源整理来的相当通用的辅助函数,本质上只是使用URL进行查询,执行的方法( GETPOSTPATCHDELETE)并从中构造HTTP请求。

我们在授权过程中获得的auth token 作为 header 传递给请求,以对Google进行身份验证并将其标识为“用户”。

如果一切正常,Google会以HTTP_OK(200)进行回复,并会调用 onSuccess,它将JSON回复转换为JSONObject,然后将其传递给我们之前注册的评估函数。

获取文件列表
performNet("https://www.googleapis.com/drive/v3/files?spaces=appDataFolder", "GET")
spaces参数用于告知Google,我们不想看到根文件夹,而是看到应用程序数据文件夹。没有此参数,请求将失败,因为我们仅请求访问appDataFolder。

响应应在 JSONArray键下包含一个 files,然后您可以解析并绘制所需的任何信息。

ThreadTask类

该帮助器类封装了在不同上下文上执行操作并在完成时在实例化线程上执行回调的必要步骤。

我并不是说这是解决问题的方法,而只是我的“简直不知道”。
import android.os.Handler
import android.os.Looper
import android.os.Message
import java.lang.Exception
import java.util.concurrent.Executor

class ThreadedTask<T> {
private val onSuccess = mutableListOf<(T) -> Unit>()
private val onFailure = mutableListOf<(String) -> Unit>()
private val onComplete = mutableListOf<() -> Unit>()

fun addOnSuccess(handler: (T) -> Unit) : ThreadedTask<T> { onSuccess.add(handler); return this; }
fun addOnFailure(handler: (String) -> Unit) : ThreadedTask<T> { onFailure.add(handler); return this; }
fun addOnComplete(handler: () -> Unit) : ThreadedTask<T> { onComplete.add(handler);return this; }

/**
* Performs the passed code in a threaded context and executes Success/Failure/Complete handler respectively on the calling thread.
* If any (uncaught) exception is triggered, the task is considered 'failed'.
* Call this method last in the chain to avoid race conditions while adding the handlers.
*
*/
fun execute(executor: Executor, code: () -> T)
{
val handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
publishResult(msg.what, msg.obj)
}
}

executor.execute {
try {
handler.obtainMessage(TASK_SUCCESS, code()).sendToTarget()
} catch (exception: Exception) {
handler.obtainMessage(TASK_FAILED, exception.toString()).sendToTarget()
}
}
}

private fun publishResult(returnCode: Int, returnValue: Any)
{
if (returnCode == TASK_FAILED)
onFailure.forEach { it(returnValue as String) }
else
onSuccess.forEach { it(returnValue as T) }
onComplete.forEach { it() }

// Removes all handlers, cleaning up potential retain cycles.
onFailure.clear()
onSuccess.clear()
onComplete.clear()
}

companion object {
private const val TASK_SUCCESS = 0
private const val TASK_FAILED = 1
}
}

在这种情况下,执行顺序很重要。
首先,您需要将回调添加到类对象中,最后需要调用 execute,并为其提供要使用其运行线程的执行器,当然还要提供要执行的代码。

这不是您使用Google云端硬盘可以做的所有事情,但这只是一个开始,我希望这个小小的汇编将来可以为其他人省去一些麻烦。

关于android - 如何使用其REST API在Android上的Google云端硬盘上访问应用程序数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54052220/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com