gpt4 book ai didi

Android 应用程序 + 具有完整驱动器访问权限的 Drive API ... 程序是什么?

转载 作者:太空狗 更新时间:2023-10-29 16:12:31 25 4
gpt4 key购买 nike

我正在寻找一些与使用 Android 应用程序访问 Google 云端硬盘相关的指南。

1) 我需要能够读取用户在我的应用之外上传的文件。这是否意味着我需要全驱动器访问权限? (如果该应用程序可以创建一个文件夹,然后查看该文件夹中存在的用户上传的所有文件,那就太好了,但我认为它不会以这种方式工作。)

2) 如果我需要全盘访问,Google 的“Drive API for Android”似乎不支持,我需要使用 REST api。我认为这是真的。

3) 我需要一个来自 Google 的 Auth 2.0 客户端 ID。如果我使用其余 API,这是否意味着我需要使用“Web 应用程序”ID?我想我需要这个,因为我想要一个“授权码”。我无法使用“Android”类型 ID 让它工作。

4) 我目前正在使用适用于 Android 的“Google 登录”来处理登录并提供授权代码。然后我可以将其转换为 token + 刷新 token ,并保存这些,以便我可以在一小时后以某种方式获得新 token 。是否需要手动处理刷新 token ?

它变得丑陋,但我认为既然我需要(?)全驱动器访问权限,那么这就是程序。

感谢您的指导。

编辑:该问题已被确定为重复问题。提供的链接给出了问题 #2 的答案,但没有解决其他问题。

我同意这个问题很困惑...

最佳答案

我在回答我自己的问题。

我为此苦苦挣扎,因为 A) Google 的 REST 示例使用过时的登录过程,B) “登录”示例使用的代码不适用于“完全访问”范围,C) 有太多尝试将它们放在一起时会出现截然不同的代码示例。

快速回答我现在看到的问题:1) 是的,读取在我的应用程序外上传的文件需要全驱动器访问权限。2) 是的,我需要使用 REST api。3) 是的,我需要一个“Web 应用程序”客户端 ID。4) Google 登录似乎是目前登录的最佳方式,只要您保留刷新 token ,使用 GoogleCredential 对象和 Drive api abject 将自动处理 token 刷新。

如果其他人正在努力使用最新的“登录”程序和 REST v3 从 Android 完全访问访问云端硬盘,下面是我的示例代码。

除了“Web 应用程序”OAuth 客户端 ID 之外,您还需要创建一个具有匹配包名称和证书指纹的“Android”类型 ID,以便登录工作。另请注意,您的开发版本和生产版本将拥有不同的证书。来自这些 Android 客户端的 ID/代码不需要输入到应用程序中。

build.gradle : 应用

// Google Sign In
compile 'com.google.android.gms:play-services-auth:10.0.1'

// Drive REST API
compile('com.google.apis:google-api-services-drive:v3-rev54-1.22.0') {
exclude group: 'org.apache.httpcomponents'
}

Activity

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

// Callback from Signin (Auth.GoogleSignInApi.getSignInIntent)
if (requestCode == 1) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
_googleApi.handleSignInResult(result);
}
}

完成工作的“GoogleApi”类

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;

import com.google.android.gms.auth.api.Auth;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.auth.api.signin.GoogleSignInResult;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Scope;
import com.google.android.gms.common.api.Status;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.FileList;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;


