android google drive How-tos Kotlin Other Android Tutorials Tech tutorial

Integrating Google Drive in Android

Integrating Google Drive in Android

Integrating Google Drive in Android

There are occasions when a consumer is required to decide on a file to add into an app. There are numerous locations from which to add information: native storage on the gadget, Dropbox, Google Drive and different providers. On this tutorial, you’ll create an app that may authenticate a consumer with Google, launch Google Drive, after which permit a consumer to decide on a file. As soon as the consumer selects a file, the app will obtain and open it.

The Google Drive SDK is used to hook up with a consumer’s Google Drive information. This tutorial will concentrate on permitting a consumer to decide on an present file, obtain it and show it by means of the app. You’ll use Google Drive’s built-in file picker, which can permit us to decide on any file that’s on the consumer’s Google drive.

Notice: Should you’re new to Android improvement or the Kotlin language, it’s extremely beneficial that you simply begin with Starting Android Improvement with Kotlin to study your means across the primary instruments and ideas.

Getting Began

Be sure to have Android Studio and the Kotlin plugin put in earlier than you start. To put in Android Studio go to developer.android.com. Your telephone or emulator will want up-to-date Google Play providers on the system to run the app.

Since your UI can be bare-bones, open up Android Studio three.1.1 or later and create a brand new challenge. From Android Studio, choose Begin a brand new Android Studio venture from the startup display or New Undertaking from the File menu.

Enter the identify GoogleDriveDemo, your organization area (or instance.com in case your want) and a challenge location. Make it possible for Kotlin help is chosen after which press Subsequent.

Create a Project - Google Drive Demo

You shouldn’t want to vary something on this display. Simply click on Subsequent.

Create a Project - Google Drive Demo

Choose Empty Exercise and press Subsequent.

Create a Project - Google Drive Demo

Click on End.

Registering for Google Drive

In an effort to use the Google Drive SDK, it’s essential allow the API in your app.

Strolling by way of the steps:

Constructing Your Android App

Return to the Android app and you can begin including settings and code.

Updating the Gradle File

First, you’ll replace the construct.gradle file contained in the app folder. Add two variables for the model of Google Play providers and Android help libraries after the apply plugin statements close to the highest:


ext
play_services_version = “15.0.1”
support_version = “27.1.1”

This can allow you to re-use the variables and simply change the variations. Exchange the model of com.android.help:appcompat-v7 with the variable, and add the help design library, each in the dependencies block:


implementation “com.android.support:appcompat-v7:$support_version”
implementation “com.android.support:design:$support_version”

The appcompat library accommodates all the compatibility courses that provide help to write code that works on many variations of the Android OS. The design help library is used in this tutorial to show a Snackbar message.

Subsequent, add the libraries for the Google Drive SDK and the Okio library from Sq. for downloading information.


// Google Drive
implementation “com.google.android.gms:play-services-auth:$play_services_version”
implementation “com.google.android.gms:play-services-drive:$play_services_version”
implementation ‘com.squareup.okio:okio:1.14.zero’

Now, sync the venture Gradle information (File ▸ Sync Venture with Gradle Information)

Modifying the Android Manifest

Subsequent, you’ll modify AndroidManifest.xml. Open the file and add web permissions proper above the tag:


<uses-permission android:identify=”android.permission.INTERNET”/>

Add the next code to specify the model of Google Play Providers as the primary sub-element in the tag:


<meta-data
android:identify=”com.google.android.gms.version”
android:worth=”@integer/google_play_services_version” />

For those who command-click (or Ctrl-click on PC) on the @integer/google_play_services_version you will notice that it takes you to the play providers values file that permit’s the Google Play SDK know which model you’re utilizing.

Making a File Supplier

Subsequent, you’ll create a FileProvider. That is required for Android eight.zero Oreo and above to entry native information.

First, create a brand new listing by right-clicking on the app/res listing and selecing New ▸ Android Useful resource Listing. Identify it xml. Proper-click on the xml listing and choose New ▸ File; identify it provider_paths.

