我自己和其他许多人都在努力设置Google Drive REST API v3以与Android应用程序一起使用。这主要是由于以下事实:Google官方文档缺少适用于Android的正确的快速入门指南,而我们只剩下一些零碎的(过时和/或令人困惑的)信息,但我们需要的是 complete < / strong>针对初学者的最新指南,以帮助我们入门和运行,以便他们可以在自己的云端硬盘上打开和编辑文件,包括如何设置凭据,依赖项和清单。
因此,我要问的是,是否有人愿意创建这样的指南,或者可以指向已经制定的与a)与最新版Google Drive API REST v3有关的详细指南,{{3} }和b)涵盖了以上所有方面,这些都需要初学者开始?
ArtOfWarfare here发布的指南绝对是 perfect ,完全符合我的要求-但不幸的是过时了几年。任何人都可以提供本指南的最新版本吗?谢谢。
答案 0 :(得分:2)
在回答这个问题之前,我想让您知道我从这里获得了代码(https://ammar.lanui.online/integrate-google-drive-rest-api-on-android-app-bc4ddbd90820),而Google的文档对我没有太大帮助。因此,此解决方案来自我可用的有限资源。
我需要驱动器才能从我的应用程序上载和下载文件。在驱动器中,我必须创建一个文件夹,并且必须将文件从我的应用程序上传到该文件夹,然后将文件从该文件夹下载到我的设备。这段代码对我来说很好用。
我相信您必须已完成Google登录。如果您不喜欢,请签出此视频(https://youtu.be/t-yZUqthDMM)。
要与Drive API进行交互,您需要为您的应用启用Drive API服务。您可以在Google Developer Console中进行此操作。
要启用Drive API,请完成以下步骤:
转到Google API控制台。
选择一个项目。
在左侧的边栏中,展开API和身份验证,然后选择API。
在显示的可用API列表中,单击Drive API链接,然后单击Enable API。
完成后,进入控制台的OAuth同意屏幕,添加两个驱动器范围并保存。
在您的项目中添加以下依赖项。
implementation 'com.google.android.gms:play-services-auth:17.0.0'// for google sign in
// for drive integration
implementation 'com.google.android.gms:play-services-auth:16.0.1'
implementation 'com.google.http-client:google-http-client-gson:1.26.0'
implementation('com.google.api-client:google-api-client-android:1.26.0') {
exclude group: 'org.apache.httpcomponents'
}
implementation('com.google.apis:google-api-services-drive:v3-rev136-1.25.0')
{
exclude group: 'org.apache.httpcomponents'
}
在android标签中的同一gradle文件中,添加打包选项。
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/notice.txt'
exclude 'META-INF/ASL2.0'
}
在清单文件中,添加所需的权限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
在这里,我将下载的文件存储在外部存储中。这就是为什么我添加了对外部存储设备READ和WRITE的权限
Google登录后,请获得访问Google云端硬盘的权限。其代码如下。
private void checkForGooglePermissions() {
if (!GoogleSignIn.hasPermissions(
GoogleSignIn.getLastSignedInAccount(getApplicationContext()),
ACCESS_DRIVE_SCOPE,
SCOPE_EMAIL)) {
GoogleSignIn.requestPermissions(
MainActivity.this,
RC_AUTHORIZE_DRIVE,
GoogleSignIn.getLastSignedInAccount(getApplicationContext()),
ACCESS_DRIVE_SCOPE,
SCOPE_EMAIL);
} else {
Toast.makeText(this, "Permission to access Drive and Email has been granted", Toast.LENGTH_SHORT).show();
driveSetUp();
}
}
变量ACCESS_DRIVE_SCOPE和SCOPE_EMAIL是
Scope ACCESS_DRIVE_SCOPE = new Scope(Scopes.DRIVE_FILE);
Scope SCOPE_EMAIL = new Scope(Scopes.EMAIL);
获得许可并登录后,我们就有了GoogleSignInAccount对象。使用该对象,创建一个GoogleAccountCredential对象,我们可以从中生成Drive对象。云端硬盘对象是我们在Google云端硬盘之间进行通信所需的对象。
private void driveSetUp() {
GoogleSignInAccount mAccount = GoogleSignIn.getLastSignedInAccount(MainActivity.this);
GoogleAccountCredential credential =
GoogleAccountCredential.usingOAuth2(
getApplicationContext(), Collections.singleton(Scopes.DRIVE_FILE));
credential.setSelectedAccount(mAccount.getAccount());
googleDriveService =
new com.google.api.services.drive.Drive.Builder(
AndroidHttp.newCompatibleTransport(),
new GsonFactory(),
credential)
.setApplicationName("GoogleDriveIntegration 3")
.build();
mDriveServiceHelper = new DriveServiceHelper(googleDriveService);
}
在这里您可以看到我创建了DriveServiceHelper类的对象,并随同传递了Drive(googleDriveSrvice)的对象。 DriveServiceHelper类在下面给出。我是从这里得到的。(https://github.com/gsuitedevs/android-samples/blob/master/drive/deprecation/app/src/main/java/com/google/android/gms/drive/sample/driveapimigration/DriveServiceHelper.java?source=post_page-----bc4ddbd90820----------------------)。您可以使用那个。我为自己上了那堂课。
public class DriveServiceHelper {
private final Executor mExecutor = Executors.newSingleThreadExecutor();
private final Drive mDriveService;
private final String TAG = "DRIVE_TAG";
public DriveServiceHelper(Drive driveService) {
mDriveService = driveService;
}
/**
* Creates a text file in the user's My Drive folder and returns its file ID.
*/
public Task<GoogleDriveFileHolder> createFile(String folderId, String filename) {
return Tasks.call(mExecutor, () -> {
GoogleDriveFileHolder googleDriveFileHolder = new GoogleDriveFileHolder();
List<String> root;
if (folderId == null) {
root = Collections.singletonList("root");
} else {
root = Collections.singletonList(folderId);
}
File metadata = new File()
.setParents(root)
.setMimeType("text/plain")
.setName(filename);
File googleFile = mDriveService.files().create(metadata).execute();
if (googleFile == null) {
throw new IOException("Null result when requesting file creation.");
}
googleDriveFileHolder.setId(googleFile.getId());
return googleDriveFileHolder;
});
}
// TO CREATE A FOLDER
public Task<GoogleDriveFileHolder> createFolder(String folderName, @Nullable String folderId) {
return Tasks.call(mExecutor, () -> {
GoogleDriveFileHolder googleDriveFileHolder = new GoogleDriveFileHolder();
List<String> root;
if (folderId == null) {
root = Collections.singletonList("root");
} else {
root = Collections.singletonList(folderId);
}
File metadata = new File()
.setParents(root)
.setMimeType("application/vnd.google-apps.folder")
.setName(folderName);
File googleFile = mDriveService.files().create(metadata).execute();
if (googleFile == null) {
throw new IOException("Null result when requesting file creation.");
}
googleDriveFileHolder.setId(googleFile.getId());
return googleDriveFileHolder;
});
}
public Task<Void> downloadFile(java.io.File targetFile, String fileId) {
return Tasks.call(mExecutor, () -> {
// Retrieve the metadata as a File object.
OutputStream outputStream = new FileOutputStream(targetFile);
mDriveService.files().get(fileId).executeMediaAndDownloadTo(outputStream);
return null;
});
}
public Task<Void> deleteFolderFile(String fileId) {
return Tasks.call(mExecutor, () -> {
// Retrieve the metadata as a File object.
if (fileId != null) {
mDriveService.files().delete(fileId).execute();
}
return null;
});
}
// TO LIST FILES
public List<File> listDriveImageFiles() throws IOException{
FileList result;
String pageToken = null;
do {
result = mDriveService.files().list()
/*.setQ("mimeType='image/png' or mimeType='text/plain'")This si to list both image and text files. Mind the type of image(png or jpeg).setQ("mimeType='image/png' or mimeType='text/plain'") */
.setSpaces("drive")
.setFields("nextPageToken, files(id, name)")
.setPageToken(pageToken)
.execute();
pageToken = result.getNextPageToken();
} while (pageToken != null);
return result.getFiles();
}
// TO UPLOAD A FILE ONTO DRIVE
public Task<GoogleDriveFileHolder> uploadFile(final java.io.File localFile,
final String mimeType, @Nullable final String folderId) {
return Tasks.call(mExecutor, new Callable<GoogleDriveFileHolder>() {
@Override
public GoogleDriveFileHolder call() throws Exception {
// Retrieve the metadata as a File object.
List<String> root;
if (folderId == null) {
root = Collections.singletonList("root");
} else {
root = Collections.singletonList(folderId);
}
File metadata = new File()
.setParents(root)
.setMimeType(mimeType)
.setName(localFile.getName());
FileContent fileContent = new FileContent(mimeType, localFile);
File fileMeta = mDriveService.files().create(metadata,
fileContent).execute();
GoogleDriveFileHolder googleDriveFileHolder = new
GoogleDriveFileHolder();
googleDriveFileHolder.setId(fileMeta.getId());
googleDriveFileHolder.setName(fileMeta.getName());
return googleDriveFileHolder;
}
});
}
}
请记住以下事实:无论何时创建文件或文件夹,或者上传文件,驱动器都会为其提供唯一的ID,并且您可以访问它。因此,这里不是唯一的文件名,而是文件的ID。因此,如果您多次上传或创建相同名称的文件,它将多次保存在文件夹中。因此,如果要用另一个同名文件替换文件。首先删除文件并保存/上传。 要创建文件,请指定要创建的文件夹ID和文件名。
下面给出了GoogleDriveHolder类。
public class GoogleDriveFileHolder {
private String id;
private String name;
private DateTime modifiedTime;
private long size;
private DateTime createdTime;
private Boolean starred;
public DateTime getCreatedTime() {
return createdTime;
}
public void setCreatedTime(DateTime createdTime) {
this.createdTime = createdTime;
}
public Boolean getStarred() {
return starred;
}
public void setStarred(Boolean starred) {
this.starred = starred;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public DateTime getModifiedTime() {
return modifiedTime;
}
public void setModifiedTime(DateTime modifiedTime) {
this.modifiedTime = modifiedTime;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
}
必须从您的活动中调用这些方法。就像下面给出的代码一样。
创建文件夹
public void createFolderInDrive(View view) {
Log.i(TAG, "Creating a Folder...");
mDriveServiceHelper.createFolder("My Foder", null)
.addOnSuccessListener(new OnSuccessListener<GoogleDriveFileHolder>() {
@Override
public void onSuccess(GoogleDriveFileHolder googleDriveFileHolder) {
Gson gson = new Gson();
Log.i(TAG, "onSuccess of Folder creation: " + gson.toJson(googleDriveFileHolder));
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.i(TAG, "onFailure of Folder creation: " + e.getMessage());
}
});
}
列出文件
public void listFilesInDrive(View view) {
Log.i(TAG, "Listing Files...");
new MyAsyncTask().execute();
}
要列出文件,您不能在主线程中进行操作,因为这会导致死锁。您必须在Asynctask的doInBackground()方法中执行此操作。这是我的课。
public class MyAsyncTask extends AsyncTask<Void, Void, List<File>> {
List<File> fileList;
@Override
protected List<File> doInBackground(Void... voids) {
try {
fileList = mDriveServiceHelper.listDriveImageFiles();
} catch (IOException e) {
Log.i(TAG, "IO Exception while fetching file list");
}
return fileList;
}
@Override
protected void onPostExecute(List<File> files) {
super.onPostExecute(files);
if (files.size() == 0){
Log.i(TAG, "No Files");
}
for (File file : files) {
Log.i(TAG, "\nFound file: File Name :" +
file.getName() + " File Id :" + file.getId());
}
}
}
上传文件
要将文件上传到Drive文件夹,请指定文件夹ID,要上传的文件的mime类型以及文件本身。 在这里,我从图库中选择一个图像并将其上传到驱动器中。
public void uploadFile(View view) {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PICK_IMAGE);
} else {
Intent i = new Intent(
Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, RESULT_LOAD_IMAGE);
}
}
在onActivityResult中
else if (requestCode == RESULT_LOAD_IMAGE) {
if (resultCode == RESULT_OK) {
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
uploadImageIntoDrive(BitmapFactory.decodeFile(picturePath));
} else {
Toast.makeText(this, "Did not select any image", Toast.LENGTH_SHORT).show();
}
uploadImageIntoDrive()方法,
private void uploadImageIntoDrive(Bitmap bitmap) {
try {
if (bitmap == null) {
Log.i(TAG, "Bitmap is null");
return;
}
java.io.File file = new java.io.File(getApplicationContext().getFilesDir(), "FirstFile");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
byte[] bitmapdata = bos.toByteArray();
//write the bytes in file
FileOutputStream fos = new FileOutputStream(file);
fos.write(bitmapdata);
fos.flush();
fos.close();
mDriveServiceHelper.uploadFile(file, "image/jpeg", "MY_FOLDER_ID")
.addOnSuccessListener(new OnSuccessListener<GoogleDriveFileHolder>() {
@Override
public void onSuccess(GoogleDriveFileHolder googleDriveFileHolder) {
Log.i(TAG, "Successfully Uploaded. File Id :" + googleDriveFileHolder.getId());
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.i(TAG, "Failed to Upload. File Id :" + e.getMessage());
}
});
} catch (Exception e) {
Log.i(TAG, "Exception : " + e.getMessage());
}
}
要下载文件
要下载文件,请指定文件ID和下载文件必须存储到的目标文件。
public void downloadFile(View view) {
java.io.File file = new java.io.File(getExternalFilesDir(null), "DemoFile2.jpg");
mDriveServiceHelper.downloadFile(file, "MY_FILE_ID")
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.i(TAG, "Downloaded the file");
long file_size = file.length() / 1024;
Log.i(TAG, "file Size :" + file_size);
Log.i(TAG, "file Path :" + file.getAbsolutePath());
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.i(TAG, "Failed to Download the file, Exception :" + e.getMessage());
}
});
}
要删除文件。
public void deleteFile(View view) {
mDriveServiceHelper.deleteFolderFile("MY_FILE_OR_FOLDER_ID")
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.i(TAG, "onSuccess of Deleting File ");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.i(TAG, "onFailure on Deleting File Exception : " + e.getMessage());
}
});
}
我不是一个有经验的人。我发布此代码的原因是有人会发现它有用,并且可以提出自己的更改并将其发布在此处。因为目前没有太多关于Android的Drive Rest API集成的参考。
谢谢。
答案 1 :(得分:0)
我也需要。我设法从这些链接中构建出了虽然不是最佳的东西,但效果仍然不错:
Google Github demo project for migration to REST after deprecation of the other method
我现在剩下的主要问题是找到文件/文件夹选择器。演示项目中的一个使用SAF,其中does not allow to retrieve the ID of the file you picked(噢!)
答案 2 :(得分:0)
我在尝试弄清楚如何使用Drive REST API时所提到的文章是on this page
我刚接触Android,但是这是我获取文件ID列表的方法。希望这对您有帮助
创建一个返回文件列表的方法(不要将它们与java.io.Files混合使用)。
它们是com.google.api.services.drive.model.File;
的实例
下面的方法是github上的弃用教程中DriveServiceHelper类的一部分。检查源文件以查看如何创建mExecutor和mDriveService实例
public Task<FileList> queryFiles() {
return Tasks.call(mExecutor, () ->
mDriveService.files().list().setSpaces("drive").execute());
}
然后您可以遍历列表并获取每个文件的ID
for (File file : fileList.getFiles()) {
file.getId()
}
获得ID后,您可以删除或更新文件 这是一个删除方法的示例,该方法可在您每次上传到Google驱动器时删除您的应用会创建的重复文件:
private void mQuery(String name) {
if (mDriveServiceHelper != null) {
Log.d(TAG, "Querying for files.");
mDriveServiceHelper.queryFiles()
.addOnSuccessListener(fileList -> {
for (File file : fileList.getFiles()) {
if(file.getName().equals(name))
mDriveServiceHelper.deleteFolderFile(file.getId()).addOnSuccessListener(v-> Log.d(TAG, "removed file "+file.getName())).
addOnFailureListener(v-> Log.d(TAG, "File was not removed: "+file.getName()));
}
})
.addOnFailureListener(exception -> Log.e(TAG, "Unable to query files.", exception));
}
}
这是DriveServiceHelper类中的deleteFolderFile方法
public Task<Void> deleteFolderFile(String fileId) {
return Tasks.call(mExecutor, () -> {
// Retrieve the metadata as a File object.
if (fileId != null) {
mDriveService.files().delete(fileId).execute();
}
return null;
});
}
NB!如果您需要对大量文件执行查询,这不是最佳方法。这只是一个草案,可以帮助您获得想法。通过使用二进制搜索算法在列表中查找特定文件,至少可以改善mQuery func。
答案 3 :(得分:0)
我创建了一个项目,其中使用“Android Google DRIVE API V3”在其中创建文件夹、上传文件、删除文件和下载文件功能。 带有代码的完整 android 应用程序位于 https://github.com/prateekbangre/GoogleDrive_demo
文件夹是否存在:
public Task<String> isFolderPresent() {
return Tasks.call(mExecutor, () -> {
FileList result = mDriveService.files().list().setQ("mimeType='application/vnd.google-apps.folder' and trashed=false").execute();
for (File file : result.getFiles()) {
if (file.getName().equals(FOLDER_NAME))
return file.getId();
}
return "";
});
}
创建文件夹:
public Task<String> createFolder() {
return Tasks.call(mExecutor, () -> {
File metadata = new File()
.setParents(Collections.singletonList("root"))
.setMimeType(FOLDER_MIME_TYPE)
.setName(FOLDER_NAME);
File googleFolder = mDriveService.files().create(metadata).execute();
if (googleFolder == null) {
throw new IOException("Null result when requesting Folder creation.");
}
return googleFolder.getId();
});
}
获取文件列表:
public Task<ArrayList<GoogleDriveFileHolder>> getFolderFileList() {
ArrayList<GoogleDriveFileHolder> fileList = new ArrayList<>();
if (folderId.isEmpty()){
Log.e(TAG, "getFolderFileList: folder id not present" );
isFolderPresent().addOnSuccessListener(id -> folderId=id)
.addOnFailureListener(exception -> Log.e(TAG, "Couldn't create file.", exception));
}
return Tasks.call(mExecutor, () -> {
FileList result = mDriveService.files().list()
.setQ("mimeType = '" + SHEET_MIME_TYPE + "' and trashed=false and parents = '" + folderId + "' ")
.setSpaces("drive")
.execute();
for (int i = 0; i < result.getFiles().size(); i++) {
GoogleDriveFileHolder googleDriveFileHolder = new GoogleDriveFileHolder();
googleDriveFileHolder.setId(result.getFiles().get(i).getId());
googleDriveFileHolder.setName(result.getFiles().get(i).getName());
fileList.add(googleDriveFileHolder);
}
Log.e(TAG, "getFolderFileList: folderFiles: "+fileList );
return fileList;
});
}
上传文件到谷歌驱动器:
public Task<Boolean> uploadFileToGoogleDrive(String path) {
if (folderId.isEmpty()){
Log.e(TAG, "uploadFileToGoogleDrive: folder id not present" );
isFolderPresent().addOnSuccessListener(id -> folderId=id)
.addOnFailureListener(exception -> Log.e(TAG, "Couldn't create file.", exception));
}
return Tasks.call(mExecutor, () -> {
Log.e(TAG, "uploadFileToGoogleDrive: path: "+path );
java.io.File filePath = new java.io.File(path);
File fileMetadata = new File();
fileMetadata.setName(filePath.getName());
fileMetadata.setParents(Collections.singletonList(folderId));
fileMetadata.setMimeType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
FileContent mediaContent = new FileContent("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", filePath);
File file = mDriveService.files().create(fileMetadata, mediaContent)
.setFields("id")
.execute();
System.out.println("File ID: " + file.getId());
return false;
});
}
从谷歌驱动器下载文件:
public Task<Boolean> downloadFile(final java.io.File fileSaveLocation, final String fileId) {
return Tasks.call(mExecutor, new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
// Retrieve the metadata as a File object.
OutputStream outputStream = new FileOutputStream(fileSaveLocation);
mDriveService.files().get(fileId).executeMediaAndDownloadTo(outputStream);
return true;
}
});
}
删除文件:
public Task<Boolean> deleteFolderFile(final String fileId) {
return Tasks.call(mExecutor, new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
// Retrieve the metadata as a File object.
if (fileId != null) {
mDriveService.files().delete(fileId).execute();
return true;
}
return false;
}
});
}
以上是相同的代码示例。
答案 4 :(得分:0)
我想下载我创建的文件夹中的所有文件,我使用 mime 类型作为文本/纯文本,但我有视频、音频和所有类型的文件,如果我使用 "mimeType = '" + "/< /em>" 然后不显示文件。该怎么办 ?此处对所有文件使用什么 MIME 类型?
public static Task<ArrayList<GoogleDriveFileHolder>> getFolderFileList() {
ArrayList<GoogleDriveFileHolder> fileList = new ArrayList<>();
return Tasks.call(mExecutor, () -> {
FileList result = mDriveService.files().list()
.setQ("mimeType = '" + "text/plain" +
"" + "' and trashed=false and parents = '" + "1lRlWrKKp4onqZe3-0anExm_yd1yWoPjR" + "' ")
.setSpaces("drive")
.execute();
for (int i = 0; i < result.getFiles().size(); i++) {
GoogleDriveFileHolder googleDriveFileHolder = new GoogleDriveFileHolder();
googleDriveFileHolder.setId(result.getFiles().get(i).getId());
googleDriveFileHolder.setName(result.getFiles().get(i).getName());
fileList.add(googleDriveFileHolder);
}
Log.e("TAG", "getFolderFileList: folderFiles: "+fileList );
return fileList;
});
}