Fetch PDF content and open in the app — Android with Kotlin
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 👏