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

使用iText 7.1.17库写入PDF时应用崩溃闪退求助

问题描述

使用iText 7.1.17库在Android上写入PDF时应用崩溃闪退,仅生成空白PDF。已添加存储权限,尝试更换内置字体、更换库版本均无效;切换PDFBox出现严重库冲突,系统内置库不支持水印和密码功能。获取到的错误日志如下(注:该日志来自编辑器而非运行时):

依赖配置

dependencies {
    implementation 'androidx.appcompat:appcompat:1.7.0-alpha01'
    implementation 'com.google.android.material:material:1.8.0-rc01'
    implementation 'androidx.constraintlayout:constraintlayout:2.2.0-alpha05'
    implementation 'com.itextpdf:kernel:7.1.17'
    implementation 'com.itextpdf:layout:7.1.17'
    implementation 'com.itextpdf:io:7.1.17'
}

实现代码

public class MainActivity extends AppCompatActivity {

private static final int REQUEST_WRITE_PERMISSION = 1;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
    != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this,
        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_PERMISSION);
        } else {
        pdfWriter();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_WRITE_PERMISSION) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            pdfWriter();
            } else {
            System.out.println("Permission Denied!");
        }
    }
}

public void pdfWriter() {
    PdfWriter writer = null;
    PdfDocument pdf = null;
    Document document = null;
    
    try {
        
        String pdfPath = getExternalFilesDir(null) + "/invoice.pdf";
        
        
        writer = new PdfWriter(pdfPath);
        pdf = new PdfDocument(writer);
        document = new Document(pdf);
        
        
        document.add(new Paragraph("Sales Invoice")
        .setFontSize(18)
        .setBold()
        .setMarginBottom(20));
        
        
        document.add(new Paragraph("Seller: ABC Store\nAddress: Main Street, City\nPhone: 123456789")
        .setFontSize(12)
        .setMarginBottom(10));
        document.add(new Paragraph("Customer: John Smith\nAddress: Future District, City\nPhone: 987654321")
        .setFontSize(12)
        .setMarginBottom(20));
        
        
        float[] columnWidths = {50, 200, 100, 100};
        Table table = new Table(columnWidths);
        
        table.addCell(new Cell().add(new Paragraph("No.").setBold()));
        table.addCell(new Cell().add(new Paragraph("Product").setBold()));
        table.addCell(new Cell().add(new Paragraph("Quantity").setBold()));
        table.addCell(new Cell().add(new Paragraph("Price").setBold()));
        
        
        String[][] products = {
            {"1", "Laptop", "2", "$1500"},
            {"2", "Smartphone", "1", "$1200"},
            {"3", "Keyboard", "3", "$100"}
        };
        
        for (String[] product : products) {
            for (String data : product) {
                table.addCell(new Cell().add(new Paragraph(data)));
            }
        }
        
        
        document.add(table);
        
        
        document.add(new Paragraph("Total Amount: $4400")
        .setFontSize(14)
        .setBold()
        .setMarginTop(20));
        
        
        } catch (Exception e) {
        e.printStackTrace();
            } finally {
        
        if (document != null) {
            document.close();
        }
    }
}

获取到的错误日志

ERROR:  Failed to perform rewrite, java.lang.RuntimeException: Rewrite cancelled.
    at com.tyron.completion.util.RewriteUtil.lambda$performRewrite$0(RewriteUtil.java:33)
    at com.tyron.completion.util.RewriteUtil$$ExternalSyntheticLambda0.call(D8$$SyntheticClass:0)
    at com.google.common.util.concurrent.TrustedListenableFutureTask$TrustedFutureInterruptibleAsyncTask.runInterruptibly(TrustedListenableFutureTask.java:167)
    at com.google.common.util.concurrent.TrustedListenableFutureTask$TrustedFutureInterruptibleAsyncTask.runInterruptibly(TrustedListenableFutureTask.java:150)
    at com.google.common.util.concurrent.InterruptibleTask.run(InterruptibleTask.java:74)
    at com.google.common.util.concurrent.TrustedListenableFutureTask.run(TrustedListenableFutureTask.java:82)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:764)

ERROR:  Failed to perform rewrite, java.lang.RuntimeException: Rewrite cancelled.
    at com.tyron.completion.util.RewriteUtil.lambda$performRewrite$0(RewriteUtil.java:33)
    at com.tyron.completion.util.RewriteUtil$$ExternalSyntheticLambda0.call(D8$$SyntheticClass:0)
    at com.google.common.util.concurrent.TrustedListenableFutureTask$TrustedFutureInterruptibleAsyncTask.runInterruptibly(TrustedListenableFutureTask.java:167)
    at com.google.common.util.concurrent.TrustedListenableFutureTask$TrustedFutureInterruptibleAsyncTask.runInterruptibly(TrustedListenableFutureTask.java:150)
    at com.google.common.util.concurrent.InterruptibleTask.run(InterruptibleTask.java:74)
    at com.google.common.util.concurrent.TrustedListenableFutureTask.run(TrustedListenableFutureTask.java:82)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:764)
解决方案

1. 将PDF写入操作移至子线程

Android禁止在主线程执行耗时IO操作,这是导致崩溃的核心原因。修改代码,用线程执行pdfWriter():

// 替换原调用pdfWriter()的地方
new Thread(() -> {
    pdfWriter();
    // 操作完成后可通过runOnUiThread更新UI
    runOnUiThread(() -> {
        Toast.makeText(MainActivity.this, "PDF生成完成", Toast.LENGTH_SHORT).show();
    });
}).start();

2. 完善异常处理,捕获真实运行错误

原日志是编辑器的重写错误,并非运行时崩溃日志。修改catch块,将错误信息输出到Logcat并提示用户:

catch (Exception e) {
    Log.e("PDF_ERROR", "生成PDF失败", e);
    runOnUiThread(() -> {
        Toast.makeText(MainActivity.this, "生成PDF失败:" + e.getMessage(), Toast.LENGTH_LONG).show();
    });
}

3. 优化资源关闭逻辑

虽然document.close()会自动关闭PdfDocument和PdfWriter,但确保在异常情况下资源正确释放,可调整finally块:

finally {
    try {
        if (document != null) {
            document.close();
        }
    } catch (Exception e) {
        Log.e("PDF_ERROR", "关闭文档失败", e);
    }
}

4. 调整依赖与权限

  • 从Android 10(API 29)开始,getExternalFilesDir(null)属于应用私有外部存储,无需申请WRITE_EXTERNAL_STORAGE权限,可移除权限申请代码,避免不必要的权限请求。
  • 建议使用iText 7的最新稳定版,替换旧版本依赖,比如:
implementation 'com.itextpdf:kernel:7.2.5'
implementation 'com.itextpdf:layout:7.2.5'
implementation 'com.itextpdf:io:7.2.5'

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 12:17:04