That is wanted since Android Oreo doesn’t help sharing file:// urls. Open the brand new file and paste in the next:


<?xml model=”1.0″ encoding=”utf-8″?>
<paths xmlns:android=”http://schemas.android.com/apk/res/android”>
<external-path identify=”external_files” path=”.”/>
</paths>

Now, in the Android Manifest file, after the meta-data tag you latterly added, add:


<supplier
android:identify=”android.support.v4.content.FileProvider”
android:authorities=”$applicationId.provider”
android:exported=”false”
android:grantUriPermissions=”true”>
<meta-data
android:identify=”android.support.FILE_PROVIDER_PATHS”
android:useful resource=”@xml/provider_paths”/>

This units up your app to make use of Android’s FileProvider class to deal with native information as urls as an alternative of as information. This can be a safety restriction that Google has carried out.

Including Strings

Now, you’ll add the strings that you simply’ll want for the UI. Open the strings.xml file and add:


<string identify=”source_google_drive”>Google Drive</string>
<string identify=”start_drive”>Begin Google Drive</string>
<string identify=”login”>Log In</string>
<string identify=”logout”>Log Out</string>
<string identify=”status_logged_out”>Logged Out</string>
<string identify=”status_logged_in”>Logged In</string>
<string identify=”status_user_cancelled”>Consumer Cancelled</string>
<string identify=”status_error”>We discovered an issue: %1$s</string>
<string identify=”not_open_file”>Couldn’t open file</string>

The primary string is for the Google Drive’s exercise title, and the remaining are for the UI.

Updating the UI

Subsequent, you’ll replace the UI. To take action, you’ll merely create three buttons to Login, Logout, and Open Google Drive, and a TextView to show login standing. Open activity_main.xml and substitute the contents with the next:


<?xml model=”1.0″ encoding=”utf-8″?>
<android.help.constraint.ConstraintLayout xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:app=”http://schemas.android.com/apk/res-auto”
xmlns:instruments=”http://schemas.android.com/tools”
android:id=”@+id/main_layout”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
instruments:context=”.MainActivity”>

<Button
android:id=”@+id/login”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:textual content=”@string/login”
app:layout_constraintBottom_toTopOf=”@+id/start”
app:layout_constraintEnd_toEndOf=”parent”
app:layout_constraintHorizontal_bias=”0.5″
app:layout_constraintStart_toStartOf=”parent”
app:layout_constraintTop_toTopOf=”parent” />

<Button
android:id=”@+id/start”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:textual content=”@string/start_drive”
app:layout_constraintBottom_toTopOf=”@+id/logout”
app:layout_constraintEnd_toEndOf=”parent”
app:layout_constraintHorizontal_bias=”0.5″
app:layout_constraintStart_toStartOf=”parent”
app:layout_constraintTop_toBottomOf=”@+id/login” />

<Button
android:id=”@+id/logout”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:textual content=”@string/logout”
app:layout_constraintBottom_toBottomOf=”parent”
app:layout_constraintEnd_toEndOf=”parent”
app:layout_constraintHorizontal_bias=”0.5″
app:layout_constraintStart_toStartOf=”parent”
app:layout_constraintTop_toBottomOf=”@+id/start” />

<TextView
android:id=”@+id/status”
android:layout_width=”0dp”
android:layout_height=”wrap_content”
android:layout_marginBottom=”8dp”
android:gravity=”center_horizontal”
android:textual content=”@string/status_logged_out”
app:layout_constraintBottom_toBottomOf=”parent”
app:layout_constraintEnd_toEndOf=”parent”
app:layout_constraintStart_toStartOf=”parent” />
</android.help.constraint.ConstraintLayout>

Run the app and ensure the UI is displayed appropriately:

If the whole lot works appropriately, you must have a primary UI with three buttons and a standing message on the backside. If the undertaking doesn’t compile or one thing goes flawed when operating, examine your work with every of the steps above.

