有人可以为 Google Drive REST API v3 提供最新的 Android 指南吗?

Chr*_*sUK 16 rest android android-studio google-drive-android-api

我和其他许多人一直在努力设置 Google Drive REST API v3 以与 Android 应用程序一起使用。这主要是因为 Google 官方文档缺少适用于 Android 的正确快速入门指南,我们只能找到散布在周围的(过时和/或令人困惑的)信息碎片 - 但我们需要的是完整的最新指南面向初学者,让我们入门并运行,以便他们可以打开和编辑 Drive 上的文件,包括如何设置凭据、依赖项和清单。

所以我问是否有人愿意创建这样的指南,或者可以指出这样一个已经制作的指南 a) 与此处详述的最新版本的 Google Drive API REST v3 相关,b) 涵盖以上所有内容初学者需要开始的方面?

ArtOfWarfare在这里发布的指南绝对完美,正是我正在寻找的——但不幸的是,这些指南已经过时了几年。谁能提供本指南的最新版本?非常感谢你。

Ros*_*n S 26

在回答这个问题之前,我想让你知道我从这里得到了代码(https://ammar.lanui.online/integrate-google-drive-rest-api-on-android-app-bc4ddbd90820)和谷歌的文档对我帮助不大。所以这个解决方案来自我可用的有限资源。

我需要驱动器来从我的应用程序上传和下载文件。在驱动器中,我必须创建一个文件夹,我必须将文件从我的应用程序上传到该文件夹​​并将文件从该文件夹下载到我的设备。这段代码对我来说很好用。

我相信你一定已经完成了谷歌登录。如果您不这样做,请查看此视频 ( https://youtu.be/t-yZUqthDMM )。

要与 Drive API 交互,您需要为您的应用启用 Drive API 服务。您可以在 Google Developer Console 中执行此操作。

要启用 Drive API,请完成以下步骤:

转到 Google API 控制台。

  1. 选择一个项目。

  2. 在左侧边栏中,展开 APIs & auth 并选择 APIs。

  3. 在显示的可用 API 列表中,单击 Drive API 链接,然后单击启用 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'
} 
Run Code Online (Sandbox Code Playgroud)

在 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'
}
Run Code Online (Sandbox Code Playgroud)

在您的清单文件中,添加所需的权限

<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"/>
Run Code Online (Sandbox Code Playgroud)

在这里,我将下载的文件存储在外部存储中。所以这就是为什么我添加了外部存储读取和写入权限的原因

谷歌登录后,请求访问谷歌驱动器的权限。下面给出了它的代码。

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();

    }

}
Run Code Online (Sandbox Code Playgroud)

变量 ACCESS_DRIVE_SCOPE 和 SCOPE_EMAIL 是,

Scope ACCESS_DRIVE_SCOPE = new Scope(Scopes.DRIVE_FILE);
Scope SCOPE_EMAIL = new Scope(Scopes.EMAIL);
Run Code Online (Sandbox Code Playgroud)

获得许可并登录后,我们就有了 GoogleSignInAccount 对象。有了这个对象,创建一个GoogleAccountCredential的对象,我们可以从中生成一个Drive的对象。Drive 对象是我们在 Google Drive 之间进行通信所需要的。

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);
}
Run Code Online (Sandbox Code Playgroud)

在这里你可以看到我创建了一个 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;
        }
    });
}
}
Run Code Online (Sandbox Code Playgroud)

请记住,无论何时创建文件或文件夹或上传文件,驱动器都会为其提供唯一 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;
}
}
Run Code Online (Sandbox Code Playgroud)

从您的活动中,您必须调用这些方法。就像下面给出的代码一样。

创建文件夹

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());
            }
        });
}
Run Code Online (Sandbox Code Playgroud)

列出文件

public void listFilesInDrive(View view) {

Log.i(TAG, "Listing Files...");
new MyAsyncTask().execute();

}
Run Code Online (Sandbox Code Playgroud)

要列出文件,您不能从主线程执行此操作,因为这会导致死锁。您必须在 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());
    }
}
}
Run Code Online (Sandbox Code Playgroud)

上传文件

要将文件上传到 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);
}
}
Run Code Online (Sandbox Code Playgroud)

在活动结果中

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();
}
Run Code Online (Sandbox Code Playgroud)

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());
}

}
Run Code Online (Sandbox Code Playgroud)

下载文件

要下载文件,请指定文件的 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());
            }
        });
}
Run Code Online (Sandbox Code Playgroud)

删除文件。

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());
            }
        });
}
Run Code Online (Sandbox Code Playgroud)

我不是一个有经验的人。我发布此代码的原因是有人会发现它很有用,可以提出自己的更改并将其发布在这里。因为目前对于 Android 的 Drive Rest API 集成没有太多参考。

谢谢你。

  • 该答案应标记为正确。很好的解释,提供了开始使用 Google 云端硬盘所需的所有信息。谷歌的文档太糟糕了!!!! (3认同)
  • AsyncTask 从版本 30 开始已弃用 (2认同)
  • @NoorHossain 最简单的替代方案之一是使用线程。 (2认同)

Nym*_*412 2

我也需要那个。我设法从这些链接构建了一些可以工作但不是最佳的东西:

REST API v3 的 Google 指南

Google Github 演示项目,用于在弃用其他方法后迁移到 REST

REST API v3 的文档

我现在剩下的主要问题是找到文件/文件夹选择器。演示项目中的项目使用SAF,它不允许检索您选择的文件的 ID(哦!!!)