Fetch PDF content and open in the app — Android with Kotlin

Rohail Ahmad
2 min readMay 6, 2021
Photo by Firmbee.com on Unsplash

Another solution to fetch PDF content and open it on your android device.

I was struggling to find a better solution on the internet to fetch a PDF file content like in a Stream and then display it in a PDF application on my android device. I couldn’t find a good and neat solution. Here I will explain how you can fetch and display a PDF file.

Firstly, I am using the Retrofit HTTP client. Example:

@GET("files/{id}/pdf")
suspend fun getPDF(
@Path("id") id: String
): Response<ResponseBody>

You can see response type is ResponseBody. Then, get InputStream from responseBody like response.byteStream() and pass it to your method to parse, save and display file. Example:

fun openPDFContent(context: Context, inputStream: InputStream, fileName: String) {//saving in cache directory
val filePath = context.externalCacheDir?.absolutePath ?: context.cacheDir.absolutePath
val fileNameExtension =
if (fileName.isNotNullOrEmpty()) fileName else context.getString(R.string.app_name) + ".pdf"
val file = inputStream.saveToFile(filePath, fileNameExtension)

val uri = FileProvider.getUriForFile(
context,
BuildConfig.APPLICATION_ID + ".provider", file
)
val intent = Intent(Intent.ACTION_VIEW).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
setDataAndType(uri, "application/pdf")
}
context.startActivity(Intent.createChooser(intent, "Select app"))
}

I am saving the file in the application cache temporarily because I don’t need to ask for any permission from the user to save the file and when a user view in a PDF application then user can download or share: context.externalCacheDir?.absolutePath but if you want, you can download in external directory but then you would have to ask for read/write permission: Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absolutePath

You must have noticed the saveToFile extension function. I have used a very neat and short form of kotlin extension function to create and write a PDF file:

private fun InputStream.saveToFile(filePath: String, fileName: String): File = use { input ->
val file = File(filePath, fileName)
file.outputStream().use { output ->
input.copyTo(output)
}
input.close()
file
}

Are we missing anything?

Yes, we are missing Provider in manifest.xml inside application tag:

<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>

Define provider_paths in res->xml->provider_paths.xml:

<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<cache-path
name="cache"
path="." />
<external-cache-path
name="external_cache"
path="." />
<files-path
name="files"
path="." />
</paths>

I have defined all paths so you can get an idea.

I hope it will work fine for you. Happy coding 😊

Don’t forget to hit the clap 👏

--

--

Rohail Ahmad

Android Engineer with @kivrasweden formerly @Eliq & @Inov8