Web - lydGit/Notes GitHub Wiki
Web界面显示转PDF文件
功能要求:把H5的网页报表转成PDF文件 参考:Android Webview生成和导出PDF解决方案探索
1:PdfDocument,PrintedPdfDocument
实现的功能差不多,都是把View中显示的内容转成PDF的格式,主要不同的是PrintedPdfDocument可以设置打印参数,如纸张大小,像素等!但是WebView中他只会转换界面显示的内容,不显示的部分做转换!(PdfDocument|PrintedPdfDocument)
2:PrintManager
调用系统打印方法,弹出一个系统窗口对打印参数进行设置或打印效果进行预览。
PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE);
// Get a print adapter instance
// MyCreatePrintDocumentAdapter为继承PrintDocumentAdapter抽象类的子类
PrintDocumentAdapter printAdapter = new MyCreatePrintDocumentAdapter();
// Create a print job with name and adapter instance
String jobName = context.getString(com.sumxiang.noteapp.R.string.app_name) + " Document";
PrintAttributes attributes = new PrintAttributes.Builder()
.setMediaSize(PrintAttributes.MediaSize.ISO_A4)
.setResolution(new PrintAttributes.Resolution("id", Context.PRINT_SERVICE, 300, 300))
.setColorMode(PrintAttributes.COLOR_MODE_COLOR)
.setMinMargins(PrintAttributes.Margins.NO_MARGINS)
.build();
// 这里第三个参数可以传自定义attributes,也可以直接传null,此时将使用默认配置。
printManager.print(jobName, printAdapter, attributes);
3:WebView>>Bitmap>>PDF(未验证方法,记录个思路)
大概流程:先将WebView转成Bitmap格式,然后根据设置好的的打印样式的大小,将Bitmap裁剪为多张Bitmap。然后再转成pdf格式!实现起来十分困难!
4:PrintDocumentAdapter+DexMaker
通过DexMaker中的ProxyBuilder.forClass()动态生成的代理类来替代真正的实体类来截取PrintDocumentAdapter中的方法。
public void savePDFFile(File saveFile) {
//手机系统4.4以下的手机不能使用该功能
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {
CommonUtil.toast(R.string.tv_common_stystem_version_low);
return;
}
try {
ParcelFileDescriptor descriptor = ParcelFileDescriptor.open(saveFile, ParcelFileDescriptor.MODE_READ_WRITE);
// 设置打印参数
PrintAttributes attributes = new PrintAttributes.Builder()
.setMediaSize(PrintAttributes.MediaSize.ISO_A4)
.setResolution(new PrintAttributes.Resolution("id", Context.PRINT_SERVICE, 300, 300))
.setColorMode(PrintAttributes.COLOR_MODE_COLOR)
.setMinMargins(PrintAttributes.Margins.NO_MARGINS)
.build();
PrintDocumentAdapter documentAdapter = webView.createPrintDocumentAdapter();
documentAdapter.onStart();
//文件暂存路径
File dexCacheFile = webView.getContext().getDir("dex", 0);
if (!dexCacheFile.exists()) {
dexCacheFile.mkdir();
}
//设置打印页数,但经过测试,暂无发现效果
PageRange ranges[] = new PageRange[]{new PageRange(1, 2)};
//监听文件是否打印
documentAdapter.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(documentAdapter, dexCacheFile, ranges, descriptor);
} else {
// 监听到打印失败或者取消了打印
documentAdapter.onFinish();
}
return null;
}
}, dexCacheFile.getAbsoluteFile()), new Bundle());
} catch (IOException e) {
e.printStackTrace();
}
}
private void onLayoutSuccess(PrintDocumentAdapter adapter, File dexCacheFile, PageRange[] ranges, ParcelFileDescriptor descriptor) throws IOException {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
PrintDocumentAdapter.WriteResultCallback callback = getWriteResultCallback((o, method, objects) -> {
if (method.getName().equals("onWriteFinished")) {
// PDF文件写入本地完成,导出成功
} else {
// 导出失败
}
adapter.onFinish();
return null;
}, dexCacheFile.getAbsoluteFile());
adapter.onWrite(ranges, descriptor, new CancellationSignal(), callback);
}
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static PrintDocumentAdapter.LayoutResultCallback getLayoutResultCallback(InvocationHandler invocationHandler, File dexCacheDir) throws IOException {
//创建一个动态生成的代理类来替代真正的实体类
return ProxyBuilder.forClass(PrintDocumentAdapter.LayoutResultCallback.class)
.dexCache(dexCacheDir)
.handler(invocationHandler)
.build();
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static PrintDocumentAdapter.WriteResultCallback getWriteResultCallback(InvocationHandler invocationHandler, File dexCacheDir) throws IOException {
//创建一个动态生成的代理类来替代真正的实体类
return ProxyBuilder.forClass(PrintDocumentAdapter.WriteResultCallback.class)
.dexCache(dexCacheDir)
.handler(invocationHandler)
.build();
}
WebView加载https时界面或图片空白
当WebView使用loadUrl方法加载通过ssl加密的https页面时,如果这个网站的安全证书在Android无法得到认证,WebView就会变成一个空白页,而不会像自带的浏览器一样弹出提示。(部分系统可能出现的是图片空白) 参考:Webview 访问https页面 SslError 处理
WebView webview = (WebView) findViewById(R.id.webview);
webview.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
//handler.cancel(); 默认的处理方式,WebView变成空白页
//handler.process();接受证书
//handleMessage(Message msg); 其他处理
}
});
如果当重载函数里面是process()时,系统就会忽略证书的错误继续Load页面内容,不会显示空白页面。