How to Auto-sync Google Drive API While Developing An Android App

In this Android app tutorial, we will learn how to auto-sync Google Drive API in order to let Android users access and download the files from Google Drive to an Android app.

This tutorial for Android Google Drive Sync is useful to those entrepreneurs who are looking to develop an android app for their own business & access all the data backed up with the help of Google Drive.

What is Google Drive?

Google Drive is a cloud-based storage service provided by Google. It is similar to other cloud storage services and is used to expand the storage capacity for keeping files beyond the limits of a hard drive. It syncs all stored documents, photos and many more files across a user’s device, including mobile devices, tablets and PCs.

How to Auto-sync google drive for backup

Google provides 15 GB of free cloud storage space to every user for signing up & creating a Gmail account. However, it’s necessary to know that all of this 15 GB free space is divided & shared between Gmail, Google Drive (Microsoft Office Docs, Presentations, Spreadsheet etc), Google Photos as well.

How Does it Work?

By signing up, a user can create a Google account which can be used to access Gmail, Google Play store, Google Drive, Google Photos and many other services. Once the google account is created, a user can log in into the account and access Google Drive from its menu to browse the stored files.

Benefits of Google Drive Sync

The main benefit of signing up for a google account and auto-sync google drive is that it can be accessed via the browser, on desktop and laptop or via smartphone also, which allows users to store & access data from anywhere as per their ease.

Google also provides the auto-sync features so that all the data of a user’s device can be automatically synced & uploaded to Google Drive without asking users for permission every time.

Moreover, accessing and storing data on the Google drive is much secure as all the data is encrypted and decrypted using 128-bit advanced encryption standard (AES) along with Transport Layer Security (TLS) standard when it goes from a user’s device and reaches to Google’s cloud storage.

Read Here: How to Use Android Wrap_Content

Want To Create An Android Application?

Looking to Create An Android app? Get in touch with our experienced Android app developers for a free consultation.

Cta Image

Let’s see How to Auto-sync Google Drive in Android

hand icon Create a new project in the Android Studio

create new project

hand icon Add package name & configuration

Select Package name
hand icon Create a new project in the Android Studio
hand icon Add dependencies in your build.gradle file which is an in-app module

add dependencies

implementation 'androidx.multidex:multidex:2.0.1'
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'
implementation('com.google.apis:google-api-services-drive:v3-rev136-1.25.0') {
    exclude group: 'com.google.guava'
}
Copy to Clipboard

hand icon also, add packagingOptions in android { }

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'
}
Copy to Clipboard

hand icon Create a new project in the Google API console

create new project in Google API console

hand icon Enable Google Drive API from APIs & Services -> Library -> Google Drive API

Enable Google Drive API

hand icon Add Application Name in OAuth consent screen

Add Application Name

hand icon Add scope -> /auth/drive.file

Add scope

hand icon Now Create Credentials from APIs & Services -> Credentials -> Create credentials -> Create OAuth client ID

Create API Credentials

Create OAuth client ID

hand icon just copy Client ID & Client Secret and paste to the string.xml file

Enter Client ID and Client Secret

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.spaceo.gdrivesyncdemo">

    <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" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:usesCleartextTraffic="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
    </application>
</manifest>
Copy to Clipboard

Activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center">

    <Button
        android:id="@+id/btnBackup"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Backup" />

    <Button
        android:id="@+id/btnRestore"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="24dp"
        android:text="Restore" />
</LinearLayout>
Copy to Clipboard

DriveServiceHelper.java

