How to Auto-sync Google Drive For Backup & Retrieve Files While Developing An Android App (Tutorial)

sync-google-drive

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.

Auto-sync google drive

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.

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

Step 1: Create a new project in the Android Studio

create-new-project

Add package name & configuration

Select-Package-name

Step 2: 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' 
}

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' 
}


Step 3:
Create a new project in the Google API console

create-new-project-in-Google-API-console

 

Step 4: Enable Google Drive API from APIs & Services -> Library -> Google Drive API

Enable-Google-Drive-API


Step 5:
Add Application Name in OAuth consent screen

Add-Application-Name


Step 6:
Add scope -> /auth/drive.file

Add-scope

 

Step 7: Now Create Credentials from APIs & Services -> Credentials -> Create credentials -> Create OAuth client ID

Create-API-Credentials

 

Create-OAuth-client-ID

Step 8: 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>


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:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Backup"
            android:id="@+id/btnBackup"
            android:layout_gravity="center"/>
    <Button android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Restore"
            android:layout_marginTop="24dp"
            android:id="@+id/btnRestore"
            android:layout_gravity="center"/>
</LinearLayout>


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


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

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


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.

 
 

Have an App Idea?

Get your free consultation now

Leave a Reply

Your email address will not be published. Required fields are marked *