cannot open file downloaded using download manager API inside android webview

761 Views Asked by At

I am downloading pdf files inside web view in android studio. That's going well. I am successfully downloading a pdf file with the .pdf extension but when I click on the file see a toast message something went wrong can't open this file Here is my code

 binding?.webView?.setDownloadListener { url, userAgent, contentDisposition, mimetype, contentLength ->
            val pdfUrl:String = url.trim().replace("blob:","")
            Log.e(TAG, "loadWAWeb:  $pdfUrl")
            if (storagePermission()) {
//                binding?.webView?.loadUrl(JavaScriptInterface.getBase64StringFromBlobUrl(url,mimetype))
                val request = DownloadManager.Request(Uri.parse(pdfUrl))
                request.setMimeType(mimetype)
                request.allowScanningByMediaScanner()
                request.setDescription("Downloading file...")
                val fileName = URLUtil.guessFileName(pdfUrl, contentDisposition, mimetype)
                request.setTitle(fileName)

                Log.e(TAG, "loadWAWeb:  $fileName" )
                request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
                request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName)

                val dm = getSystemService(DOWNLOAD_SERVICE) as DownloadManager
                dm.enqueue(request)

            }

        }

this is a pdf file which is good in format but I don't know where is the issue.

enter image description here

but when I try to open this file. This issue that I am facing.

enter image description here

2

There are 2 best solutions below

1
Jiilan .T On

I Don't see that have a problem, maybe the pdf file just corrupted. Test in another PDF File or just update your Android Studio. in my case before i am implement Fast Android Networking the file sometimes corrupted, but after i am implement Fast Android Networking the file is not corrupted.

in Gradle, paste this

implementation 'com.amitshekhar.android:android-networking:1.0.2'

and add Internet Permission on Manifest.xml

<uses-permission android:name="android.permission.INTERNET" />

Then initialize it in onCreate() Method of application class

AndroidNetworking.initialize(getApplicationContext());

i think my explanation is not that good, you can see at https://github.com/amitshekhariitbhu/Fast-Android-Networking

im sorry if this not make you problem solved, but based on my case it solved

0
Muhammad Hamza On

Continuously my downloaded file was corrupting I handled this as:

JavaScriptInterface.kt

package com.hamza.hiwhatsappweb.utils

import android.R
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Environment
import android.os.Handler
import android.util.Base64
import android.util.Log
import android.webkit.JavascriptInterface
import android.widget.Toast
import androidx.core.app.NotificationCompat
import androidx.core.content.FileProvider
import java.io.File
import java.io.FileOutputStream
import java.io.IOException


class JavaScriptInterface(private val context: Context) {
    @JavascriptInterface
    @Throws(IOException::class)
    fun getBase64FromBlobData(base64Data: String) {
        Log.e("mimeType", "getBase64FromBlobData:  $mimTp")
        convertBase64StringToPdfAndStoreIt(base64Data)
    }

    @Throws(IOException::class)
    private fun convertBase64StringToPdfAndStoreIt(base64PDf: String) {
        Log.e("BASE 64", base64PDf)
        val notificationId = 1
        val dwldsPath = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString() + "/$fileName")
        val pdfAsBytes =
            Base64.decode(base64PDf.replaceFirst("^data:$mimTp;base64,".toRegex(), ""), 0)
        val os = FileOutputStream(dwldsPath, false)
        os.write(pdfAsBytes)
        os.flush()
        if (dwldsPath.exists()) {
            val intent = Intent()
            intent.action = Intent.ACTION_VIEW
            val apkURI = FileProvider.getUriForFile(context, context.applicationContext.packageName + ".provider", dwldsPath)
            intent.setDataAndType(apkURI, mimTp)
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            val pendingIntent =
                PendingIntent.getActivity(context, 1, intent, PendingIntent.FLAG_CANCEL_CURRENT)
            val CHANNEL_ID = "MYCHANNEL"
            val notificationManager =
                context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                val notificationChannel =
                    NotificationChannel(CHANNEL_ID, "name", NotificationManager.IMPORTANCE_HIGH)
                val notification = Notification.Builder(
                    context, CHANNEL_ID
                )
                    .setContentText(fileName)
                    .setContentTitle("File downloaded")
                    .setContentIntent(pendingIntent)
                    .setChannelId(CHANNEL_ID)
                    .setSmallIcon(R.drawable.sym_action_chat)
                    .build()
                if (notificationManager != null) {
                    notificationManager.createNotificationChannel(notificationChannel)
                    notificationManager.notify(notificationId, notification)
                }
            } else {
                val b = NotificationCompat.Builder(context, CHANNEL_ID)
                    .setDefaults(NotificationCompat.DEFAULT_ALL)
                    .setWhen(System.currentTimeMillis())
                    .setSmallIcon(R.drawable.sym_action_chat) //.setContentIntent(pendingIntent)
                    .setContentTitle("MY TITLE")
                    .setContentText("MY TEXT CONTENT")
                if (notificationManager != null) {
                    notificationManager.notify(notificationId, b.build())
                    val h = Handler()
                    val delayInMilliseconds: Long = 1000
                    h.postDelayed({ notificationManager.cancel(notificationId) }, delayInMilliseconds)
                }
            }
        }
        Toast.makeText(context, "PDF FILE DOWNLOADED!", Toast.LENGTH_SHORT).show()
    }

    companion object {
        var mimTp:String = ""
        var fileName:String = ""
        fun getBase64StringFromBlobUrl(blobUrl: String, mimeType: String,fileName:String): String {
            mimTp = mimeType
            this.fileName = fileName
            return if (blobUrl.startsWith("blob")) {
                "javascript: var xhr = new XMLHttpRequest();" +
                        "xhr.open('GET', '" + blobUrl + "', true);" +
                        "xhr.setRequestHeader('Content-type','$mimeType');" +
                        "xhr.responseType = 'blob';" +
                        "xhr.onload = function(e) {" +
                        "    if (this.status == 200) {" +
                        "        var blobPdf = this.response;" +
                        "        var reader = new FileReader();" +
                        "        reader.readAsDataURL(blobPdf);" +
                        "        reader.onloadend = function() {" +
                        "            base64data = reader.result;" +
                        "            Android.getBase64FromBlobData(base64data);" +
                        "        }" +
                        "    }" +
                        "};" +
                        "xhr.send();"
            } else "javascript: console.log('It is not a Blob URL');"
        }
    }
}

Set this property on Webview:

binding?.webView?.addJavascriptInterface(JavaScriptInterface(applicationContext), "Android")
        binding?.webView?.settings?.pluginState = WebSettings.PluginState.ON

        binding?.webView?.setDownloadListener { url, _, contentDisposition, mimetype, _ ->
//           downloadFiles(url, mimetype, contentDisposition)
            val pdfUrl: String? = url?.trim()?.replace("blob:", "")
            val fileName = URLUtil.guessFileName(pdfUrl, contentDisposition, mimetype)

            binding?.webView?.loadUrl(JavaScriptInterface.getBase64StringFromBlobUrl(url,mimetype,fileName))

        }

provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path name="external_files" path="."/>
</paths>

Paste this code under Application in AndroidManifest.xml file

<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>