public class GoogleApi implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {

private Context _context;
private Handler _handler;
private GoogleCredential _credential;
private Drive _drive;

private GoogleApiClient _googleApiClient; // only set during login process
private Activity _activity; // launch intent for login (UI)

// Saved to data store
private boolean _loggedIn;
private String _refreshToken; // store, even if user is logged out as we may need to reuse


private static final String ClientID = "xxxxxx.apps.googleusercontent.com"; // web client
private static final String ClientSecret = "xxxxx"; // web client

private class FileAndErrorMsg {
public File file;
public String errorMsg;
public FileAndErrorMsg (File file_, String errorMsg_) { file = file_; errorMsg = errorMsg_; }
}
private class FileListAndErrorMsg {
public List<File> fileList;
public String errorMsg;
public FileListAndErrorMsg (List<File> fileList_, String errorMsg_) { fileList = fileList_; errorMsg = errorMsg_; }
}

// -------------------
// Constructor
// -------------------


public GoogleApi (Context context) {

_context = context;
_handler = new Handler();
loadFromPrefs(); // loggedIn, refreshToken

// create credential; will refresh itself automatically (in Drive calls) as long as valid refresh token exists
HttpTransport transport = new NetHttpTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
_credential = new GoogleCredential.Builder()
.setTransport(transport)
.setJsonFactory(jsonFactory)
.setClientSecrets(ClientID, ClientSecret) // .addRefreshListener
.build();
_credential.setRefreshToken(_refreshToken);

// Get app name from Manifest (for Drive builder)
ApplicationInfo appInfo = context.getApplicationInfo();
String appName = appInfo.labelRes == 0 ? appInfo.nonLocalizedLabel.toString() : context.getString(appInfo.labelRes);

_drive = new Drive.Builder(transport, jsonFactory, _credential).setApplicationName(appName).build();
}

// -------------------
// Auth
// -------------------

// https://developers.google.com/identity/sign-in/android/offline-access#before_you_begin
// https://developers.google.com/identity/sign-in/android/offline-access#enable_server-side_api_access_for_your_app
// https://android-developers.googleblog.com/2016/02/using-credentials-between-your-server.html
// https://android-developers.googleblog.com/2016/05/improving-security-and-user-experience.html


public boolean isLoggedIn () {
return _loggedIn;
}

public void startAuth(Activity activity) {
startAuth(activity, false);
}

public void startAuth(Activity activity, boolean forceRefreshToken) {

_activity = activity;
_loggedIn = false;
saveToPrefs();

GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestScopes(new Scope("https://www.googleapis.com/auth/drive"))
.requestServerAuthCode(ClientID, forceRefreshToken) // if force, guaranteed to get back refresh token, but will show "offline access?" if Google already issued refresh token
.build();

_googleApiClient = new GoogleApiClient.Builder(activity)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();

_googleApiClient.connect();
}

@Override
public void onConnected(Bundle connectionHint) {
// Called soon after .connect()
// This is only called when starting our Login process. Sign Out first so select-account screen shown. (OK if not already signed in)
Auth.GoogleSignInApi.signOut(_googleApiClient).setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
// Start sign in
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(_googleApiClient);
_activity.startActivityForResult(signInIntent, 1); // Activity's onActivityResult will use the same code: 1
}
});
}

@Override
public void onConnectionSuspended(int cause) {
authDone("Connection suspended.");
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) { authDone("Connection failed."); }

public void handleSignInResult(GoogleSignInResult result) {

// Callback from Activity > onActivityResult
if (result.isSuccess()) {
GoogleSignInAccount acct = result.getSignInAccount();
String authCode = acct.getServerAuthCode();
new Thread(new ContinueAuthWithAuthCode_Background(authCode)).start();
}
else authDone("Login canceled or unable to connect to Google."); // can we get better error message?
}

private class ContinueAuthWithAuthCode_Background implements Runnable {

String _authCode;
public ContinueAuthWithAuthCode_Background (String authCode) {
_authCode = authCode;
}
public void run() {

// Convert authCode to tokens
GoogleTokenResponse tokenResponse = null;
String errorMsg = null;
try {
tokenResponse = new GoogleAuthorizationCodeTokenRequest(new NetHttpTransport(), JacksonFactory.getDefaultInstance(), "https://www.googleapis.com/oauth2/v4/token", ClientID, ClientSecret, _authCode, "").execute();
}
catch (IOException e) { errorMsg = e.getLocalizedMessage(); }
final GoogleTokenResponse tokenResponseFinal = tokenResponse;
final String errorMsgFinal = errorMsg;

_handler.post(new Runnable() { public void run() {
// Main thread
GoogleTokenResponse tokenResponse = tokenResponseFinal;
String errorMsg = errorMsgFinal;
if (tokenResponse != null && errorMsg == null) {
_credential.setFromTokenResponse(tokenResponse); // this will keep old refresh token if no new one sent
_refreshToken = _credential.getRefreshToken();
_loggedIn = true;
saveToPrefs();
// FIXME: if our refresh token is bad and we're not getting a new one, how do we deal with this?
Log("New refresh token: " + tokenResponse.getRefreshToken());
}
else if (errorMsg == null) errorMsg = "Get token error."; // shouldn't get here
authDone(errorMsg);
} });
}
}

