Integrating Google Drive in Android
See how to integrate the Google Drive SDK in order to let your users access and download their Drive files directly to your app. By Kevin D Moore.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Integrating Google Drive in Android
25 mins
- Getting Started
- Registering for Google Drive
- Building Your Android App
- Updating the Gradle File
- Modifying the Android Manifest
- Creating a File Provider
- Adding Strings
- Updating the UI
- Creating a ServiceListener Interface
- Creating a Data Class: GoogleDriveConfig
- Creating the GoogleDriveService
- Handling Activity Results
- Opening a Picked-File Dialog
- Logging In and Out
- Updating MainActivity
- Handling the OnActivityResult Method
- Where to Go From Here?
Opening a Picked-File Dialog
You have created the methods to handle the result of signing in and picking a file, but you don’t yet have a method to initiate those actions. Create a method named pickFiles()
to open the picked-file dialog:
/**
* Prompts the user to select a text file using OpenFileActivity.
*
* @return Task that resolves with the selected item's ID.
*/
fun 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.build()
pickItem(openOptions)
}
You set the mime type and title, and then set the starting folder if driveId
is provided. Then call pickItem
with those options.
Next add the pickItem
method:
private fun pickItem(openOptions: OpenFileActivityOptions) {
val openTask = driveClient?.newOpenFileActivityIntentSender(openOptions)
openTask?.let {
openTask.continueWith { task ->
ActivityCompat.startIntentSenderForResult(activity, task.result, REQUEST_CODE_OPEN_ITEM,
null, 0, 0, 0, null)
}
}
}
This will start Google Drive’s File Picker activity, which will call your onActivityResult
with the user’s response.
Logging In and Out
Next, you add a method that can retrieve any account that has been signed in from previous launches:
fun checkLoginStatus() {
val requiredScopes = HashSet<Scope>(2)
requiredScopes.add(Drive.SCOPE_FILE)
requiredScopes.add(Drive.SCOPE_APPFOLDER)
signInAccount = GoogleSignIn.getLastSignedInAccount(activity)
val containsScope = signInAccount?.grantedScopes?.containsAll(requiredScopes)
val account = signInAccount
if (account != null && containsScope == true) {
initializeDriveClient(account)
}
}
If a signed-in account is found and no scope has changed, you call initializeDriveClient()
that you created earlier to handle the sign in. Add the following method to launch the Authentication dialog:
fun auth() {
activity.startActivityForResult(googleSignInClient.signInIntent, REQUEST_CODE_SIGN_IN)
}
Finally, add a method to allow a user to log out.
fun logout() {
googleSignInClient.signOut()
signInAccount = null
}
Updating MainActivity
Now, you will turn your attention back to the MainActivity.
Above the onCreate()
function, create a simple enum to keep track of the buttons state:
enum class ButtonState {
LOGGED_OUT,
LOGGED_IN
}
As mentioned earlier, the activity needs to be set as a serviceListener
so that it can respond to the service. Implement the ServiceListener
interface in the MainActivity:
class MainActivity : AppCompatActivity(), ServiceListener {
And add the interface methods:
override fun loggedIn() {
}
override fun fileDownloaded(file: File) {
}
override fun cancelled() {
}
override fun handleError(exception: Exception) {
}
Add properties for the service and button state:
private lateinit var googleDriveService: GoogleDriveService
private var state = ButtonState.LOGGED_OUT
You need to change the state of the buttons based on your logged-in or logged-out state. Consequently, you create a function named setButtons
:
private fun setButtons() {
when (state) {
ButtonState.LOGGED_OUT -> {
status.text = getString(R.string.status_logged_out)
start.isEnabled = false
logout.isEnabled = false
login.isEnabled = true
}
else -> {
status.text = getString(R.string.status_logged_in)
start.isEnabled = true
logout.isEnabled = true
login.isEnabled = false
}
}
}
status
, start
, logout
, and login
are the ID of the views you created in activity_main.xml. You should be able to import them using Option+Return on macOS Alt+Enter on PC as long as you have apply plugin:'kotlin-android-extensions'
in the app module build.gradle, which new projects do by default.
Update onCreate()
to be:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//1
val config = GoogleDriveConfig(
getString(R.string.source_google_drive),
GoogleDriveService.documentMimeTypes
)
googleDriveService = GoogleDriveService(this, config)
//2
googleDriveService.serviceListener = this
//3
googleDriveService.checkLoginStatus()
//4
login.setOnClickListener {
googleDriveService.auth()
}
start.setOnClickListener {
googleDriveService.pickFiles(null)
}
logout.setOnClickListener {
googleDriveService.logout()
state = ButtonState.LOGGED_OUT
setButtons()
}
//5
setButtons()
}
Here’s what the above does:
- Creates the service with your title and the document mime types.
- Sets MainActivity as the listener.
- Changes the state to logged-in if there is any logged-in account present.
- Sets the button click listeners. There are three buttons: Login, Pick a File and Logout.
- Updates views based on the current state.
Handling the OnActivityResult Method
Add the onActivityResult()
method and have it pass the result to the service:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
googleDriveService.onActivityResult(requestCode, resultCode, data)
}
Now, add implementations for the listener methods:
override fun loggedIn() {
state = ButtonState.LOGGED_IN
setButtons()
}
override fun 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).show()
}
}
override fun cancelled() {
Snackbar.make(main_layout, R.string.status_user_cancelled, Snackbar.LENGTH_LONG).show()
}
override fun handleError(exception: Exception) {
val errorMessage = getString(R.string.status_error, exception.message)
Snackbar.make(main_layout, errorMessage, Snackbar.LENGTH_LONG).show()
}
The code inside loggedIn()
, cancelled()
, and handleError()
are pretty straightforward. They update the UI and/or display messages with Snackbar
.
In fileDownloaded()
, a file is received; subsequently, you want the system to open the file. This is where the FileProvider information you put in the AndroidManifest.xml file comes in.
In Android 8.0 Oreo and above, you can no longer open file:// url’s, so you need to provide your own FileProvider for that. You don’t need any other code than this. MimeTypeMap
is a system class that has a few helper methods you can use to get the file extension and mime type from the url. You create an intent and make sure that the system can handle it before starting the activity — the app will crash otherwise.
Time to give it a try! Build and run the app.
First, try logging in:
You will first be presented with an account chooser. After you’ve chosen an account, you’ll need to give the app permissions to access your Google Drive.
Next, hit the “Start Google Drive” button, and you will see your files like this:
Once you select a file and press Select, the download process will start. After the download is complete, you should then see the file you picked automatically open in a system viewer.
Where to Go From Here?
In this tutorial, you have learned how to integrate your app with Google Drive and how to download a file. Congratulations on successfully downloading files from your Google Drive!
You can download the final project by using the download button at the top or bottom of this tutorial.
You can do much more with Google Drive. Try, for example, adding more capabilities to your app, such as creating a file or deleting a file. Check out the documentation about other Google Drive SDK features for Android.
If you have any comments or questions about this tutorial or Google Drive SDK, feel free to join the forum discussion below!