Android 将webView中的内容生成到PDF文件中

    //使用dexmaker生成动态代理代理PrintDocumentAdapter.WriteResultCallback和PrintDocumentAdapter.LayoutResultCallback方法依赖
    implementation 'org.droidparts.dexmaker:dexmaker-mockito:1.5'    



    // web - pdf
    private lateinit var file : File
    private var dexCacheFile: File? = null
    // 获取需要打印的webview适配器
    private  var printAdapter: PrintDocumentAdapter? = null
    private  var ranges: Array<PageRange>? = null
    private  var descriptor: ParcelFileDescriptor? = null



    /**
     *  将webView中的内容生成到PDF格式
     *  @param webView 需要打印的webView
     * */
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private fun printPDFFile(webView: WebView) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
            /**
             * android 5.0之后,出于对动态注入字节码安全性德考虑,已经不允许随意指定字节码的保存路径了,需要放在应用自己的包名文件夹下。
             */
            //新的创建DexMaker缓存目录的方式,直接通过context获取路径
            dexCacheFile = getDir("dex", 0)
            if (!dexCacheFile!!.exists()) {
                dexCacheFile?.mkdir()
            }

            try {
                //创建待写入的PDF文件,PDFPATH为自行指定的PDF文件路径
                file = File(PDFPATH)
                if (file.exists()){
                    file.delete()
                }
                file.createNewFile()
                descriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE)
                // 设置打印参数
                val attributes = PrintAttributes.Builder()
                        .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
                        .setResolution(PrintAttributes.Resolution("id", Context.PRINT_SERVICE, 300, 300))
                        .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
                        .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
                        .build()
                //打印所有界面
                ranges = arrayOf(PageRange.ALL_PAGES)

                printAdapter = webView.createPrintDocumentAdapter("test")
                // 开始打印
                printAdapter!!.onStart()
                printAdapter!!.onLayout(attributes, attributes, CancellationSignal(), getLayoutResultCallback(InvocationHandler { proxy, method, args ->
                    if (method.name == "onLayoutFinished") {
                        // 监听到内部调用了onLayoutFinished()方法,即打印成功
                        onLayoutSuccess()
                    } else {
                        // 监听到打印失败或者取消了打印
                    }
                    null
                }, dexCacheFile!!.absoluteFile), Bundle())
            } catch (e: IOException) {
                e.printStackTrace()
            }

        }
    }

    /**
     * @throws IOException
     */
    @Throws(IOException::class)
    private fun onLayoutSuccess() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            val callback = getWriteResultCallback(InvocationHandler { o, method, objects ->
                if (method.name == "onWriteFinished") {
                    //ToastUtils.showShort("导出成功")
                    // PDF文件写入本地完成,导出成功
                    Log.e("onLayoutSuccess", "onLayoutSuccess")
                } else {
                    //ToastUtils.showShort("导出失败")
                    Log.e("onLayoutFailure", "onLayoutFailure")
                }
                null
            }, dexCacheFile!!.absoluteFile)
            //写入文件到本地
            try {
                printAdapter!!.onWrite(ranges, descriptor, CancellationSignal(), callback)
            }catch (e:IllegalStateException){
                e.printStackTrace()
            }
        } else {
            ToastUtils.showShort("当前系统不支持该功能")

        }
    }

    companion object {

        @SuppressLint("NewApi")
        @Throws(IOException::class)
        fun getLayoutResultCallback(invocationHandler: InvocationHandler, dexCacheDir: File): PrintDocumentAdapter.LayoutResultCallback {
            return ProxyBuilder.forClass(PrintDocumentAdapter.LayoutResultCallback::class.java)
                    .dexCache(dexCacheDir)
                    .handler(invocationHandler)
                    .build()
        }

        @SuppressLint("NewApi")
        @Throws(IOException::class)
        fun getWriteResultCallback(invocationHandler: InvocationHandler, dexCacheDir: File): PrintDocumentAdapter.WriteResultCallback {
            return ProxyBuilder.forClass(PrintDocumentAdapter.WriteResultCallback::class.java)
                    .dexCache(dexCacheDir)
                    .handler(invocationHandler)
                    .build()
        }
    

猜你喜欢

转载自blog.csdn.net/DengDongQi/article/details/80497402