3

I'm hitting an API Endpoint with a Kotlin Android app. In this API call I'm returning a byte Array. What I would like to see is a way to convert the byte array to a pdf file and save it in the phones download folder.

    private suspend fun getIDCard(sessionID: String?, carriermemid: String?): ByteArray? {
        var results: String = ""

        val postData = "{\"sessionid\": \" $sessionID\"}"
        val outputStreamWriter: OutputStreamWriter

        var byteArray: ByteArray? = null
        val url: URL = URL(idURL + carriermemid)
        val conn: HttpURLConnection = url.openConnection() as HttpURLConnection

        try {
            conn.setRequestProperty(apiConfig.typeKey, apiConfig.typeValueJSON)
            conn.setRequestProperty("Accept", "application/json")
            conn.setRequestProperty("sessionid", sessionID)
            conn.requestMethod = apiConfig.methodGet


            val responseCode: Int = conn.responseCode
            println("Response Code :: $responseCode")
            //returning 404
            return if (responseCode == HttpURLConnection.HTTP_OK) {// connection ok
                var out: ByteArrayOutputStream? = ByteArrayOutputStream()
                val `in`: InputStream = conn.inputStream
                var bytesRead: Int
                val buffer = ByteArray(1024)
                while (`in`.read(buffer).also { bytesRead = it } > 0) {
                    out!!.write(buffer, 0, bytesRead)
                }
                out!!.close()
                byteArray = out.toByteArray()
                return byteArray

            } else {
                return byteArray
            }

        } catch (ex: Exception) {
            ex.printStackTrace()
        } finally {
            conn.disconnect()
        }
        return byteArray
    }
4
  • 4
    convert the byte array to a pdf file and save it in the phones download folder. What is in the byte array that can be converted to a pdf? I think the byte array will contain the pdf and all you have to do is saving the bytes in the array to file and you are done. Commented May 19, 2020 at 6:55
  • @blackapps the byte array does contain the pdf. As far as how I'm looking for examples. :facepalm: Commented May 19, 2020 at 13:19
  • 1
    So basically your question is: How can I store a file in the global download folder? Commented May 22, 2020 at 9:31
  • @tynn convert a byte array to a file to store in the global download. Commented May 22, 2020 at 19:18

3 Answers 3

11
+50

This will get the Android download directory and write the byte array as a PDF file (assuming the byte array contains a PDF). Change File.createTempFile to any file you like (you don't need to create a temporary file):

fun writeBytesAsPdf(bytes : ByteArray) {
   val path = requireContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
    var file = File.createTempFile("my_file",".pdf", path)
    var os = FileOutputStream(file);
    os.write(bytes);
    os.close();
}

You will also have to add android.permission.WRITE_EXTERNAL_STORAGE to your manifest.

Sign up to request clarification or add additional context in comments.

5 Comments

To avoid needing the context in the viewModel, you could get the path in the fragment/activity and save it in the viewModel, it should be constant for a particular user.
You also don't need to use createTemporaryFile, that may or may not work in the Downloads folder. You can just use (or similar): File(path, "my_file.pdf")
Yeah the manifest is updated let me try getting rid of Create temp file
That didn't work either. Maybe due to permissions or the byte array I'll take a look in a bit
that wasn't what fixed it at all. See the accepted answer.
1

Looking at How to download PDF file with Retrofit and Kotlin coroutines?, you can use:

private const val BUFFER_SIZE = 4 * 1024

private fun copyStreamToFile(inputStream: InputStream, outputFile: File) {
    inputStream.use { input ->
        val outputStream = FileOutputStream(outputFile)
        outputStream.use { output ->
            val buffer = ByteArray(BUFFER_SIZE)
            while (true) {
                val byteCount = input.read(buffer)
                if (byteCount < 0) break
                output.write(buffer, 0, byteCount)
            }
            output.flush()
        }
    }
}

or

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

Also you should create the file.

private fun createFile(context: Context, name: String): File? {
    val storageDir = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.path
    var file = File("$storageDir/$name.pdf")
    return storageDir?.let { file }
}

Comments

-1

So this ended up being what fixed this. Almost forgot to post this. It was the resolveinfo list and the way I granted permission that got me through but here goes

                    try {
                        val pdfbyte = viewModel.getPDFImage()
                        val path =
                            requireContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
                                .toString() + File.separator
                        val fileName = "my_idcard.pdf"
                        val storageDir =
                            requireContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.path
                        var file = File("$storageDir/$fileName")
                        var os = FileOutputStream(file);
                        os.write(pdfbyte);
                        os.close();
                        val intent = Intent(Intent.ACTION_VIEW)
                        val uri: Uri = FileProvider.getUriForFile(
                            requireContext(),
                            BuildConfig.APPLICATION_ID + ".provider",
                            file
                        )
                        intent.setDataAndType(uri, "application/pdf")
                        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                        intent.flags = Intent.FLAG_ACTIVITY_NO_HISTORY
                        val resInfoList: List<ResolveInfo> = requireActivity().getPackageManager()
                            .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)

                        for (resolveInfo in resInfoList) {
                            val packageName = resolveInfo.activityInfo.packageName
                            requireActivity().grantUriPermission(
                                packageName,
                                uri,
                                Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
                            )
                        }
                        startActivity(intent)
                    } catch (e: ActivityNotFoundException) {
                        println("*************************NO PDF**************************")
                    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.