Android 10 本地PDF文件写入和打开方式适配

571 阅读2分钟

文章目录

下载PDF后的responseBody写入本地

        val responseBody = downLoadResponseBodyBean.respone
        logE("收到responseBody.length == ${responseBody?.contentLength()}")
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                thread {
                    responseBody?.let { writePDF(it) }
                }.start()

            } else{
                GlobalScope.launch {
                    responseBody?.let { writePDFQ(it) }
                }

            }

Android10以下写入

   fun writePDF(body: ResponseBody): Boolean {
        var length = 0L
        var result = 0
       return  try {
            val files = File(PDF_PATH)
            if (!files.exists()) {
                 files.mkdirs()
            }
            val futureStudioIconFile = File(PDF_PATH_NAME)
            var inputStream: InputStream? = null
            var outputStream: OutputStream? = null
            try {
                val fileReader = ByteArray(1024)
                val fileSize: Long = body.contentLength()
                inputStream = body.byteStream()
                outputStream = FileOutputStream(futureStudioIconFile)
                while (true) {
                        val read: Int = inputStream.read(fileReader)
                        if (read == -1) {
                            break
                        }
                        outputStream.write(fileReader,0,read)
                        length += read
                         result = (100*length/fileSize).toInt()
                        if(result>0){
                            logE("监听PDF写入文件进度 : ${result}%")
                            ownerDashBoardModel.downLoadPDFProgress.postValue(result)
                        }

                }
                outputStream.flush()
                true
            } catch (e: IOException) {
                logE("网络错误${e.printStackTrace()}")
                false
            } finally {
                try {
                    inputStream!!.close()
                    outputStream!!.close()
                } catch(e: Exception) {
                    e.printStackTrace()
                }
            }
        } catch (e: IOException) {
            logE(e.message)
            false
        }
    }

android 10 以上写入

  @RequiresApi(Build.VERSION_CODES.Q)
    private suspend fun writePDFQ(responseBody: ResponseBody) {
        var length = 0L
        withContext(Dispatchers.IO){
            var result = 0
            val fileSize: Long = responseBody.contentLength()
            logE("文件大小:$fileSize")
            try {
                val inputStream = responseBody.byteStream()
                val bis = BufferedInputStream(inputStream)
                val values = ContentValues()
                values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
                values.put(MediaStore.Downloads.MIME_TYPE, "application/pdf")
                values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)

                var uri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values)
                if (uri != null) {
                    val outputStream = contentResolver.openOutputStream(uri)
                    if (outputStream != null) {
                        val bos = BufferedOutputStream(outputStream)
                        val buffer = ByteArray(1024)
                        var bytes = bis.read(buffer)
                        while (bytes >= 0) {
                            bos.write(buffer, 0 , bytes)
                            bos.flush()
                            bytes = bis.read(buffer)
                            length += bytes
                            result = (101*length/fileSize).toInt()
                            if(result in 1..100){
                                logE("Q监听PDF写入文件进度 : ${result}%")
                                ownerDashBoardModel.downLoadPDFProgress.postValue(result)
                            }
                        }
                        bos.close()
                    }
                }else{
                    Toast.makeText(context, "$fileName 写入异常", Toast.LENGTH_SHORT).show()
                }
                bis.close()
            }catch (e: Exception) {
                e.printStackTrace()
            }

        }


    }
  • Android10以下写入SD卡根目录,可自己创建文件夹
  • Android10以及以上上放入公共目录 Download目录下,而且是在根目录下,不然隐式调用第三方APP打开文件的时候会有权限问题 Permission denied

使用腾讯tbs内核在webview中直接打开本地PDF文件

  • 目前最新版 api ‘com.tencent.tbs.tbssdk:sdk:43903’ 支持通过QQ浏览器打开PDF
  • 如果以 Android 10 或更高版本为目标平台,请在应用的清单文件中将 requestLegacyExternalStorage 的值设为 true:
<manifest ... >
      <!-- This attribute is "false" by default on apps targeting
           Android 10 or higher. -->
      <application android:requestLegacyExternalStorage="true" ... >
        ...
      </application>
</manifest>
    
   <!--   webView打开PDF     -->
        <RelativeLayout
            android:id="@+id/rl_pdf"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <com.beans.base.widget.TBSWebView
                android:id="@+id/webView"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
            </com.beans.base.widget.TBSWebView>
        </RelativeLayout>

直接打开本地PDF文件

   var tbsReaderView:TbsReaderView? = null

    /**
     * 打开本地PDF文件
     */
    private fun openPDF() {
        var bundle = Bundle()
        if(isAndroidQ()){
            bundle.putString("filePath", "/storage/emulated/0/Download/wey.pdf")
            bundle.putString("tempPath", context.cacheDir?.path+"/wey.pdf")
        }else{
            bundle.putString("filePath", getPdfPath())
            bundle.putString("tempPath", Environment.getExternalStorageDirectory().path)
        }
        var result = tbsReaderView!!.preOpen(parseFormat(parseName()),false)
        if (result){
            tbsReaderView!!.openFile(bundle)
        }else{
            QbSdk.openFileReader(this,"/storage/emulated/0/Download/wey.pdf",null, ValueCallback {
                logE("x5打卡文件PDF $it")
            })
        }
    }
  
  private fun parseFormat( fileName:String):String{
       return fileName.substring(fileName.lastIndexOf(".") + 1);
    }
  
 private fun parseName():String{
        return  PDF_PATH_NAME.substring(PDF_PATH_NAME.lastIndexOf("/")+1)
    }

隐式调用第三方应用打开PDF

    // PDF 文件保存路径
    val PDF_PATH: String = Environment.getExternalStorageDirectory().getPath().toString() + "/wey/"
    val PDF_PATH_NAME: String = "${PDF_PATH}wey.pdf"
    var file :File
    if(Build.VERSION.SDK_INT < Build.VERSION_CODES.Q){
       file= File(PDF_PATH_NAME)
      }else{
        file = File("/storage/emulated/0/Download/", fileName)
      }

       if(!file.exists()) {
           ToastUtils.s(this,"文件找不到")
             return@OnClickListener
         }
         val intent = Intent(Intent.ACTION_VIEW)
          var uri :Uri
         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ){
            uri = Uri.parse(PDF_PATH_NAME)
             if( Build.VERSION.SDK_INT >=Build.VERSION_CODES.Q){
                 uri = Uri.parse(PDF_PATH_Q_NAME)
                 }
           }else{
                 uri = Uri.fromFile(file)
           }
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            intent.setDataAndType(uri, "application/pdf")
            var componentName:ComponentName = intent.resolveActivity(packageManager)
            if(componentName == null){
                ToastUtils.s(this,"没有可用的其他程序")
                 return@OnClickListener
            }else{
                    logE("跳转程序 $componentName")
            }
            try {
                startActivityForResult(intent,PDF_JUMP_CODE)
            } catch(e: ActivityNotFoundException) {
                Log.e("URLSpan","Activity was not found for intent, $intent")
           }
  override fun onDestroy() {
        super.onDestroy()
        mBinding.webView.clearCache(true)
        mBinding.webView.clearFormData()
        mBinding.webView.destroy()
        tbsReaderView!!.onStop()
    }