Android WebView 或者 HTML 转化成 PDF 原生实现

以前有个需求就是要把webview打印成pdf保存到本地然后上传的问题,然后百度google了一大堆,大部分还都是用第三方的库来实现,然而并不太好用,偶尔看了一篇博客用原生的API来打印,这两天再找那个博客,竟然没了,所以写个博客记录一下,万一以后用得着还能有个记录

话不多少直接上代码:


    private void webViewToPdf () {
        //创建DexMaker缓存目录
        try {
            File pdfFile = new File(pdfFilePath);
            if (pdfFile.exists()) {
                pdfFile.delete();
            }
            pdfFile.createNewFile();
            descriptor = ParcelFileDescriptor.open(pdfFile, ParcelFileDescriptor.MODE_READ_WRITE);
            // 设置打印参数
            PrintAttributes.MediaSize isoA4 = PrintAttributes.MediaSize.ISO_A4;
            PrintAttributes attributes = new PrintAttributes.Builder()
                    .setMediaSize(isoA4)
                    .setResolution(new PrintAttributes.Resolution("id", Context.PRINT_SERVICE, 240, 240))
                    .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
                    .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
                    .build();
            // 计算webview打印需要的页数
            int numberOfPages = (int) ((mWebView.getContentHeight() * 240 / (isoA4.getHeightMils())) );
            ranges = new PageRange[]{new PageRange(0, numberOfPages)};
            // 创建pdf文件缓存目录
            // 获取需要打印的webview适配器
            printAdapter = mWebView.createPrintDocumentAdapter();
            // 开始打印
            printAdapter.onStart();
            printAdapter.onLayout(attributes, attributes, new CancellationSignal(),
                    getLayoutResultCallback(new InvocationHandler() {
                        @Override
                        public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
                            if (method.getName().equals("onLayoutFinished")) {
                                // 监听到内部调用了onLayoutFinished()方法,即打印成功
                                onLayoutSuccess();
                            } else {
                                // 监听到打印失败或者取消了打印
                                Toast.makeText(MainActivity.this, "导出失败,请重试", Toast.LENGTH_SHORT).show();
                            }
                            return null;
                        }
                    }), new Bundle());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void onLayoutSuccess () throws IOException {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            PrintDocumentAdapter.WriteResultCallback callback = getWriteResultCallback(new InvocationHandler() {
                @Override
                public Object invoke (Object o, Method method, Object[] objects) {
                    if (method.getName().equals("onWriteFinished")) {
                        Toast.makeText(MainActivity.this, "导出成功", Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(MainActivity.this, "导出失败", Toast.LENGTH_SHORT).show();
                    }
                    return null;
                }
            });
            printAdapter.onWrite(ranges, descriptor, new CancellationSignal(), callback);
        }
    }

    public static PrintDocumentAdapter.LayoutResultCallback getLayoutResultCallback (InvocationHandler invocationHandler) throws IOException {
        return ProxyBuilder.forClass(PrintDocumentAdapter.LayoutResultCallback.class)
                .handler(invocationHandler)
                .build();
    }

    public static PrintDocumentAdapter.WriteResultCallback getWriteResultCallback (InvocationHandler invocationHandler) throws IOException {
        return ProxyBuilder.forClass(PrintDocumentAdapter.WriteResultCallback.class)
                .handler(invocationHandler)
                .build();
    }

需要注意的点:

1.需要导入一个三分库 implementation 'com.linkedin.dexmaker:dexmaker-mockito:2.16.0'

2.new PrintAttributes.Resolution("id", Context.PRINT_SERVICE, 240,240)参数不太知道有什么用虽然说的是dpi但是我用500和240保存出来的pdf文件没什么不同

3.需要网络权限和写入硬盘权限

4.是否需要子线程的问题

5.页数问题最好是确定数量,算的方法有可能有问题

demo地址:WebView转PDF

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值