package com.spaceo.gdrivesyncdemo.util;
    import androidx.core.util.Pair;
    import com.google.android.gms.tasks.Task;
    import com.google.android.gms.tasks.Tasks;
    import com.google.api.client.http.InputStreamContent;
    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.*;
    import java.util.Collections;
    import java.util.concurrent.Executor;
    import java.util.concurrent.Executors;
    
    /**
     * A utility for performing read/write operations on Drive files via the REST API and opening a
     * file picker UI via Storage Access Framework.
     */
    public class DriveServiceHelper {
        private final Executor mExecutor = Executors.newSingleThreadExecutor();
        private final Drive mDriveService;
        public DriveServiceHelper(Drive driveService) {
            mDriveService = driveService;
        }
        public Task<String> uploadFile(String name, java.io.File fileTest) {
            return Tasks.call(mExecutor, () -> {
                File metadata = new File()
                        .setParents(Collections.singletonList("root"))
                        .setMimeType("text/plain")
                        .setName(name);
                InputStream targetStream = new FileInputStream(fileTest);
                InputStreamContent inputStreamContent = new
                InputStreamContent("text/plain", targetStream);
                File googleFile = mDriveService.files().create(metadata, 
                inputStreamContent).execute();
                if (googleFile == null) {
                    throw new IOException("Null result when requesting file creation.");
                }
                return googleFile.getId();
            });
        }
    
    /**
         * Opens the file identified by {@code fileId} and returns a {@link Pair} of its name and * contents. */
    
    public Task<Pair<String, String>> readFile(String fileId) {
            return Tasks.call(mExecutor, () -> {
                // Retrieve the metadata as a File object.
                File metadata = mDriveService.files().get(fileId).execute();
                String name = metadata.getName();
                // Stream the file contents to a String.
                try (InputStream is =
                 mDriveService.files().get(fileId).executeMediaAsInputStream();
                     BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
                    StringBuilder stringBuilder = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        stringBuilder.append(line);
                    }
                    String contents = stringBuilder.toString();
                    return Pair.create(name, contents);
                }
            });
        }
    
    /**
         * Returns a {@link FileList} containing all the visible files in the user's My Drive.
         *
         * <p>The returned list will only contain files visible to this app, i.e. those which were
         * created by this app. To perform operations on files not created by the app, the project must
         * request Drive Full Scope in the <a href="https://play.google.com/apps/publish">Google
         * Developer's Console</a> and be submitted to Google for verification.</p>
         */
    
    public Task<FileList> queryFiles() {
            return Tasks.call(mExecutor, () ->
                    mDriveService.files().list().setSpaces("drive").execute());
        }
    }
Copy to Clipboard

RunTimePermission.kt

package com.spaceo.gdrivesyncdemo.util

import android.content.pm.PackageManager
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat

open class RunTimePermission : AppCompatActivity() {

    private var callback: ((Boolean) -> Unit)? = null

    fun requestPermission(permissions: Array<String>, callback: (isGranted: Boolean) -> Unit) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            var granted = true
            for (permission in permissions) {
                if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                    granted = false
                    break
                }
            }
            if (granted) {
                callback(true)
            } else {
                this.callback = callback
                requestPermissions(permissions, Integer.MAX_VALUE)
            }
        } else callback(true)
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == Integer.MAX_VALUE) {
            var granted = true
            for (i in 0 until grantResults.size) {
                if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                    granted = false
                    break
                }
            }
            if (granted)
                callback?.invoke(true)
            else onDenied()
        }
    }

    private fun onDenied() {
        callback?.invoke(false)
    }
}
Copy to Clipboard

MainActivity.kt