Making a ServiceListener Interface

Since there are just a few courses, you’ll put all of them in the basis supply folder. Begin with the interface that the listener of your service should implement. Create a brand new Kotlin interface named ServiceListener:


interface ServiceListener
enjoyable loggedIn() //1
enjoyable fileDownloaded(file: File) //2
enjoyable cancelled() //three
enjoyable handleError(exception: Exception) //four

Chances are you’ll want to decide on Choice+Return on macOS Alt+Enter on PC to tug in the import for the File class.

These strategies notify the listener when:

  1. loggedIn(): A consumer is efficiently authenticated.
  2. fileDownloaded(file: File): A file is chosen and downloaded efficiently.
  3. cancelled(): A login or file choice is cancelled.
  4. handleError(exception: Exception): There’s any error.

This interface will probably be carried out by MainActivity and utilized by a service as a strategy to let the consumer of the service know when one thing has occurred.

Making a Knowledge Class: GoogleDriveConfig

Subsequent, create a easy knowledge class for holding the knowledge that the service wants. Create a brand new knowledge class named GoogleDriveConfig:


knowledge class GoogleDriveConfig(val activityTitle: String? = null, val mimeTypes: Record<String>? = null)

This class incorporates the title that Google Drive will designate because the exercise’s title and the mimeTypes that determines which file varieties to point out.

Creating the GoogleDriveService

Subsequent, you’ll create the precise service. Create a brand new class named GoogleDriveService:


class GoogleDriveService(personal val exercise: Exercise, personal val config: GoogleDriveConfig)

The category is just not an Android Service, however as an alternative acts as a service for MainActivity. You’ll be including the next code, in order.

First, add a companion object:


companion object
personal val SCOPES = setOf<Scope>(Drive.SCOPE_FILE, Drive.SCOPE_APPFOLDER)
val documentMimeTypes = arrayListOf(
“application/pdf”,
“application/msword”,
“application/vnd.openxmlformats-officedocument.wordprocessingml.document”)

const val REQUEST_CODE_OPEN_ITEM = 100
const val REQUEST_CODE_SIGN_IN = 101
const val TAG = “GoogleDriveService”

Scopes are Google Drive’s set of permissions. Subsequently, by giving a file and an app folder scope, you inform Google Drive to allow you to deal with information and folders.

