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

Android Studio中Canvas生成PDF并存储到设备功能失效求助

Android 生成PDF保存到公共下载目录问题修复

现有代码核心问题

  • 路径不符合需求:当前代码将PDF保存到应用专属缓存目录externalCacheDir,并非系统公共下载目录,用户无法在下载管理器/下载文件夹中找到文件,且直接使用!!断言可能为空的externalCacheDir会触发空指针崩溃
  • Paint未配置基础属性:未设置文字大小、颜色等属性,默认参数可能导致生成的PDF文字不可见
  • 未适配高版本安卓存储规则:Android 10(API 29)及以上版本禁止直接通过File路径访问公共存储目录,即使申请了存储权限也会写入失败
  • 资源未安全关闭:FileOutputStream未在finally块中关闭,存在内存泄露风险
  • 异常捕获范围太窄:仅捕获IOException,未覆盖空指针、权限拒绝等其他运行时异常

修复后的实现代码

import android.content.ContentValues
import android.content.Context
import android.graphics.Paint
import android.graphics.pdf.PdfDocument
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import java.io.IOException
import java.io.OutputStream

fun createPdf(text: String, context: Context) {
    // 初始化PDF文档和页面配置
    val pdfDocument = PdfDocument()
    val pageInfo = PdfDocument.PageInfo.Builder(1240, 1754, 1).create()
    val page = pdfDocument.startPage(pageInfo)
    val canvas = page.canvas

    // 配置Paint属性,避免文字不可见
    val paint = Paint().apply {
        textSize = 40f 
        color = android.graphics.Color.BLACK 
        isAntiAlias = true 
    }

    // 绘制文本
    canvas.drawText(text, 40f, 50f, paint)
    pdfDocument.finishPage(page)

    // 写入文件到公共下载目录
    var outputStream: OutputStream? = null
    try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // Android 10及以上使用MediaStore写入下载目录
            val contentValues = ContentValues().apply {
                put(MediaStore.Downloads.DISPLAY_NAME, "FirstPdf.pdf")
                put(MediaStore.Downloads.MIME_TYPE, "application/pdf")
                put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
            }
            val contentResolver = context.contentResolver
            val uri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)
                ?: throw IOException("无法创建下载目录文件")
            outputStream = contentResolver.openOutputStream(uri)
        } else {
            // Android 9及以下直接使用File路径写入
            val downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
            val file = java.io.File(downloadDir, "FirstPdf.pdf")
            outputStream = java.io.FileOutputStream(file)
        }

        outputStream?.let {
            pdfDocument.writeTo(it)
        } ?: throw IOException("文件输出流创建失败")
    } catch (e: Exception) {
        e.printStackTrace()
        // 可在这里添加自定义错误回调逻辑,告知用户生成失败
    } finally {
        // 安全关闭资源
        outputStream?.close()
        pdfDocument.close()
    }
}

配套权限配置

需要在AndroidManifest.xml中添加对应权限:

<!-- Android 9及以下需要存储写入权限 -->
<uses-permission
    android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="28" />

Android 6.0到Android 9版本运行时需要动态申请WRITE_EXTERNAL_STORAGE权限,Android 10及以上不需要申请存储权限即可写入公共下载目录。

内容的提问来源于stack exchange,提问作者Mehdi.ncb

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 16:15:01