以前有个需求就是要把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