一:添加依赖
implementation 'com.itextpdf:itext7-core:7.1.13'
二:清单文件AndroidManifest.xml
添加权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
在<application>中添加
android:requestLegacyExternalStorage="true"
添加provider
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.demo.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
在res目录下新建xml目录,并创建provider_paths.xml文件
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="."/>
</paths>
三:文件工具类FileUtils
package com.example.demo;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.widget.Toast;
import androidx.core.content.FileProvider;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class FileUtils {
/**
* 获取包含文件的应用程序路径
*
* @return String 根目录路径
*/
public static String getAppPath() {
File dir = new File(android.os.Environment.getExternalStorageDirectory()
+ File.separator
+ "PDF"
+ File.separator);
if (!dir.exists()) {
dir.mkdirs();
}
return dir.getPath() + File.separator;
}
/**
* 打开PDF文件
* @param context
* @param url
* @throws ActivityNotFoundException
* @throws IOException
*/
public static void openFile(Context context, File url) throws ActivityNotFoundException {
if (url.exists()) {
Uri uri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".fileprovider", url);
String urlString = url.toString().toLowerCase();
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
/**
* Security
*/
List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
// 通过比较url和扩展名,检查您要打开的文件类型。
// 当if条件匹配时,插件设置正确的意图(mime)类型
// 所以Android知道用什么程序打开文件
if (urlString.toLowerCase().contains(".doc")
|| urlString.toLowerCase().contains(".docx")) {
// Word document
intent.setDataAndType(uri, "application/msword");
} else if (urlString.toLowerCase().contains(".pdf")) {
// PDF file
intent.setDataAndType(uri, "application/pdf");
} else if (urlString.toLowerCase().contains(".ppt")
|| urlString.toLowerCase().contains(".pptx")) {
// Powerpoint file
intent.setDataAndType(uri, "application/vnd.ms-powerpoint");
} else if (urlString.toLowerCase().contains(".xls")
|| urlString.toLowerCase().contains(".xlsx")) {
// Excel file
intent.setDataAndType(uri, "application/vnd.ms-excel");
} else if (urlString.toLowerCase().contains(".zip")
|| urlString.toLowerCase().contains(".rar")) {
// ZIP file
intent.setDataAndType(uri, "application/trap");
} else if (urlString.toLowerCase().contains(".rtf")) {
// RTF file
intent.setDataAndType(uri, "application/rtf");
} else if (urlString.toLowerCase().contains(".wav")
|| urlString.toLowerCase().contains(".mp3")) {
// WAV/MP3 audio file
intent.setDataAndType(uri, "audio/*");
} else if (urlString.toLowerCase().contains(".gif")) {
// GIF file
intent.setDataAndType(uri, "image/gif");
} else if (urlString.toLowerCase().contains(".jpg")
|| urlString.toLowerCase().contains(".jpeg")
|| urlString.toLowerCase().contains(".png")) {
// JPG file
intent.setDataAndType(uri, "image/jpeg");
} else if (urlString.toLowerCase().contains(".txt")) {
// Text file
intent.setDataAndType(uri, "text/plain");
} else if (urlString.toLowerCase().contains(".3gp")
|| urlString.toLowerCase().contains(".mpg")
|| urlString.toLowerCase().contains(".mpeg")
|| urlString.toLowerCase().contains(".mpe")
|| urlString.toLowerCase().contains(".mp4")
|| urlString.toLowerCase().contains(".avi")) {
// Video files
intent.setDataAndType(uri, "video/*");
} else {
// 如果你愿意,你也可以为任何其他文件定义意图类型
// 另外,使用下面的else子句来管理其他未知扩展
// 在这种情况下,Android将显示设备上安装的所有应用程序
// 因此您可以选择使用哪个应用程序
intent.setDataAndType(uri, "*/*");
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} else {
Toast.makeText(context, "文件不存在", Toast.LENGTH_SHORT).show();
}
}
}
四:权限工具类Permissions
package com.example.demo;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.provider.Settings;
public class Permissions {
/**
* 弹出权限提示框
*/
public static void showPermissionsSettingDialog(Context context, String permission) {
String msg = "";
if (permission.equals("android.permission.READ_EXTERNAL_STORAGE") ||
permission.equals("android.permission.WRITE_EXTERNAL_STORAGE")) {
msg= "本App需要“允许储存空间”权限才能正常运行,请点击确定,进入设置界面进行授权处理";
}
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(msg);
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
showSettings(context);
}
});
builder.setCancelable(false);
builder.show();
}
/**
* 如果授权失败,就要进入App权限设置界面
*/
public static void showSettings(Context context) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", context.getPackageName(), null);
intent.setData(uri);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
五:布局文件activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/create_pdf"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="生成PDF文件"
android:layout_marginTop="100dp"
android:layout_marginBottom="30dp"/>
<Button
android:id="@+id/open_pdf"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="打开PDF文件"/>
</LinearLayout>
六:使用iText7生成PDF文件,并打开PDF文件
package com.example.demo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.itextpdf.kernel.colors.Color;
import com.itextpdf.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfDocumentInfo;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.draw.SolidLine;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.LineSeparator;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Text;
import com.itextpdf.layout.property.TextAlignment;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
private Button create_pdf;
private Button open_pdf;
private String path;
private Context context;
private boolean isPermissions = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestPermission();
initView();
}
private void initView() {
create_pdf = findViewById(R.id.create_pdf);
open_pdf = findViewById(R.id.open_pdf);
context = getApplicationContext();
path = FileUtils.getAppPath() + "test.pdf";
Log.e("pdf保存路径", path);
create_pdf.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
createPDF(path);
}
});
open_pdf.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openPDF();
}
});
}
/**
* 创建PDF文件
*/
private void createPDF(String path) {
if (isPermissions) {
File file = new File(path);
if (file.exists()) {
file.delete();
}
file.getParentFile().mkdirs();
// 创建Document
PdfWriter writer = null;
try {
writer = new PdfWriter(new FileOutputStream(path));
} catch (FileNotFoundException e) {
Log.e("FileNotFoundException", e.toString());
}
PdfDocument pdf_document = new PdfDocument(writer);
// 生成的PDF文档信息
PdfDocumentInfo info = pdf_document.getDocumentInfo();
// 标题
info.setTitle("First pdf file");
// 作者
info.setAuthor("Quinto");
// 科目
info.setSubject("test");
// 关键词
info.setKeywords("pdf");
// 创建日期
info.setCreator("2022-10-20");
Document document = new Document(pdf_document, PageSize.A4, true);
// 文字字体(显示中文)、大小、颜色
PdfFont font = null;
try {
font = PdfFontFactory.createFont("STSong-Light","UniGB-UCS2-H");
} catch (IOException e) {
Log.e("IOException", e.toString());
}
float title_size = 36.0f;
float text_title_size = 30.0f;
float text_size = 24.0f;
Color title_color = new DeviceRgb(0, 0, 0);
Color text_title_color = new DeviceRgb(65, 136, 160);
Color text_color = new DeviceRgb(43, 43, 43);
// 行分隔符
// 实线:SolidLine() 点线:DottedLine() 仪表盘线:DashedLine()
LineSeparator separator = new LineSeparator(new SolidLine());
separator.setStrokeColor(new DeviceRgb(0, 0, 68));
// 添加大标题
Text title = new Text("这里是pdf文件标题").setFont(font).setFontSize(title_size).setFontColor(title_color);
Paragraph paragraph_title = new Paragraph(title).setTextAlignment(TextAlignment.CENTER);
document.add(paragraph_title);
for (int i = 1; i < 10; i++) {
// 添加文本小标题
Text text_title = new Text("第" + i + "行:").setFont(font).setFontSize(text_title_size).setFontColor(text_title_color);
Paragraph paragraph_text_title = new Paragraph(text_title);
document.add(paragraph_text_title);
// 添加文本内容
String content = "我是文本内容" + i + i + i + i + i + i + i + i + i + i;
Text text = new Text(content).setFont(font).setFontSize(text_size).setFontColor(text_color);
Paragraph paragraph_text = new Paragraph(text);
document.add(paragraph_text);
// 添加可换行空间
document.add(new Paragraph(""));
// 添加水平线
document.add(separator);
// 添加可换行空间
document.add(new Paragraph(""));
}
/**
* 添加列表
*/
List list = new List().setSymbolIndent(12).setListSymbol("\u2022").setFont(font);
list.add(new ListItem("列表1"))
.add(new ListItem("列表2"))
.add(new ListItem("列表3"));
document.add(list);
/**
* 添加图片
*/
Text text_image = new Text("图片:").setFont(font).setFontSize(text_title_size).setFontColor(text_title_color);
Paragraph image = new Paragraph(text_image);
document.add(image);
Image image1 = null;
Image image2 = null;
Image image3 = null;
try {
image1 = new Image(ImageDataFactory.create("/storage/emulated/0/DCIM/Camera/IMG_20221003_181926.jpg")).setWidth(PageSize.A4.getWidth() * 2 / 3);
image2 = new Image(ImageDataFactory.create("/storage/emulated/0/Download/互传/folder/证件/XHS_159716343059020494b83-da6a-39d7-ae3b-13fd92cfbb53.jpg")).setWidth(PageSize.A4.getWidth() / 3) ;
image3 = new Image(ImageDataFactory.create("/storage/emulated/0/Download/互传/folder/证件/XHS_1597163520524f0b4df77-8db1-35c6-9dfa-3e0aa74f1fef.jpg")).setWidth(PageSize.A4.getWidth() / 3);
} catch (MalformedURLException e) {
Log.e("MalformedURLException", e.toString());
}
Paragraph paragraph_image = new Paragraph().add(image1)
.add(" ")
.add(image2)
.add(" ")
.add(image3);
document.add(paragraph_image);
document.add(new Paragraph(""));
/**
* 添加表格
*/
Text text_table = new Text("表单:").setFont(font).setFontSize(text_title_size).setFontColor(text_title_color);
Paragraph paragraph_table = new Paragraph(text_table);
document.add(paragraph_table);
// 3列
float[] pointColumnWidths = {100f, 100f, 100f};
Table table = new Table(pointColumnWidths);
// 设置边框样式、颜色、宽度
Color table_color = new DeviceRgb(80, 136, 255);
Border border = new DottedBorder(table_color, 3);
table.setBorder(border);
// 设置单元格文本居中
table.setTextAlignment(TextAlignment.CENTER);
// 添加单元格内容
Color table_header = new DeviceRgb(0, 0, 255);
Color table_content = new DeviceRgb(255, 0, 0);
Color table_footer = new DeviceRgb(0, 255, 0);
Text text1 = new Text("姓名").setFont(font).setFontSize(20.0f).setFontColor(table_header);
Text text2 = new Text("年龄").setFont(font).setFontSize(20.0f).setFontColor(table_header);
Text text3 = new Text("性别").setFont(font).setFontSize(20.0f).setFontColor(table_header);
table.addHeaderCell(new Paragraph(text1));
table.addHeaderCell(new Paragraph(text2));
table.addHeaderCell(new Paragraph(text3));
Text text4 = new Text("张三").setFont(font).setFontSize(15.0f).setFontColor(table_content);
Text text5 = new Text("30").setFont(font).setFontSize(15.0f).setFontColor(table_content);
Text text6 = new Text("男").setFont(font).setFontSize(15.0f).setFontColor(table_content);
table.addCell(new Paragraph(text4));
table.addCell(new Paragraph(text5));
table.addCell(new Paragraph(text6));
Text text7 = new Text("丽萨").setFont(font).setFontSize(15.0f).setFontColor(table_footer);
Text text8 = new Text("20").setFont(font).setFontSize(15.0f).setFontColor(table_footer);
Text text9 = new Text("女").setFont(font).setFontSize(15.0f).setFontColor(table_footer);
table.addFooterCell(new Paragraph(text7));
table.addFooterCell(new Paragraph(text8));
table.addFooterCell(new Paragraph(text9));
// 将表格添加进pdf文件
document.add(table);
/**
* 添加页眉、页脚、水印
*/
Rectangle pageSize;
PdfCanvas canvas;
int n = pdf_document.getNumberOfPages();
for (int i = 1; i <= n; i++) {
PdfPage page = pdf_document.getPage(i);
pageSize = page.getPageSize();
canvas = new PdfCanvas(page);
// 页眉
canvas.beginText().setFontAndSize(font, 7)
.moveText(pageSize.getWidth() / 2 - 18, pageSize.getHeight() - 10)
.showText("我是页眉")
.endText();
// 页脚
canvas.setStrokeColor(text_color)
.setLineWidth(.2f)
.moveTo(pageSize.getWidth() / 2 - 30, 20)
.lineTo(pageSize.getWidth() / 2 + 30, 20).stroke();
canvas.beginText().setFontAndSize(font, 7)
.moveText(pageSize.getWidth() / 2 - 6, 10)
.showText(String.valueOf(i))
.endText();
// 水印
Paragraph p = new Paragraph("Quinto").setFontSize(60);
canvas.saveState();
PdfExtGState gs1 = new PdfExtGState().setFillOpacity(0.2f);
canvas.setExtGState(gs1);
document.showTextAligned(p, pageSize.getWidth() / 2, pageSize.getHeight() / 2,
pdf_document.getPageNumber(page),
TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45);
canvas.restoreState();
}
// 关闭
document.close();
Toast.makeText(this, "PDF文件已生成", Toast.LENGTH_SHORT).show();
} else {
requestPermission();
}
}
/**
* 打开PDF文件
*/
private void openPDF() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
try {
FileUtils.openFile(context, new File(path));
} catch (Exception e) {
Log.e("Exception", e.toString());
}
}
}, 1000);
}
/**
* 动态申请权限
*/
private void requestPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// 先判断有没有权限
if (Environment.isExternalStorageManager()) {
isPermissions = true;
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("生成PDF文件需要“允许所有文件访问”权限才能正常运行,请点击确定,进入设置界面进行授权处理");
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startActivityForResult(new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION), 1024);
}
});
builder.setCancelable(false);
builder.show();
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 先判断有没有权限
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
isPermissions = true;
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1024);
}
} else {
isPermissions = true;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1024) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
isPermissions = true;
} else {
//拒绝就要强行跳转设置界面
Permissions.showPermissionsSettingDialog(this, permissions[0]);
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (requestCode == 1024 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (Environment.isExternalStorageManager()) {
isPermissions = true;
} else {
Toast.makeText(context, "存储权限获取失败", Toast.LENGTH_SHORT).show();
}
}
}
}
七:生成的PDF文件预览图