Open a local PDF file on Android

Nutrient Android SDK allows you to open PDF and image (PNG or JPEG) files from your device’s local storage. This guide covers how to open a PDF document from local storage.

Never hardcode absolute paths

Directories where your app stores files aren’t guaranteed to be stable between different devices or even between app restarts, and paths to your app’s files may change over time if the app is moved to an adopted storage device. We recommend using methods from Context(opens in a new tab) to access different special file system directories. More specifically:

  • Use Context#getFilesDir(opens in a new tab) to get the path to the file system directory where your internal files are stored. Use this path instead of hardcoding the device-dependent path /data/data/<application_package/files.
  • Use Context#getExternalFilesDir(null)(opens in a new tab) to get the path to the primary shared/external storage device where your application can place the persistent files it owns. Use this path instead of hardcoding the device-dependent path /storage/emulated/0/.

If you need to persist paths to files — for example, in a database or in settings — only relative paths should be persisted.

Accessing the external storage

Android devices support shared “external storage” that can be used for storing files. These can be removable (for example, SD cards or USB hard drives) or non-removable (internal). External storage can become unavailable for multiple reasons and does not enforce any security restrictions for accessing your files. Make sure your application handles these situations correctly.

Storage Access Framework

Use the Storage Access Framework(opens in a new tab) if you’re running on Android 4.4+ and you want to allow users to browse and open documents from device storage.

You can find a complete example of how to access files through the Storage Access Framework inside ExternalDocumentExample of the Catalog app.

Permissions to external storage

To read or write files on the external storage, your app must acquire READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE permissions. To acquire these permissions, add them to your manifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="your.app.package">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...
</manifest>

If your app targets Android 6.0+, these permissions aren’t granted to your app automatically after installation. You need to explicitly ask for them(opens in a new tab) in your activity:

override fun onCreate(savedInstanceState: Bundle?) {
...
// Request permission here.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_ASK_FOR_PERMISSION)
}
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
if (requestCode == REQUEST_ASK_FOR_PERMISSION) {
if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission has been granted.
} else {
if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
// User denied permission.
} else {
// User asked to "Never ask again" when denying permission.
}
}
}
}

Since Android 4.4+, these permissions have no longer been required when accessing external files of your app (stored in the Context#getExternalFilesDir(null)(opens in a new tab) directory).

Scoped directory access

Note that READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions allow access to all public directories on the external storage, which could make your users worried or suspicious.

Use Scoped Directory Access(opens in a new tab) if you’re running on Android 7.0+ and you only need to access a specific directory on the external storage. This provides a permissions UI that clearly states which directory your application is requesting access to.

Opening a document from local storage

Once you have the appropriate permissions, you can open a PDF document from local storage using PdfActivityIntentBuilder.fromUri()(opens in a new tab). This section shows how to open documents from different storage locations.

Opening from internal storage

To open a document from your app’s internal storage directory:

// Get a file from internal storage.
val filesDir = context.filesDir
val documentFile = File(filesDir, "document.pdf")
val documentUri = Uri.fromFile(documentFile)
// Open the document.
val intent = PdfActivityIntentBuilder.fromUri(context, documentUri)
.build()
context.startActivity(intent)

Opening from external storage

To open a document from external storage (requires storage permissions):

// Get a file from external storage.
val externalFilesDir = context.getExternalFilesDir(null)
val documentFile = File(externalFilesDir, "document.pdf")
val documentUri = Uri.fromFile(documentFile)
// Open the document.
val intent = PdfActivityIntentBuilder.fromUri(context, documentUri)
.build()
context.startActivity(intent)

Opening with Storage Access Framework

To allow users to browse and select a document using the system file picker:

// Request code for the file picker.
private const val REQUEST_OPEN_DOCUMENT = 100
// Launch the file picker.
fun openDocumentPicker() {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "application/pdf"
}
startActivityForResult(intent, REQUEST_OPEN_DOCUMENT)
}
// Handle the selected document.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_OPEN_DOCUMENT && resultCode == Activity.RESULT_OK) {
data?.data?.let { uri ->
// Open the selected document.
val intent = PdfActivityIntentBuilder.fromUri(this, uri)
.build()
startActivity(intent)
}
}
}

When using Intent.ACTION_OPEN_DOCUMENT, the system grants your app temporary read access to the selected file through the returned URI. No storage permissions are required for this approach on Android 4.4+.