Press "Enter" to skip to content

Drive Android API Integration – Part 1

0

Sometimes, when developing an app, we may find useful to store some data in the cloud, so we can give our uses the ability to access such data on any device. While there are different options out there to achieve it, we will focus on the Drive Android API, that allows us to easily manipulate files and folders as well as sync them between devices and the cloud.

While writing this article I realized it started becoming large, so I decided to split it into two parts. This part will cover:

  • How to get an Android certificate from the Google API Console
  • How to implement Google Drive Android API Sign-in process
  • How to manipulate Drive files to
    • Query Drive files using different filters
    • Create and upload files to Drive backend
    • Move a Drive file to trash
  • How to use File Picker component

The second part will cover:

  • How to resolve conflicts when syncing data
  • How to monitor a Drive file/folder

As usual, you can find here a complete demo app that implements all the examples covered on both parts of this article.  

One of the benefits when using Drive Android API is that we can store the data like a local file storage, even when we are offline. To support offline cases, the API implements a sync engine that runs in the background. This engine is responsible to merge upstream and downstream changes when connection is back, as well as to resolve conflicts. See how it works:

Also, another Drive Android API advantage is that since it is part of the Google Play services client library, we do not need to compile our app using any other library in order to access the Drive service, and this significantly reduces the installed size of Drive-enabled apps. You can find here a short but useful video and here an article from the same author that explain some features of the Drive Android API.

First Steps

Before we begin developing our Drive application, we need to register it on the Google API Console. To do that, there are some steps we need to perform, as follow:

  • get the fingerprint for the .apk
  • register the application in the Google API Console
  • get an Android certificate from the Google API Console
  • configure the certificate on the app

The first thing to do is getting the SHA1 fingerprint for .apk file’s public certificate. On your machine, open a terminal and run the Keytool utility like this:

After that, go to the Google API Console and register your application by setting up a project and the application (you’ll also need to inform your app package name). You may find Google API Console really easy to use, since it guides you through the entire process. Then, copy the SHA1 fingerprint you got from the console (in the previous step), and past it in the appropriate field in the Google API Console. Now, click on the generate button and a Client ID will be generated (note the button’s name may be different).

Then, copy the just generated Client ID and past it in your app’s manifest file:

For a detailed explanation about the registration process, check this and this links.

Along the registration process, there are two more steps you must perform:

  • Download the Google Play Services SDKs (you can find it here.)
  • Add Google Play Services Dependencies in build.gradle file as shown below:

Google Drive Android API Sign-in Process

Now that we already setup our environment accordingly, we can start the sign-in process. This involves connecting and authorizing Drive Android API.

We first define the authentication scopes we want to use and pass it to the  GoogleSignIn::getLastSignedInAccount() method that returns the last account that the user signed in with. If user has never signed in before or has signed out / revoked access, null is returned. But if an account is returned (i.e. a GoogleSignInAccount instance), we need to check whether it contains all the scopes we want to use. In case it does, we can then create an instance of the DriveClient and DriveResourceClient classes, which allow us to access the contents of the user’s Drive.

If none account is found (i.e. getLastSignedInAccount returns null), we need to proceed the sign-in process. Basically we first need to build a GoogleSignInOptions object informing all the scopes we want to use and build a GoogleSignInClient by calling GoogleSignIn::getClient() method with the options just built. Then, just call startActivityForResult by using the intent returned by GoogleSignInClient::getSignInIntent() in order to start the Google Sign-In flow.

After user chooses an account and authorize it, onActivityResult is called and we can call GoogleSignIn.getSignedInAccountFromIntent() in order to get the account for the current user (actually it returns a task, but we can access the account from it) and also create an instance of the DriveClient and DriveResourceClient classes.

This process may look complicated at first glance, but after you read the code, you may understand it and things may become clear.

Note: A nice feature of Drive API is that in case of errors when creating a DriveClient and DriveResourceClient instances, error resolutions are automatically launched from the provided Activity, displaying UI when necessary.

It might worth to take a look in the GoogleSignIn and GoogleSignInClient APIs documentation. The former contains methods to create a GoogleSignInClient object as well as to manage user permissions and the latter contains methods to manage user accounts (e.g. sign out, revoke access, etc).

Now we are signed In to the Drive API and ready to start using it.

Drive Files Manipulation

The Google Drive Android API provides abstractions for managing file content and metadata. Files are represented by the DriveFile interface and folders by the DriveFolder interface. Both share a common superinterface, DriveResource, which contains a DriveId. This is the unique identifier for all files and folders. The API also includes a package for querying for files based on metadata attributes, such as the title, etc.

When we want to manipulate Drive files or folders, we need to use DriveResourceClient API. DriveResourceClient is the contract for any DriveResource and provides several methods for manipulating such resources.

Next steps will show you on how to query, create and move a file to trash.

Querying Drive Files

Drive API provides a Query object that can be used for querying for files. When creating an instance of a Query object, we can specify the search criteria by using Filters factory class.

For example, if we want to search for a specific file named “MyFile.txt”, we can create a query like this:

Once a Query object has been build, we must call DriveResourceClient.query() method that returns a task object. Query method is executed on the Drive root folder (My Drive) and recursively traverses the entire filesystem.

