Build an Android PDF viewer using Nutrient: A step-by-step guide
This article was first published in August 2022 and was updated in August 2024.
Ready to transform your Android app with a powerful PDF viewer? In this post, we’ll walk you through using Nutrient’s robust library to seamlessly integrate a PDF viewer into your Android application. With Android’s expansive reach of more than 3 billion active devices, ensuring your app can efficiently handle PDF documents is essential.
To kick off, we’ll start by setting up a new project in Android Studio to build your Android PDF viewer using Nutrient. We’ll walk you through opening a PDF document from the android-assets
folder and later, how to access files from your device’s local storage.
What is an Android PDF viewer?
An Android PDF viewer allows you to render and display PDF documents inside your app without your users needing to download them or use an external application like a PDF reader. You can build one from scratch, or you can save dev time by deploying a commercial Android PDF viewer library, like the one Nutrient offers.
Nutrient Android PDF viewer library
Nutrient’s Android PDF viewer library uses a high-fidelity, reliable, PDFium-based rendering engine that’s fast, precise, and feature rich. It enables you to quickly and painlessly embed a fully configurable PDF viewer in your Android application.
Nutrient SDKs are deployed in some of the world’s most popular applications, including Autodesk, Disney, Dropbox, IBM, and Lufthansa.
Key capabilities include:
-
A customizable UI — Hide or add buttons, and match your look and feel.
-
30+ features — Easily add features like PDF editing, digital signatures, form filling, real-time document collaboration, and more.
-
Dedicated support — Deploy faster by working 1-on-1 with our developers.
-
Page modes and transition — Use single- or double-page modes and multiple scroll modes.
-
Outline — Supports all custom variants and PDF action types.
-
Bookmarks — Users can add, remove, and sort bookmarks.
-
Reader view — Reflow text to present it in a single-column view.
-
PNG and JPG — Open images in the viewer (in addition to PDFs).
You can view our demo to see what Nutrient is capable of and determine how you can use it for your project.
Requirements
To get started, you’ll need:
-
Android Studio — The official integrated development environment for Android
How to integrate Nutrient for Android PDF viewing
The next few sections will walk you through the getting started process.
Step 1 — Create a new Android project in Android Studio
-
Launch Android Studio and select New Project. Navigate to File > New > New Project… to start creating a new project for your Android app.
-
Select Empty Activity as the template for your project.
-
Configure your project by setting the App Name (e.g. Nutrient Demo), choosing a Save Location, and selecting a Build Configuration Language. Ensure that the Minimum SDK is set to API 21.
-
Click Finish to create your project in the specified directory.
Step 2 — Add Nutrient’s PDF viewer library to your Android project
-
Open the
settings.gradle
file located at the root of your project and add the Nutrient Maven repository:
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() maven { url = uri("https://my.nutrient.io/maven") } } }
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven {
'https://my.nutrient.io/maven/'
}
}
}
-
Add the Nutrient dependency to your
app/build.gradle
file:
dependencies {
implementation("com.pspdfkit:pspdfkit:2024.7.0")
}
dependencies {
implementation("com.pspdfkit:pspdfkit:2024.7.0")
}
Step 3 — Display a PDF file using Nutrient in your Android app
To verify that Nutrient is successfully integrated into your application, open a PDF file with the ready-to-use PdfActivity
.
-
Place a PDF document in the
assets
directory of your Android project — for example,src/main/assets/my-document.pdf
. -
Optional— If you have a trial key or license key, add it to your
AndroidManifest.xml
. Otherwise, skip this step:
<application> <meta-data android:name="pspdfkit_license_key" android:value="YOUR_LICENSE_KEY_GOES_HERE" /> ... </application>
-
Add
PdfActivity
to your app’sAndroidManifest.xml
:
<application> <activity android:name="com.pspdfkit.ui.PdfActivity" android:windowSoftInputMode="adjustNothing" /> </application>
-
You can now start
PdfActivity
with the document from yourassets
directory:
val uri = Uri.parse("file:///android_asset/my-document.pdf") val config = PdfActivityConfiguration.Builder(context).build() PdfActivity.showDocument(this, uri, config)
final Uri uri = Uri.parse("file:///android_asset/my-document.pdf"); final PdfActivityConfiguration config = new PdfActivityConfiguration.Builder(context).build(); PdfActivity.showDocument(this, uri, config);
-
PdfActivity
will now present the document from yourassets
directory.
This is a simple demonstration using the
android_assets
folder. This folder is a read-only directory that, during the build process, gets built into the.apk
file in most Android applications. For more information on its use, refer to the following section.
How to open a local PDF file on Android
This section will guide you through displaying a PDF file from the device’s local storage. Before starting, it’s essential to understand the types of local storage available on Android devices.
Understanding Android storage types
Android devices offer two primary types of storage locations:
-
Internal storage — Smaller and always available. Ideal for app-specific data.
-
External storage — Larger but may not always be available. Useful for files that need to be shared or stored long-term.
How to open a PDF from app-specific storage
Absolute paths must never be hardcoded. Directories where your app stores files aren’t guaranteed to be stable between different devices or even between app restarts. As such, we recommend using methods from Context
to access different special file system directories.
-
Opening a PDF from internal storage
Use the getFilesDir
method from Context
to get the path to the file system directory where your internal files are stored:
// This will fail if "my-document.pdf" isn't created in // advance using `openFileOutput(String, int)`. val uri = Uri.parse(getFilesDir() + "my-document.pdf") val config = PdfActivityConfiguration.Builder(context).build() PdfActivity.showDocument(this, uri, config)
// This will fail if "my-document.pdf" isn't created in // advance using `openFileOutput(String, int)`. final Uri uri = Uri.parse(getFilesDir() + "my-document.pdf"); final PdfActivityConfiguration config = new PdfActivityConfiguration.Builder(context).build(); PdfActivity.showDocument(this, uri, config);
Learn more about
openFileOutput(String, int)
here.
-
Opening a PDF from external storage
Use Context#getExternalFilesDir(null)
to access the directory that the system provides for your app on external storage:
// This will fail if external storage is not mounted correctly // or if "my-document.pdf" isn't present in the directory. // returned by getExternalFilesDir(null) val uri = Uri.parse(getExternalFilesDir(null) + "my-document.pdf") val config = PdfActivityConfiguration.Builder(context).build() PdfActivity.showDocument(this, uri, config)
// This will fail if external storage is not mounted correctly // or if "my-document.pdf" isn't present in the directory. // returned by getExternalFilesDir(null) final Uri uri = Uri.parse(getExternalFilesDir(null) + "my-document.pdf"); final PdfActivityConfiguration config = new PdfActivityConfiguration.Builder(context).build(); PdfActivity.showDocument(this, uri, config);
How to open a PDF from shared storage
As the name suggests, shared storage is shared between all the applications running on a device. Shared storage directories and their data aren’t affected by a particular app’s uninstall.
The recommended method for accessing shared storage is through the Storage Access Framework (SAF). According to the documentation, “the SAF makes it simple for users to browse and open documents, images, and other files across all of their preferred document storage providers. A standard, easy-to-use UI lets users browse files and access recents in a consistent way across apps and providers.”
To open a PDF using SAF, invoke the ACTION_OPEN_DOCUMENT
intent as follows:
package com.example.yourappid; // Replace with your actual app ID or package name. import android.app.Activity import android.content.Intent import android.net.Uri import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.enableEdgeToEdge import androidx.activity.result.ActivityResult import androidx.activity.result.contract.ActivityResultContracts import com.pspdfkit.configuration.activity.PdfActivityConfiguration import com.pspdfkit.ui.PdfActivity class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply{ addCategory(Intent.CATEGORY_OPENABLE) type = "application/pdf" } registerForActivityResult(ActivityResultContracts.StartActivityForResult()){ result -> onDone(result) }.launch(intent) } private fun onDone(result: ActivityResult){ if(result.resultCode == Activity.RESULT_OK) { val resultData = result.data resultData?.data?.also { uri -> val documentUri = Uri.parse(uri.toString()) val config = PdfActivityConfiguration.Builder(this).build() PdfActivity.showDocument(this, documentUri, config) } } } }
package com.example.yourappid; // Replace with your actual app ID or package name. import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import androidx.activity.ComponentActivity; import androidx.activity.result.ActivityResult; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import com.pspdfkit.configuration.activity.PdfActivityConfiguration; import com.pspdfkit.ui.PdfActivity; public class MainActivity extends AppCompatActivity { private ActivityResultLauncher<Intent> launcher; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); launcher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), this::onDone); Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("application/pdf"); launcher.launch(intent); } private void onDone(ActivityResult result) { if (result.getResultCode() == Activity.RESULT_OK) { Intent resultData = result.getData(); if (resultData != null) { Uri uri = resultData.getData(); if (uri != null) { Uri documentUri = Uri.parse(uri.toString()); PdfActivityConfiguration config = new PdfActivityConfiguration.Builder(this).build(); PdfActivity.showDocument(this, documentUri, config); } } } } }
Since the user is browsing and selecting the document through a file picker, they’re completely aware of what files your app has access to. Hence, your application doesn’t need to ask for runtime permissions.
Advanced PDF handling with Nutrient
Nutrient’s Android library isn’t just limited to opening and manipulating documents from local storage. Nutrient can also open documents:
-
From remote storage
-
From Nutrient Document Engine
-
From a custom data provider
-
That are password protected
To learn more about opening PDF documents in Android apps, refer to our related blog post.
Conclusion
This post demonstrated how to integrate Nutrient’s Android PDF viewer library into an Android application and present a PDF document from local directories. If you hit any snags, don’t hesitate to reach out to our Support team for help.
At Nutrient, we offer a commercial, feature-rich, and completely customizable Android PDF library that’s easy to integrate and comes with well-documented APIs to handle advanced use cases. Try it for free, or visit our demo to see it in action.
FAQ
Here are a few frequently asked questions about PDF viewers on Android.
What is an intent in Android?
Intents are messages you pass to the Android OS. They describe actions you want the system to perform on your behalf. After describing an intent, you pass it to the OS and act on the result. Usually, the result is passed to a callback function.
What’s a request code used for in Android?
In Android, request codes help identify intents and their corresponding results. The best place to declare a request code is in a separate file that holds all your constants.
More about PdfActivity
PdfActivity
is a public class that extends AppCompactActivity
and implements PdfUi
, PdfActivityListener
, and PdfActivityComponentsApi
. It’s an activity with fully integrated views and behavior, and it can be invoked by the simple helper methods showDocument
and showImage
.
More about the showDocument helper method
The showDocument(Context context, Uri documentUri, PdfActivityConfiguration configuration)
helper method opens a new PdfActivity
displaying a passed document. If the document is password protected, Nutrient will prompt the user to enter the password. If you want to supply the password programmatically, use the showDocument(Context context, Uri documentUri, String password PdfActivityConfiguration configuration)
method overload, which has been documented here.