The mime varieties are for the kind of information you need to permit the consumer to select. If you need the consumer to decide on pictures, you’d use picture/*. Right here, you decide .pdf and .doc/.docx information.

You even have two request codes to make use of for dealing with the results of signing in and choosing a file. The TAG fixed is used for Logging.

After the companion object part, add the next variables:


var serviceListener: ServiceListener? = null //1
personal var driveClient: DriveClient? = null //2
personal var driveResourceClient: DriveResourceClient? = null //three
personal var signInAccount: GoogleSignInAccount? = null //four

These are:

  1. serviceListener is the listener of your service.
  2. driveClient handles high-level drive features like Create File, Open File, and Sync.
  3. driveResourceClient handles entry to Drive assets and/or information.
  4. signInAccount retains monitor of the at present signed-in account.

Now add a GoogleSignInClient property that’s lazily-initialized:


personal val googleSignInClient: GoogleSignInClient by lazy
val builder = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
for (scope in SCOPES)
builder.requestScopes(scope)

val signInOptions = builder.construct()
GoogleSignIn.getClient(exercise, signInOptions)

googleSignInClient is created when wanted and consists of the scopes outlined earlier. The final assertion returns the GoogleSignInClient.

Dealing with Exercise Outcomes

You want to have the ability to deal with the outcomes from the consumer who’s signing in and choosing a file in the MainActivity. Create a way named onActivityResult, which can be referred to as inside onActivityResult of MainActivity:


enjoyable onActivityResult(requestCode: Int, resultCode: Int, knowledge: Intent?)
when (requestCode)
REQUEST_CODE_SIGN_IN ->
if (knowledge != null)
handleSignIn(knowledge)
else
serviceListener?.cancelled()



REQUEST_CODE_OPEN_ITEM ->
if (knowledge != null)
openItem(knowledge)
else
serviceListener?.cancelled()



Within the technique, you name helper strategies or the serviceListener relying on the requestCode. You’ll be able to verify the end result towards the presence of knowledge as an alternative of resultCode. If no knowledge is returned, it means the consumer cancelled the motion.

Now add the helper technique for dealing with signal in with one other technique to initialize the drive shopper:


personal enjoyable handleSignIn(knowledge: Intent)
val getAccountTask = GoogleSignIn.getSignedInAccountFromIntent(knowledge)
if (getAccountTask.isSuccessful)
initializeDriveClient(getAccountTask.end result)
else
serviceListener?.handleError(Exception(“Sign-in failed.”, getAccountTask.exception))



personal enjoyable initializeDriveClient(signInAccount: GoogleSignInAccount)
driveClient = Drive.getDriveClient(exercise.applicationContext, signInAccount)
driveResourceClient = Drive.getDriveResourceClient(exercise.applicationContext, signInAccount)
serviceListener?.loggedIn()

As soon as the consumer has signed in, you deal with the outcome in initializeDriveClient(). It will create your drive shoppers. It additionally notifies the listener that the consumer has efficiently signed in.

After a consumer has picked a file, you’ll get an exercise intent and move it to openItem(), so add that helper technique now:


personal enjoyable openItem(knowledge: Intent)
val driveId = knowledge.getParcelableExtra<DriveId>(OpenFileActivityOptions.EXTRA_RESPONSE_DRIVE_ID)
downloadFile(driveId)

This perform will get the driveId from the intent choices and passes that ID to a different helper technique downloadFile().

The important thing facet of the entire service is downloading the picked file. To try this, you must get an enter stream to the file and reserve it to an area file. You’ll use Sq.’s Okio library to simply take that stream and reserve it to a file.

Add the downloadFile() technique now:


personal enjoyable downloadFile(knowledge: DriveId?)
if (knowledge == null)
Log.e(TAG, “downloadFile data is null”)
return

val drive = knowledge.asDriveFile()
var fileName = “test”
driveResourceClient?.getMetadata(drive)?.addOnSuccessListener
fileName = it.originalFilename

val openFileTask = driveResourceClient?.openFile(drive, DriveFile.MODE_READ_ONLY)
openFileTask?.continueWithTask activity ->
val contents = process.outcome
contents.inputStream.use
attempt
//That is the app’s obtain listing, not the telephones
val storageDir = exercise.getExternalFilesDir(Surroundings.DIRECTORY_DOWNLOADS)
val tempFile = File(storageDir, fileName)
tempFile.createNewFile()
val sink = Okio.buffer(Okio.sink(tempFile))
sink.writeAll(Okio.supply(it))
sink.shut()

serviceListener?.fileDownloaded(tempFile)
catch (e: IOException)
Log.e(TAG, “Problems saving file”, e)
serviceListener?.handleError(e)


driveResourceClient?.discardContents(contents)
?.addOnFailureListener e ->
// Deal with failure
Log.e(TAG, “Unable to read contents”, e)
serviceListener?.handleError(e)

There’s lots happening in this technique. Discover the getMetaData() name. That’s wanted to get the identify of the chosen file. You’re then saving the file to your app’s inner obtain folder (which isn’t seen to the consumer), then alerting the listener concerning the downloaded file and the place to seek out it.

Opening a Picked-File Dialog

You have got created the strategies to deal with the results of signing in and choosing a file, however you don’t but have a way to provoke these actions. Create a way named pickFiles() to open the picked-file dialog:


/**
* Prompts the consumer to pick a textual content file utilizing OpenFileActivity.
*
* @return Process that resolves with the chosen merchandise’s ID.
*/
enjoyable pickFiles(driveId: DriveId?)
val builder = OpenFileActivityOptions.Builder()
if (config.mimeTypes != null)
builder.setMimeType(config.mimeTypes)
else
builder.setMimeType(documentMimeTypes)

