You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Kotlin中直接打印指定路径PDF(无确认对话框)

实现无弹窗直接打印PDF(首次选打印机)

完全可以实现你要的功能,核心思路是保存首次选择的打印机ID,后续打印直接调用该打印机,跳过所有确认弹窗。下面是具体实现步骤:

1. 持久化存储打印机ID

用SharedPreferences保存用户首次选择的打印机ID,确保重启应用后仍能复用:

private fun savePrinterId(printerId: String) {
    getSharedPreferences("PrintPrefs", MODE_PRIVATE)
        .edit()
        .putString("selected_printer_id", printerId)
        .apply()
}

private fun getSavedPrinterId(): String? {
    return getSharedPreferences("PrintPrefs", MODE_PRIVATE)
        .getString("selected_printer_id", null)
}

2. 创建PDF打印适配器

实现PrintDocumentAdapter,负责向系统打印框架提供PDF文件的数据流:

private fun createPdfPrintAdapter(file: File): PrintDocumentAdapter {
    return object : PrintDocumentAdapter() {
        override fun onLayout(
            oldAttributes: PrintAttributes?,
            newAttributes: PrintAttributes?,
            cancellationSignal: CancellationSignal?,
            callback: LayoutResultCallback?,
            extras: Bundle?
        ) {
            if (cancellationSignal?.isCanceled == true) {
                callback?.onLayoutCancelled()
                return
            }
            val printInfo = PrintDocumentInfo.Builder(file.name)
                .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
                .setPageCount(PrintDocumentInfo.PAGE_COUNT_UNKNOWN)
                .build()
            callback?.onLayoutFinished(printInfo, oldAttributes != newAttributes)
        }

        override fun onWrite(
            pages: Array<out PageRange>?,
            destination: ParcelFileDescriptor?,
            cancellationSignal: CancellationSignal?,
            callback: WriteResultCallback?
        ) {
            if (cancellationSignal?.isCanceled == true) {
                callback?.onWriteCancelled()
                return
            }
            try {
                val input = FileInputStream(file)
                val output = FileOutputStream(destination?.fileDescriptor)
                input.copyTo(output)
                callback?.onWriteFinished(arrayOf(PageRange.ALL_PAGES))
            } catch (e: Exception) {
                callback?.onWriteFailed(e.localizedMessage)
            }
        }
    }
}

3. 整合自动打印逻辑

在generatePDF函数的Toast提示后,添加打印判断逻辑:

// 原generatePDF函数末尾 Toast之后添加:
val printManager = getSystemService(Context.PRINT_SERVICE) as PrintManager
val printAdapter = createPdfPrintAdapter(file)
val printJobName = "打印徽章PDF"

val savedPrinterId = getSavedPrinterId()
if (savedPrinterId != null) {
    // 直接使用保存的打印机打印,无任何弹窗
    printManager.print(
        printJobName,
        printAdapter,
        PrintAttributes.Builder().build(),
        savedPrinterId
    )
} else {
    // 首次打印,弹出打印机选择界面
    val printIntent = printManager.createPrintJobIntent(printJobName, printAdapter)
    startActivityForResult(printIntent, 1001)
}

4. 处理打印机选择结果

重写onActivityResult(AndroidX可改用registerForActivityResult),保存用户选中的打印机ID并触发首次打印:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == 1001 && resultCode == RESULT_OK) {
        val printerId = data?.getStringExtra(PrintManager.EXTRA_PRINTER_ID)
        printerId?.let {
            savePrinterId(it)
            // 首次选择后立即打印
            val printManager = getSystemService(Context.PRINT_SERVICE) as PrintManager
            val printAdapter = createPdfPrintAdapter(File("/storage/emulated/0/Download/Badges/badge.pdf"))
            printManager.print("打印徽章PDF", printAdapter, PrintAttributes.Builder().build(), it)
        }
    }
}

关键注意事项

  • 权限:Android 10及以下需申请READ_EXTERNAL_STORAGE权限;Android 11+访问公共Download目录无需额外权限。
  • 兼容性:部分小众打印机可能不支持无弹窗直接打印,建议测试主流品牌设备。
  • 状态监听:可通过PrintJob对象监听打印成功/失败状态,做后续提示或重试逻辑。

内容的提问来源于stack exchange,提问作者kartik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 20:37:28