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

Android应用无法向外部存储Download文件夹写入生成的PDF文件问题求解

安卓外部存储生成PDF失败问题解决方案

问题根因

  • 动态权限缺失:Android 6.0(API 23)及以上系统,存储类权限仅在Manifest中声明无效,必须主动触发动态申请流程由用户授权,你当前的代码只做了权限校验,没有申请逻辑,所以checkSelfPermission返回PERMISSION_DENIED(值为-1)。
  • 权限规则过时:你的targetSdk版本为31(对应Android 12),WRITE_EXTERNAL_STORAGE权限在Android 10(API 29)及以上版本已经被官方废弃,即便申请也不会获得授权。
  • 路径规则变更:你使用的Environment.getExternalStorageDirectory()在API 29及以上已被禁止直接访问,无法在外部存储根目录自建文件夹写入文件。

修复步骤

  1. 修改AndroidManifest.xml配置
    在<application>节点中添加过渡适配属性,临时兼容旧存储逻辑:
android:requestLegacyExternalStorage="true"

如果你的应用不需要访问其他应用的私有文件,仅需要写入公共Download目录,可以删除Manifest中WRITE_EXTERNAL_STORAGE的声明,API 30+写入公共媒体/下载目录不需要该权限。
2. 补充动态权限申请逻辑
在onCreate方法中增加权限校验和申请逻辑,适配Android 6.0-Android 9的设备。
3. 调整存储路径
不要在外部存储根目录自建文件夹,改为写入系统公共Download目录,符合系统存储规范。

核心修改代码示例

动态权限申请代码(添加到onCreate方法中)

// 存储权限申请请求码
private static final int REQUEST_STORAGE_PERMISSION = 1001;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_save_path);
    Button btnShowPath = findViewById(R.id.btnPath);

    // 先校验权限,未授权则申请
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_STORAGE_PERMISSION);
        btnShowPath.setEnabled(false);
    }

    btnShowPath.setOnClickListener(v -> {
        try {
            writeFile();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    });
}

// 接收权限申请结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_STORAGE_PERMISSION) {
        Button btnShowPath = findViewById(R.id.btnPath);
        btnShowPath.setEnabled(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED);
    }
}

writeFile方法路径修改

public void writeFile() throws FileNotFoundException {
    if (isExternalStorageWritable()) {
        // 改为写入系统公共Download目录
        File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
        File file = new File(dir, "newFile.pdf");
        FileOutputStream fOut = new FileOutputStream(file);
        
        // 后面的PDF生成逻辑保持不变即可
        Rectangle layout = new Rectangle(PageSize.ARCH_A);
        layout.setBorderColor(BaseColor.DARK_GRAY);
        layout.setBorderWidth(6);
        layout.setBorder(Rectangle.BOX);

        Document document = new Document(layout);
        PdfWriter writer = null;
        try {
            writer = PdfWriter.getInstance(document, fOut);
            document.open();
            PdfContentByte cb = writer.getDirectContent();
            float pdfPageWidth = document.getPageSize().getWidth();
            float pdfPageHeight = document.getPageSize().getHeight();

            document.add(new Paragraph("pdfPageWidth = "+pdfPageWidth));
            document.add(new Paragraph("pdfPageHeight = "+pdfPageHeight));

            Barcode39 barcode39 = new Barcode39();
            barcode39.setCode("123456789");
            Image code39Image = barcode39.createImageWithBarcode(cb, null, null);
            document.add(code39Image);
            document.newPage();
            document.close();
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    } else {
        Toast.makeText(getApplicationContext(), "无法访问外部存储", Toast.LENGTH_SHORT).show();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 18:15:04