if (config.activityTitle != null && config.activityTitle.isNotEmpty())
builder.setActivityTitle(config.activityTitle)

if (driveId != null)
builder.setActivityStartFolder(driveId)

val openOptions = builder.construct()
pickItem(openOptions)

You set the mime sort and title, after which set the beginning folder if driveId is offered. Then name pickItem with these choices.

Subsequent add the pickItem technique:


personal enjoyable pickItem(openOptions: OpenFileActivityOptions)
val openTask = driveClient?.newOpenFileActivityIntentSender(openOptions)
openTask?.let
openTask.continueWith activity ->
ActivityCompat.startIntentSenderForResult(exercise, activity.end result, REQUEST_CODE_OPEN_ITEM,
null, zero, zero, zero, null)


It will begin Google Drive’s File Picker exercise, which can name your onActivityResult with the consumer’s response.

Logging In and Out

Subsequent, you add a way that may retrieve any account that has been signed in from earlier launches:


enjoyable checkLoginStatus()
val requiredScopes = HashSet<Scope>(2)
requiredScopes.add(Drive.SCOPE_FILE)
requiredScopes.add(Drive.SCOPE_APPFOLDER)
signInAccount = GoogleSignIn.getLastSignedInAccount(exercise)
val containsScope = signInAccount?.grantedScopes?.containsAll(requiredScopes)
val account = signInAccount
if (account != null && containsScope == true)
initializeDriveClient(account)

If a signed-in account is discovered and no scope has modified, you name initializeDriveClient() that you simply created earlier to deal with the signal in. Add the next technique to launch the Authentication dialog:


enjoyable auth()
exercise.startActivityForResult(googleSignInClient.signInIntent, REQUEST_CODE_SIGN_IN)

Lastly, add a way to permit a consumer to sign off.


enjoyable logout()
googleSignInClient.signOut()
signInAccount = null

Updating MainActivity

Now, you’ll flip your consideration again to the MainActivity.
Above the onCreate() perform, create a easy enum to maintain monitor of the buttons state:


enum class ButtonState
LOGGED_OUT,
LOGGED_IN

As talked about earlier, the exercise must be set as a serviceListener in order that it may reply to the service. Implement the ServiceListener interface in the MainActivity:


class MainActivity : AppCompatActivity(), ServiceListener

And add the interface strategies:


override enjoyable loggedIn()


override enjoyable fileDownloaded(file: File)


override enjoyable cancelled()


override enjoyable handleError(exception: Exception)

Add properties for the service and button state:


personal lateinit var googleDriveService: GoogleDriveService
personal var state = ButtonState.LOGGED_OUT

You have to change the state of the buttons based mostly in your logged-in or logged-out state. Consequently, you create a perform named setButtons:


personal enjoyable setButtons()
when (state)
ButtonState.LOGGED_OUT ->
standing.textual content = getString(R.string.status_logged_out)
begin.isEnabled = false
logout.isEnabled = false
login.isEnabled = true


else ->
standing.textual content = getString(R.string.status_logged_in)
begin.isEnabled = true
logout.isEnabled = true
login.isEnabled = false


standing, begin, logout, and login are the ID of the views you created in activity_main.xml. You need to have the ability to import them utilizing Choice+Return on macOS Alt+Enter on PC so long as you’ve got apply plugin:’kotlin-android-extensions’ in the app module construct.gradle, which new tasks do by default.

Replace onCreate() to be:


override enjoyable onCreate(savedInstanceState: Bundle?)
tremendous.onCreate(savedInstanceState)
setContentView(R.format.activity_main)

//1
val config = GoogleDriveConfig(
getString(R.string.source_google_drive),
GoogleDriveService.documentMimeTypes
)
googleDriveService = GoogleDriveService(this, config)