If we want a query to be executed only in a specific folder, we must use DriveResourceClient.queryChildren() instead.

In case we need multiple filters when building a query, we can use the Filters class to build expressions by joining multiple filters together using “and” and “or” methods.

After finishing using the query result, we must call release().

We can also sort the result of a query. To do that, we need to build a SortOrder object and inform whether we want an ascending or descending order as well a SortableField (by title, creation date, modification date, etc). Then, when building a query, we call Query.Builder.setSortOrder() method to inform the sort order we want to use.

You can find below some snippets that show some different filters we can use when querying for files:

Text file filter

Files other than text files

Using multiple filters

Files that contain a specific letter on the name

Creating Files on Drive

If we want to create a file programmatically, we must use DriveResourceClient::createFile() method that creates the new file in the folder that we pass in as an argument. We can also inform the initial content and metadata. If we want to create an empty file, just pass null in place of DriveContents value.

The snippet below shows how to create a random text file named “Text_File_XX”, where XX is a number between 1 and 200.  The file will be create on the root folder. Then it writes a short content to the file by using an OutputStreamWriter instance. It also marks the file as starred. We can set all these metadata when building a MetadataChangeSet object. The last step is to call DriveResourceClient::createFile() so that the file can be created.

One thing that might worth to note is that even when createFile() method fires addOnSuccessListener callback, it only means the file was created in the Drive client. Later, when the file was really created in the Drive backend, we can request Drive API to send us an event. In order to receive this event, we need to create an ExecutionOptions object and call its setNotifyOnCompletion method with the value true. Then pass the ExecutionOptions object to the createFile method. When the file is created on the server, Drive API fires a CompletionEvent.STATUS_SUCCESS event.

To receive a CompletionEvent, we must create a service extending the DriveEventService and override its onCompletion method, where we can handle the CompletionEvent.

We need also to define our DriveEventService in the AndroidManifest.xml file as shown below:

That is it. Now we can ensure our file was created on the server when receiving a Completition event.

If we want to upload a local file to the Drive, the process is similar when creating a file, since for the drive, this is just a matter a file creation. This means we can follow the process discussed previously. In case we want our user to select a local file to be uploaded, just create an ACTION_VIEW intent and start it.

In the demo app you will find an example that allows user to choose an image from the local storage and upload it to the Drive.

Moving a file to trash

Ok, now we know how to query for files, folders, how to create and upload a file to Drive. But what if we want to remove a file by moving it to the trash? Well, it is quite simple. Basically we need the Metadata for the file we want to remove and call DriveResourceClient::trash() passing a DriveResource associated to the file. That is it.

File Picker Component

This section shows how to use the Drive File Picker componentThe file picker is one of the user interface component introduced by the Drive API and it is implemented by using the standard Intent mechanism, so we can easily integrate it on our app.

Basically, if we want our user to select a file, all we have to do is to call DriveClient::newOpenFileActivityIntentSender(). In case we want our user to create a new file, just call DriveClient::newCreateFileActivityIntentSender() method (we will not cover file creation by using file picker component since we already demonstrated how to do it by using DriveResourceClient::createFile()  method).

newOpenFileActivityIntentSender() method creates an intent that opens up the file activity builder. When the intent is fired (by calling startIntentSenderForResult method) , user is able to select a file in the file picker. After that, the result is available in the onActivityResult callback. The DriveId for file user chosen can be retrieved via the extra EXTRA_RESPONSE_DRIVE_ID.

Note that  newOpenFileActivityIntentSender() method accepts an OpenFileActivityOptions object that can used to configure settings for the open file dialog activity. Using it, search results can be filtered for a faster experience and more narrow results. See activity builder section on the Drive docs for details.

The snippet below shows the user Drive’s file open dialog by filtering results only for text files. You can change the mime type to add any filter you need.

Now, see how onActivityResult should look like if we just want to open the file that user has chosen:

If instead of opening a file, we want to retrieve the file metadata, we must call DriveResourceClient::getMetadata() method inside onActivityResult() which returns a Metadata object. In case of a successful response, we can do whatever we want with the response. The snippet below shows the user a dialog with the file metadata.

Probably the two examples we demonstrated above gave you an idea on how to work with file picker. On the demo app, besides these examples, it implements how to pin/unpin a file, how to retrieve a file content as well as how to count the number of files in a folder. You may notice how easy is to implement any feature by using file picker component.

Conclusion

While Android provides a Storage Access Framework that can work with many storage technologies, including Drive storage, Drive Android API, as the name implies is specific for Drive platform, and it contains specific features that can make our lives really easy. So, if you plan to add Drive features to your app, it may worth to consider using Drive Android API.

As you could see, Drive Android API provides several features that allows us to manipulate files and folder in an easy way. We based this article (and also the second part) in some official Drive documentations as well as in a Suite Android Demo provided by GSuiteDevs and I really recommend you to take a look on them. 

Next part will cover conflicts resolution when syncing data as well as how to monitor a file/folder. For this last topic, we will present some issues we found when dealing with file monitoring by using Drive Android API.

Stay tuned!