//使用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()
}