package com.spaceo.gdrivesyncdemo
import android.content.Intent
import android.os.Bundle
import android.os.Environment
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInClient
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.android.gms.common.Scopes
import com.google.android.gms.common.api.Scope
import com.google.api.client.extensions.android.http.AndroidHttp
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential
import com.google.api.client.json.gson.GsonFactory
import com.google.api.services.drive.Drive
import com.google.api.services.drive.DriveScopes
import com.spaceo.gdrivesyncdemo.util.DriveServiceHelper
import com.spaceo.gdrivesyncdemo.util.RunTimePermission
import kotlinx.android.synthetic.main.activity_main.*
import java.io.File
import java.io.FileOutputStream
import java.io.FileWriter
import java.lang.StringBuilder
import java.util.*
import java.util.jar.Manifest
class MainActivity : RunTimePermission() {
    private val RQ_GOOGLE_SIGN_IN = 210
    private val BACKUP_FILE = "test.txt"
    private var isRestore = false
    private var mGoogleApiClient: GoogleSignInClient? = null
    private var mDriveServiceHelper: DriveServiceHelper? = null
    private var lastUploadFileId: String? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        btnBackup.setOnClickListener {
            requestPermission(arrayOf(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) { isGranted ->
                if (isGranted) {
                    isRestore = false
                    if (mDriveServiceHelper == null)
                        googleAuth()
                    else {
                        val uploadTask = mDriveServiceHelper?.uploadFile(BACKUP_FILE, generateFile())
                        uploadTask?.addOnCompleteListener {
                            lastUploadFileId = uploadTask.result
                            println("lastUploadFileId==>$lastUploadFileId")
                            Toast.makeText(this@MainActivity, "Backup upload successfully", Toast.LENGTH_LONG).show()
                        }
                    }
                }
            }
        }
        btnRestore.setOnClickListener {requestPermission(arrayOf(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) { isGranted ->
                if (isGranted) {
                    isRestore = true
                    if (mDriveServiceHelper == null)
                        googleAuth()
                    else {
                        if (null != lastUploadFileId) {
                            val downloadTask = mDriveServiceHelper?.readFile(lastUploadFileId)
                            downloadTask?.addOnCompleteListener {
                                println("Name==>${downloadTask.result?.first}")
                                println("Content==>${downloadTask.result?.second}")
                                Toast.makeText(this@MainActivity, "Backup download successfully", Toast.LENGTH_LONG)
                                    .show()
                            }
                        }
                    }
                }
            }
        }
    }
    private fun googleAuth() {
        val signInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestServerAuthCode(getString(R.string.web_client_id))
            .requestScopes(Scope(Scopes.PROFILE), Scope("https://www.googleapis.com/auth/drive.file"))
            .build()
        mGoogleApiClient = GoogleSignIn.getClient(this, signInOptions)
        startActivityForResult(mGoogleApiClient!!.signInIntent, RQ_GOOGLE_SIGN_IN)
    }
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == RQ_GOOGLE_SIGN_IN && resultCode == RESULT_OK) {
            val task = GoogleSignIn.getSignedInAccountFromIntent(data)
            task.addOnSuccessListener {
                val credential = GoogleAccountCredential.usingOAuth2(
                    this,
                    Collections.singleton(DriveScopes.DRIVE_FILE)
                )
                credential.selectedAccount = it.account
                val googleDriveService = Drive.Builder(
                    AndroidHttp.newCompatibleTransport(), GsonFactory(),
                    credential
                ).setApplicationName(getString(R.string.app_name)).build()
                mDriveServiceHelper = DriveServiceHelper(googleDriveService)
                if (isRestore) {
                    if (null != lastUploadFileId) {
                        val downloadTask = mDriveServiceHelper?.readFile(lastUploadFileId)
                        downloadTask?.addOnCompleteListener {
                            println("Name==>${downloadTask.result?.first}")
                            println("Content==>${downloadTask.result?.second}")
                            Toast.makeText(this@MainActivity, "Backup download successfully", Toast.LENGTH_LONG).show()
                        }
                    }
                } else {
                    val uploadTask = mDriveServiceHelper?.uploadFile(BACKUP_FILE, generateFile())
                    uploadTask?.addOnCompleteListener {
                        lastUploadFileId = uploadTask.result
                        println("lastUploadFileId==>$lastUploadFileId")
                        Toast.makeText(this@MainActivity, "Backup upload successfully", Toast.LENGTH_LONG).show()
                    }
                }
            }
        }
    }
    private fun generateFile(): File {
        Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).mkdir()
        val file = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), BACKUP_FILE)
        if (!file.exists())
            file.createNewFile()
        val data = StringBuilder()
        for (i in 0..50) {
            data.append("$i. First string is here to be written. First string is here to be written.")
        }
        val fileOutputStream = FileOutputStream(file, true)
        fileOutputStream.write(data.toString().toByteArray())
        return file
    }
    override fun onDestroy() {
        super.onDestroy()
        if (null != mGoogleApiClient)
            mGoogleApiClient!!.signOut()
    }
}
Copy to Clipboard

Conclusion

Using the above Google Drive Auto-sync example, we learned how to easily backup files from an Android device to Google Drive (Cloud backup) and also retrieve anytime. It also saves the memory on a mobile device as well as on Laptop, Desktop. You can get the source of this Android app tutorial from Github.

Moreover, if you are looking to create an android app and wish to add this functionality within the app, you can get in touch with us through below contact us form. One of our sales representatives will get back to you shortly. The consultation is absolutely free of cost.

Bhaval Patel

Written by

Bhaval Patel is a Director (Operations) at Space-O Technologies. He has 20+ years of experience helping startups and enterprises with custom software solutions to drive maximum results. Under his leadership, Space-O has won the 8th GESIA annual award for being the best mobile app development company. So far, he has validated more than 300 app ideas and successfully delivered 100 custom solutions using the technologies, such as Swift, Kotlin, React Native, Flutter, PHP, RoR, IoT, AI, NFC, AR/VR, Blockchain, NFT, and more.