Blog Post

Build an Android PDF viewer using Nutrient: A step-by-step guide

Teja Tatimatla
Jonathan D. Rhyne
Illustration: Build an Android PDF viewer using Nutrient: A step-by-step guide
Information

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

  1. Launch Android Studio and select New Project. Navigate to File > New > New Project… to start creating a new project for your Android app.

Screenshot of Android Studio’s ‘New Project’ setup wizard for creating an Android PDF viewer using Nutrient

  1. Select Empty Activity as the template for your project.

Image showing a menu in Android Studio that lets user choose an activity

  1. 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.

Image showing a wizard for project setup

  1. Click Finish to create your project in the specified directory.

Step 2 — Add Nutrient’s PDF viewer library to your Android project

  1. 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/'
        }
    }
}
  1. Add the Nutrient dependency to yourapp/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.

  1. Place a PDF document in the assets directory of your Android project — for example, src/main/assets/my-document.pdf.

  2. 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>
  1. Add PdfActivity to your app’s AndroidManifest.xml:

<application>
    <activity
        android:name="com.pspdfkit.ui.PdfActivity"
        android:windowSoftInputMode="adjustNothing" />
</application>
  1. You can now start PdfActivity with the document from your assets 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);
  1. PdfActivity will now present the document from your assets directory.

GIF showing the application running on the Android emulator

Information

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.

  1. 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);
Information

Learn more about openFileOutput(String, int) here.

  1. 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);
                }
            }
        }
    }
}

GIF showing the application running on the Android emulator

Information

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.

Author
Jonathan D. Rhyne Co-Founder and CEO

Jonathan joined Nutrient in 2014. As CEO, Jonathan defines the company’s vision and strategic goals, bolsters the team culture, and steers product direction. When he’s not working, he enjoys being a dad, photography, and soccer.

Explore related topics

Related products
Share post
Free trial Ready to get started?
Free trial