//2
googleDriveService.serviceListener = this

//three
googleDriveService.checkLoginStatus()

//four
login.setOnClickListener
googleDriveService.auth()

begin.setOnClickListener
googleDriveService.pickFiles(null)

logout.setOnClickListener
googleDriveService.logout()
state = ButtonState.LOGGED_OUT
setButtons()


//5
setButtons()

Right here’s what the above does:

  1. Creates the service together with your title and the doc mime varieties.
  2. Units MainActivity because the listener.
  3. Modifications the state to logged-in if there’s any logged-in account current.
  4. Units the button click on listeners. There are three buttons: Login, Decide a File and Logout.
  5. Updates views based mostly on the present state.

Dealing with the OnActivityResult Technique

Add the onActivityResult() technique and have it move the end result to the service:


override enjoyable onActivityResult(requestCode: Int, resultCode: Int, knowledge: Intent?)
googleDriveService.onActivityResult(requestCode, resultCode, knowledge)

Now, add implementations for the listener strategies:


override enjoyable loggedIn()
state = ButtonState.LOGGED_IN
setButtons()


override enjoyable fileDownloaded(file: File)
val intent = Intent(Intent.ACTION_VIEW)
val apkURI = FileProvider.getUriForFile(
this,
applicationContext.packageName + “.provider”,
file)
val uri = Uri.fromFile(file)
val extension = MimeTypeMap.getFileExtensionFromUrl(uri.toString())
val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
intent.setDataAndType(apkURI, mimeType)
intent.flags = FLAG_GRANT_READ_URI_PERMISSION
if (intent.resolveActivity(packageManager) != null)
startActivity(intent)
else
Snackbar.make(main_layout, R.string.not_open_file, Snackbar.LENGTH_LONG).present()



override enjoyable cancelled()
Snackbar.make(main_layout, R.string.status_user_cancelled, Snackbar.LENGTH_LONG).present()


override enjoyable handleError(exception: Exception)
val errorMessage = getString(R.string.status_error, exception.message)
Snackbar.make(main_layout, errorMessage, Snackbar.LENGTH_LONG).present()

The code inside loggedIn(), cancelled(), and handleError() are fairly simple. They replace the UI and/or show messages with Snackbar.

In fileDownloaded(), a file is acquired; subsequently, you need the system to open the file. That is the place the FileProvider info you set in the AndroidManifest.xml file comes in.

In Android eight.zero Oreo and above, you possibly can not open file:// url’s, so you might want to present your personal FileProvider for that. You don’t want some other code than this. MimeTypeMap is a system class that has a number of helper strategies you should use to get the file extension and mime sort from the url. You create an intent and be sure that the system can deal with it earlier than beginning the exercise — the app will crash in any other case.

Time to offer it a attempt! Construct and run the app.

First, attempt logging in:

You’ll first be introduced with an account chooser. After you’ve chosen an account, you’ll want to provide the app permissions to entry your Google Drive.

Subsequent, hit the “Start Google Drive” button, and you will notice your information like this:

As soon as you choose a file and press Choose, the obtain course of will begin. After the obtain is full, it is best to then see the file you picked routinely open in a system viewer.

The place to Go From Right here?

On this tutorial, you could have discovered the right way to combine your app with Google Drive and how you can obtain a file. Congratulations on efficiently downloading information out of your Google Drive!

You’ll be able to obtain the ultimate challenge through the use of the obtain button on the prime or backside of this tutorial.

You are able to do rather more with Google Drive. Attempt, for instance, including extra capabilities to your app, akin to making a file or deleting a file. Take a look at the documentation about different Google Drive SDK options for Android.

When you have any feedback or questions on this tutorial or Google Drive SDK, be happy to hitch the discussion board dialogue under!

Obtain Supplies

(perform(d, s, id)
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = “//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.5&appId=118196468516511”;
fjs.parentNode.insertBefore(js, fjs);
(doc, ‘script’, ‘facebook-jssdk’));