arrow left
Back to Developer Education

    Backup Services with Google Drive API in Android

    Backup Services with Google Drive API in Android

    Almost every Android app needs some form of cloud storage to save user's data. Google Drive is one of the cloud-based storage solutions. It works similarly to other cloud storage services in that it is used to augment storage capacity for important files that the user would want to recover in case they get lost. <!--more--> Google Drive synchronizes all documents, images, and other types of files across all of a user's devices, including mobile phones, tablets, and computers.

    Prerequisites

    To follow through this tutorial, you'll need:

    • A good understanding of Kotlin Coroutines and higher order functions.
    • An active Google account. If you don't have one, you can create one here.
    • To be familiar with Google sign in authentication.

    Getting Started

    To begin with, launch an Android project in which you have previously integrated Google sign-in authentication. If you don't have one already, you can create it by either following:

    Setting up the dependencies

    Open the app level build.gradle file and add the following dependencies:

    Kotlin Coroutines

    implementation ('org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3-native-mt')
    

    Google Drive API

    implementation('com.google.api-client:google-api-client-android:1.23.0')
    implementation('com.google.apis:google-api-services-drive:v3-rev136-1.25.0')
    

    Instantiating Google Drive

    To use Google Drive, we need to construct a Drive object. Drive is one of the Google Drive API classes. Its uses include uploading, downloading, searching, and adjusting Drive sharing rights.

    The procedures for creating a Drive instance using its builder is as follows:

    Step 1

    As mentioned earlier, we need a Google account authenticated using your Android App. We can then get the latest account using the getLastSignedInAccount function as shown below.

    GoogleSignIn.getLastSignedInAccount(this)?.let { googleAccount -> }
    

    Step 2

    To access the user's Google Drive contents, we need to build a GoogleAccountCredential that authenticates the signed-in account with DRIVE_FILE permissions. These permissions are used to decide whether or not a file may be accessed.

    val credential = GoogleAccountCredential.usingOAuth2(
        this, listOf(DriveScopes.DRIVE_FILE)
    )
    // select account
    credential.selectedAccount = googleAccount.account!!
    

    Step 3

    This is the final step when creating a Drive instance. Here, We need to construct the Drive service instance using its builder, passing AndroidHttp, JacksonFactory, and GoogleAccountCredential as arguments.

    We can combine the above steps into one function as shown below:

    private fun getDriveService(): Drive? {
        GoogleSignIn.getLastSignedInAccount(this)?.let { googleAccount ->
            val credential = GoogleAccountCredential.usingOAuth2(
                this, listOf(DriveScopes.DRIVE_FILE)
            )
            credential.selectedAccount = googleAccount.account!!
            return Drive.Builder(
                AndroidHttp.newCompatibleTransport(),
                JacksonFactory.getDefaultInstance(),
                credential
            )
                .setApplicationName(getString(R.string.app_name))
                .build()
        }
        return null
    }
    

    The above function returns a Drive instance if the user is signed in and has the DRIVE_FILE permissions. Otherwise, it returns null.

    How to access Google Drive's contents

    Now that we have a Drive instance, we can access the user's Google Drive contents. We have a method named files within the drive class which is used as an accessor for making requests from the file collections.

    Parameters of the files function

    1. q — is a request for sorting the file results.
    2. spaces — A list of storage locations where data is stored. Google Drive stores all materials in one of these three distinct categories: drive, appDataFolder, and pictures. We'll use drive in this context.
    3. fields — The data requested for each file, such as the id and name.

    The following code example shows how to access all files on the drive space:

    private fun accessDriveFiles() {
        getDriveService()?.let { googleDriveService ->
            CoroutineScope(Dispatchers.IO).launch {
                var pageToken: String?
                do {
                    val result = googleDriveService.files().list().apply {
                        spaces = "drive"
                        fields = "nextPageToken, files(id, name)"
                        pageToken = this.pageToken
                    }.execute()
    
                    result.files.forEach { file ->
                        Log.d("FILE", ("name=${file.name} id=${file.id}"))
                    }
                } while (pageToken != null)
            }
        }
    }
    

    Here we've used a coroutine scope to launch a coroutine that makes a request to the Google Drive API. The coroutine scope is used to ensure that the request job is executed in the background.

    The name and id of each file is printed on the logcat.

    How to upload a file to Google Drive

    This involves three steps.

    Step 1

    To start with, you need to construct an instance of the file you wish to upload from the local storage.

    val localFileDirectory = File(getExternalFilesDir("backup")!!.toURI())
    val actualFile = File("${localFileDirectory}/$FILE_NAME_BACKUP")
    

    Step 2

    Create the Google Drive file and replace the filename with the real file name.

    val gFile = com.google.api.services.drive.model.File()
    gFile.name = actualFile.name
    

    Step 3

    Create an instance of the FileContent comprising of the content and mime-type of the actual file then upload it as shown below.

    val fileContent = FileContent("text/plain", actualFile)
    googleDriveService.Files().create(gFile,fileContent).execute()
    

    Compiling this into one function, we have the following:

    fun uploadFileToGDrive() {
        getDriveService()?.let { googleDriveService ->
            CoroutineScope(Dispatchers.IO).launch {
                try {
                    val localFileDirectory = File(getExternalFilesDir("backup")!!.toURI())
                    val actualFile = File("${localFileDirectory}/FILE_NAME_BACKUP")
                    val gFile = com.google.api.services.drive.model.File()
                    gFile.name = actualFile.name
                    val fileContent = FileContent("text/plain", actualFile)
                    googleDriveService.Files().create(gFile, fileContent).execute()
                } catch (exception: Exception) {
                    exception.printStackTrace()
                }
            }
        } ?: Toast.makeText(this, "Please Log In first!", LENGTH_SHORT).show()
    }
    

    If the user is not signed in, the uploadFileToGDrive function will display a toast message.

    How to download a file from Google Drive

    To obtain a file from the Drive, you need to pass its id to the service's get() method and execute the request.

    fun downloadFileFromGDrive(id : String){
        getDriveService()?.let {googleDriveService->
            CoroutineScope(Dispatchers.IO).launch {
                googleDriveService.Files().get(id).execute()
            }
        } ?: Toast.makeText(this, "Please Log In first!", LENGTH_SHORT).show()
    }
    

    How to fix crashes when working with Google Drive API

    • Ensure that the user is signed in with an active Google account and has the DRIVE_FILE permission.
    • On the server-side, ensure that the file is not already present on the server.
    • On the client-side, ensure that the file is not already present in the local storage when downloading.

    Conclusion

    In this tutorial, we've covered the fundamental steps of accessing Google Drive API and using it to upload and download files from Google Drive. You can implement this knowledge in a more complicated project in your desired approach.

    For further reading, you can refer to the following links:

    Happy coding!


    Peer Review Contributions by: Eric Gacoki

    Published on: Aug 8, 2021
    Updated on: Jul 15, 2024
    CTA

    Start your journey with Cloudzilla

    With Cloudzilla, apps freely roam across a global cloud with unbeatable simplicity and cost efficiency