本页内容
如何用Java开发一个Android PDF阅读器
本节将帮助您快速开始使用 ComPDFKit PDF SDK,并通过分步说明使用 Java 制作 Android 应用程序。通过以下步骤,您将获得一个简单的应用程序,可以显示指定 PDF 文件的内容。
创建新项目
- 使用 Android Studio 创建一个 Phone and Table 项目。这里我们创建一个 No Activity 项目。
添加 ComPDFKit PDF SDK 包
首先,我们需要导入 ComPDFKit PDF SDK。您可以通过两种方式集成它:使用 Gradle 集成或手动集成。
Gradle 集成
- 打开位于项目根目录中的 "settings.gradle" 文件,然后添 加 mavenCentral 存储库:
diff
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
+ mavenCentral()
}
}
- 在应用程序模块目录中打开 "build.gradle" 文件:
编辑它并添加完整的 ComPDFKit SDK 依赖项:
groovy
dependencies {
implementation 'com.compdf:compdfkit:2.2.0'
implementation 'com.compdf:compdfkit-ui:2.2.0'
}
- 在
AndroidManifest.xml
中申请读写权限:
xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
注: 对于面向 Android 6.0 或更高版本的应用程序,请确保在运行时检查并请求外部存储的读写权限。
- 如果您使用了在线认证的许可证,请在
AndroidManifest.xml
中添加网络访问权限:
xml
<uses-permission android:name="android.permission.INTERNET"/>
手动集成
- 将 "ComPDFKit.aar" 和 "ComPDFKit-UI.aar" 复制到 app 的 "libs" 目录中。
- 将以下代码添加到 app 目录下的 "build.gradle" 文件中:
groovy
...
dependencies {
/*ComPDFKit SDK*/
implementation(fileTree('libs'))
...
}
...
- 将 ComPDFKit PDF SDK for Android 作为项目的依赖项添加进去。在 app 目录下的 "build.gradle" 文件中,将 "ComPDFKit.aar" 、"ComPDFKit-UI.aar" 以及相关的支持库添加到
dependencies
中。为了简化操作,您可以按照以下方式更新依赖项:
groovy
dependencies {
...
//glide
implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
implementation 'androidx.documentfile:documentfile:1.0.1'
}
- 在
AndroidManifest.xml
中申请读写权限:
xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
注: 对于面向 Android 6.0 或更高版本的应用程序,请确保在运行时检查并请求外部存储的读写权限。
应用许可证密钥
具体步骤请参考应用许可证密钥
添加混淆
在 "proguard-rules.pro" 文件中,请添加 compdfkit 的混淆配置信息如下:
-keep class com.compdfkit.ui.** {*;}
-keep class com.compdfkit.core.** {*;}
显示PDF文档
- 将 PDF 文档复制到 Android 项目的 assets 目录中。例如,将文件 "Quick Start Guide.pdf" 导入到路径 src/main/assets 中。
- 在您的包下创建一个新的 Empty Activity,并将该 Activity 的名称设置为 MainActivity。
Android Studio将自动生成一个名为 "MainActivity.java" 的 source 文件和一个名为 "activity_main.xml" 的 layout 文件。
Source文件:
Layout文件:
- 在 "activity_main.xml" 中创建一个
CPDFReaderView
来显示 PDF 文档的内容:
xml
<!-- 你的 activity_main.xml 文件 -->
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!-- 创建一个 CPDFReaderView -->
<com.compdfkit.ui.reader.CPDFReaderView
android:id="@+id/readerview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
从布局中获取 CPDFReaderView
或者直接在对应的 MainActivity.java 文件中的代码中创建一个CPDFReaderView
:
Java
// 你的 MainActivity.java 文件。
package com.compdfkit.pdfviewer;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import com.compdfkit.ui.reader.CPDFReaderView;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 从xml中获取CPDFReaderView
CPDFReaderView readerView = findViewById(R.id.readerview);
// 创建CPDFReaderView的代码。
// CPDFDocument readerView = new CPDFReaderView(content);
}
}
kotlin
// 你的 MainActivity.kt 文件。
package com.compdfkit.pdfviewer
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.compdfkit.ui.reader.CPDFReaderView
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 从xml中获取CPDFReaderView
val readerView = findViewById<CPDFReaderView>(R.id.readerview)
// 创建CPDFReaderView的代码。
// CPDFDocument readerView = new CPDFReaderView(content);
}
}
- 打开文档。这是一个耗时的过程,因此需要在子线程中执行。文档成功打开后,会初始化渲染 PDF 的 UI:
Java
// 你的 MainActivity.java 文件。
... //导入。
public class MainActivity extends AppCompatActivity {
// 将PDF文件从资源文件夹复制到缓存文件夹。
private void copyPdfFromAssetsToCache(String fileName) {
try {
InputStream inputStream = getAssets().open(fileName);
File outputFile = new File(getCacheDir(), fileName);
FileOutputStream outputStream = new FileOutputStream(outputFile);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CPDFReaderView readerView = findViewById(R.id.readerview);
// 创建CPDFReaderView的代码。
// CPDFDocument readerView = new CPDFReaderView(content);
// 创建文档对象。
CPDFDocument document = new CPDFDocument(this);
new Thread(() -> {
String fileName = "Quick Start Guide.pdf";
copyPdfFromAssetsToCache(fileName);
File file = new File(getCacheDir(), fileName);
String filePath = file.getAbsolutePath();
// 打开文档。
CPDFDocument.PDFDocumentError error = document.open(filePath);
if (error == CPDFDocument.PDFDocumentError.PDFDocumentErrorPassword) {
// 该文档已加密,需要密码才能打开。
error = document.open(filePath, "password");
}
if (error == CPDFDocument.PDFDocumentError.PDFDocumentErrorSuccess) {
// 文档已成功打开,并且可以对数据进行解析和操作。
} else {
//无法打开PDF文件。具体错误可以参考API文件。
}
}).start();
}
}
kotlin
// 你的 MainActivity.java 文件。
... //导入。
class MainActivity : AppCompatActivity() {
// 将PDF文件从资源文件夹复制到缓存文件夹。
private fun copyPdfFromAssetsToCache(fileName: String) {
try {
val inputStream = assets.open(fileName)
val outputFile = File(cacheDir, fileName)
val outputStream = FileOutputStream(outputFile)
val buffer = ByteArray(1024)
var bytesRead: Int
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
outputStream.write(buffer, 0, bytesRead)
}
inputStream.close()
outputStream.flush()
outputStream.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val readerView = findViewById<CPDFReaderView>(R.id.readerview)
// 创建CPDFReaderView的代码。
// CPDFDocument readerView = new CPDFReaderView(content);
// 创建文档对象。
val document = CPDFDocument(this)
Thread {
val fileName = "Quick Start Guide.pdf"
copyPdfFromAssetsToCache(fileName)
val file = File(cacheDir, fileName)
val filePath = file.absolutePath
// 打开文档。
var error = document.open(filePath)
if (error == CPDFDocument.PDFDocumentError.PDFDocumentErrorPassword) {
// 该文档已加密,需要密码才能打开。
error = document.open(filePath, "password")
}
if (error == CPDFDocument.PDFDocumentError.PDFDocumentErrorSuccess) {
// 文档已成功打开,并且可以对数据进行解析和操作。
} else {
// 无法打开PDF文件。具体错误可以参考API文件。
}
}.start()
}
}
- 设置
CPDFReaderView
的基本属性:
Java
// 你的 MainActivity.java 文件。
... // 导入。
public class MainActivity extends AppCompatActivity {
// 创建一个处理程序以在主线程上运行代码。
private Handler mainThreadHandler = new Handler(Looper.getMainLooper());
...
if (error == CPDFDocument.PDFDocumentError.PDFDocumentErrorSuccess) {
// 文档已成功打开,并且可以对数据进行解析和操作。
mainThreadHandler.post(() -> {
// 设置UI的文档内容。
readerView.setPDFDocument(document);
});
} else {
// 无法打开PDF文件。具体错误可以参考API文件。
}
...
}
kotlin
// 你的 MainActivity.java 文件。
... // 导入。
public class MainActivity : AppCompatActivity() {
// 创建一个处理程序以在主线程上运行代码。
private var mainThreadHandler = Handler(Looper.getMainLooper());
...
if (error == CPDFDocument.PDFDocumentError.PDFDocumentErrorSuccess) {
// 文档已成功打开,并且可以对数据进行解析和操作。
mainThreadHandler.post {
// 设置UI的文档内容。
readerView.setPDFDocument(document);
}
} else {
// 无法打开PDF文件。具体错误可以参考API文件。
}
...
}
- 在这个阶段,您的代码会像下面展示的这样:
Java
// 你的 MainActivity.java 文件。
... // 导入。
public class MainActivity extends AppCompatActivity {
// 创建一个处理程序,在主线程上运行代码。
private Handler mainThreadHandler = new Handler(Looper.getMainLooper());
// 将PDF文件从资源文件夹复制到缓存文件夹。
private void copyPdfFromAssetsToCache(String fileName) {
try {
InputStream inputStream = getAssets().open(fileName);
File outputFile = new File(getCacheDir(), fileName);
FileOutputStream outputStream = new FileOutputStream(outputFile);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CPDFReaderView readerView = findViewById(R.id.readerview);
// 创建文档对象。
CPDFDocument document = new CPDFDocument(this);
new Thread(() -> {
String fileName = "Quick Start Guide.pdf";
copyPdfFromAssetsToCache(fileName);
File file = new File(getCacheDir(), fileName);
String filePath = file.getAbsolutePath();
// 打开文档。
CPDFDocument.PDFDocumentError error = document.open(filePath);
if (error == CPDFDocument.PDFDocumentError.PDFDocumentErrorPassword) {
// 该文档已加密,需要密码才能打开。
error = document.open(filePath, "password");
}
if (error == CPDFDocument.PDFDocumentError.PDFDocumentErrorSuccess) {
// 文档已成功打开,并且可以对数据进行解析和操作。
mainThreadHandler.post(() -> {
// 将文档设置为阅读器视图。
readerView.setPDFDocument(document);
});
} else {
// 无法打开PDF文件。具体错误可以参考API文件。
}
}).start();
}
}
kotlin
// 你的 MainActivity.java 文件。
... // 导入。
class MainActivity : AppCompatActivity() {
// 创建一个处理程序,在主线程上运行代码。
private val mainThreadHandler = Handler(Looper.getMainLooper())
// 将PDF文件从资源文件夹复制到缓存文件夹。
private fun copyPdfFromAssetsToCache(fileName: String) {
try {
val inputStream = assets.open(fileName)
val outputFile = File(cacheDir, fileName)
val outputStream = FileOutputStream(outputFile)
val buffer = ByteArray(1024)
var bytesRead: Int
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
outputStream.write(buffer, 0, bytesRead)
}
inputStream.close()
outputStream.flush()
outputStream.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val readerView = findViewById<CPDFReaderView>(R.id.readerview)
// 创建文档对象。
val document = CPDFDocument(this)
Thread {
val fileName = "Quick Start Guide.pdf"
copyPdfFromAssetsToCache(fileName)
val file = File(cacheDir, fileName)
val filePath = file.absolutePath
// 打开文档。
var error = document.open(filePath)
if (error == PDFDocumentError.PDFDocumentErrorPassword) {
// 该文档已加密,需要密码才能打开。
error = document.open(filePath, "password")
}
if (error == PDFDocumentError.PDFDocumentErrorSuccess) {
// 文档已成功打开,并且可以对数据进行解析和操作。
mainThreadHandler.post {
// 将文档设置为阅读器视图。
readerView.pdfDocument = document
}
} else {
// 无法打开PDF文件。具体错误可以参考API文件。
}
}.start()
}
}
xml
<!-- 你的 activity_main.xml 文件 -->
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.compdfkit.ui.reader.CPDFReaderView
android:id="@+id/readerview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
- 运行应用程序。
现在,借助ComPDFKit的帮助,您获得了一个简单的应用程序来显示PDF文件。
问题排除
无法打开 PDF 文件
我们向您提供的许可证是与您的应用程序 ID 绑定的,因此请确保所获取的许可证与您的应用程序 ID 匹配。
其它问题
如果您在集成 ComPDFKit PDF SDK for Android 时遇到其他问题,请随时联系 ComPDFKit 团队。