private void authDone(String errorMsg) {
// Disconnect (we only need googleApiClient for login process)
if (_googleApiClient != null && _googleApiClient.isConnected()) _googleApiClient.disconnect();
_googleApiClient = null;
}

/*
public void signOut() {
Auth.GoogleSignInApi.signOut(_googleApiClient).setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
}
});
}

public void revokeAccess() {
// FIXME: I don't know yet, but this may revoke access for all android devices
Auth.GoogleSignInApi.revokeAccess(_googleApiClient).setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
}
});
}
*/

public void LogOut() {
_loggedIn = false;
saveToPrefs(); // don't clear refresh token as we may need again
}


// -------------------
// API Calls
// -------------------


public void makeApiCall() {
new Thread(new TestApiCall_Background()).start();
}

private class TestApiCall_Background implements Runnable {
public void run() {

FileAndErrorMsg fileAndErr = getFolderFromName_b("Many Files", null);
if (fileAndErr.errorMsg != null) Log("getFolderFromName_b error: " + fileAndErr.errorMsg);
else {
FileListAndErrorMsg fileListAndErr = getFileListInFolder_b(fileAndErr.file);
if (fileListAndErr.errorMsg != null)
Log("getFileListInFolder_b error: " + fileListAndErr.errorMsg);
else {
Log("file count: " + fileListAndErr.fileList.size());
for (File file : fileListAndErr.fileList) {
//Log(file.getName());
}
}
}

_handler.post(new Runnable() { public void run() {
// Main thread
} });
}
}

private FileAndErrorMsg getFolderFromName_b (String folderName, File parent) {

// parent can be null for top level
// Working with folders: https://developers.google.com/drive/v3/web/folder

File folder = null;
folderName = folderName.replace("'", "\\'"); // escape '
String q = String.format(Locale.US, "mimeType='application/vnd.google-apps.folder' and '%s' in parents and name='%s' and trashed=false", parent == null ? "root" : parent.getId(), folderName);
String errorMsg = null;
try {
FileList result = _drive.files().list().setQ(q).setPageSize(1000).execute();
int foundCount = 0;
for (File file : result.getFiles()) {
foundCount++;
folder = file;
}
if (foundCount == 0) errorMsg = "Folder not found: " + folderName;
else if (foundCount > 1) errorMsg = "More than one folder found with name (" + foundCount + "): " + folderName;
}
catch (IOException e) { errorMsg = e.getLocalizedMessage(); }
if (errorMsg != null) folder = null;
return new FileAndErrorMsg(folder, errorMsg);
}

private FileListAndErrorMsg getFileListInFolder_b (File folder) {

// folder can be null for top level; does not return subfolder names
List<File> fileList = new ArrayList<File>();
String q = String.format(Locale.US, "mimeType != 'application/vnd.google-apps.folder' and '%s' in parents and trashed=false", folder == null ? "root" : folder.getId());
String errorMsg = null;
try {
String pageToken = null;
do {
FileList result = _drive.files().list().setQ(q).setPageSize(1000).setPageToken(pageToken).execute();
fileList.addAll(result.getFiles());
pageToken = result.getNextPageToken();
} while (pageToken != null);
}
catch (IOException e) { errorMsg = e.getLocalizedMessage(); }
if (errorMsg != null) fileList = null;
return new FileListAndErrorMsg(fileList, errorMsg);
}


// -------------------
// Misc
// -------------------

private void Log(String msg) {
Log.v("ept", msg);
}


// -------------------
// Load/Save Tokens
// -------------------


private void loadFromPrefs() {
SharedPreferences pref = _context.getSharedPreferences("prefs", Context.MODE_PRIVATE);
_loggedIn = pref.getBoolean("GoogleLoggedIn", false);
_refreshToken = pref.getString("GoogleRefreshToken", null);
}
private void saveToPrefs() {
SharedPreferences.Editor editor = _context.getSharedPreferences("prefs", Context.MODE_PRIVATE).edit();
editor.putBoolean("GoogleLoggedIn", _loggedIn);
editor.putString("GoogleRefreshToken", _refreshToken);
editor.apply(); // async

}

}

关于Android 应用程序 + 具有完整驱动器访问权限的 Drive API ... 程序是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41675630/

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