Skip to content

Build a Full-Featured PDF Reader (UI Extensions)

This guide explains how to quickly build a full-featured PDF reader with the UI Extensions component, including the built-in toolbar and common feature module UI.

Note To display PDFs only (no built-in UI), see Build a Basic PDF Reader (PDFViewCtrl).

Prerequisites

  1. Complete Integrate Foxit Android SDK (project setup, SDK integration, and license initialization).
  2. Ensure UI Extensions dependencies are enabled (see Enable UI Extensions).

Step 1: Integrate UI Extensions for a Full Reader

The core approach:

  1. Create PDFViewCtrl as the rendering and interaction container.
  2. Create UIExtensionsManager and bind it to PDFViewCtrl.
  3. Open documents with UIExtensionsManager.openDocument() and use its ContentView as the UI content.

1.1 Theme and Full-Screen (Required)

UI Extensions takes over the layout. To avoid system ActionBar or title bar affecting the built-in UI:

  • Use a NoActionBar theme
    • For example, set Theme.MaterialComponents.Light.NoActionBar in YourProjectName/app/src/main/res/values/themes.xml
  • Set the Activity to full screen

Example (call after super.onCreate() and before UI initialization in Activity#onCreate()):

java
import android.view.Window;
import android.view.WindowManager;

// Turn off the title at the top of the screen.
this.requestWindowFeature(Window.FEATURE_NO_TITLE);

// Set the window to Fullscreen.
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

1.2 Initialize UIExtensionsManager

java
import com.foxit.uiextensions.UIExtensionsManager;

private UIExtensionsManager uiExtensionsManager = null;

uiExtensionsManager = new UIExtensionsManager(this.getApplicationContext(), pdfViewCtrl);
uiExtensionsManager.setAttachedActivity(this);
uiExtensionsManager.onCreate(this, pdfViewCtrl, savedInstanceState);
pdfViewCtrl.setUIExtensionsManager(uiExtensionsManager);

1.3 Open a Document

Use UIExtensionsManager.openDocument() to open a document (not PDFViewCtrl.openDoc()):

java
import android.os.Environment;

String path = Environment.getExternalStorageDirectory().getPath() + "/FoxitSDK/Sample.pdf";
uiExtensionsManager.openDocument(path, null);
setContentView(uiExtensionsManager.getContentView());

1.4 Forward Lifecycle Events (Important)

Forward lifecycle and event callbacks in the Activity so some features work correctly:

java
@Override
public void onStart() {
    if (uiExtensionsManager != null) {
        uiExtensionsManager.onStart(this);
    }
    super.onStart();
}

@Override
public void onStop() {
    if (uiExtensionsManager != null) {
        uiExtensionsManager.onStop(this);
    }
    super.onStop();
}

@Override
public void onPause() {
    if (uiExtensionsManager != null) {
        uiExtensionsManager.onPause(this);
    }
    super.onPause();
}

@Override
public void onResume() {
    if (uiExtensionsManager != null) {
        uiExtensionsManager.onResume(this);
    }
    super.onResume();
}

@Override
protected void onDestroy() {
    if (uiExtensionsManager != null) {
        uiExtensionsManager.onDestroy(this);
    }
    super.onDestroy();
}

Update AndroidManifest.xml so built-in features work correctly:

  1. Permissions (enable as needed)
  • Camera: Scanning and other camera use cases.
  • Record audio: Audio/video features; some capabilities may be unavailable without it.

Example:

xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
  1. Activity configChanges (Important)

To avoid Activity recreation on rotation and other configuration changes, add to MainActivity:

xml
<activity
    android:name=".MainActivity"
    android:configChanges="keyboardHidden|orientation|locale|layoutDirection|screenSize" />

Reference: MainActivity.java

Complete MainActivity.java example with UI Extensions initialization, runtime permissions, document open, and lifecycle forwarding:

[MainActivity.java]
java
package com.foxit.pdfreader;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.view.KeyEvent;
import android.view.Window;
import android.view.WindowManager;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.foxit.sdk.PDFViewCtrl;
import com.foxit.sdk.common.Constants;
import com.foxit.sdk.common.Library;
import com.foxit.uiextensions.UIExtensionsManager;

public class MainActivity extends AppCompatActivity {

    private PDFViewCtrl pdfViewCtrl = null;
    private UIExtensionsManager uiExtensionsManager = null;
    private static final int REQUEST_EXTERNAL_STORAGE = 1;
    private static final int REQUEST_ALL_FILES_ACCESS_PERMISSION = 222;
    private static final String[] PERMISSIONS_STORAGE = {
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };

    // The value of "sn" can be found in the "rdk_sn.txt".
    // The value of "key" can be found in the "rdk_key.txt".
    private static String sn = " ";
    private static String key = " ";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // initialize the library.
        int errorCode = Library.initialize(sn, key);
        if (errorCode != Constants.e_ErrSuccess)
            return;

        // Turn off the title at the top of the screen.
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        // Set the window to Fullscreen.
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        // Instantiate a PDFViewCtrl object.
        pdfViewCtrl = new PDFViewCtrl(this);

        // Set the associated activity for RMS UI operations.
        pdfViewCtrl.setAttachedActivity(this);

        // Initialize a UIExtensionManager object and set it to PDFViewCtrl.
        uiExtensionsManager = new UIExtensionsManager(this.getApplicationContext(), pdfViewCtrl);
        uiExtensionsManager.setAttachedActivity(this);
        uiExtensionsManager.onCreate(this, pdfViewCtrl, savedInstanceState);
        pdfViewCtrl.setUIExtensionsManager(uiExtensionsManager);
        setContentView(uiExtensionsManager.getContentView());

        // Require the authorization of runtime permissions.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            if (!Environment.isExternalStorageManager()) {
                Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
                intent.setData(Uri.parse("package:" + getApplicationContext().getPackageName()));
                startActivityForResult(intent, REQUEST_ALL_FILES_ACCESS_PERMISSION);
                return;
            }
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            int permission = ContextCompat.checkSelfPermission(this.getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE);
            if (permission != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
                return;
            }
        }

        // Open and Render a PDF document.
        String path = Environment.getExternalStorageDirectory().getPath() + "/FoxitSDK/Sample.pdf";
        uiExtensionsManager.openDocument(path, null);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == REQUEST_EXTERNAL_STORAGE && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // Open and Render a PDF document.
            String path = Environment.getExternalStorageDirectory().getPath() + "/FoxitSDK/Sample.pdf";
            uiExtensionsManager.openDocument(path, null);
        } else {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_ALL_FILES_ACCESS_PERMISSION) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                if (Environment.isExternalStorageManager()) {
                    String path = Environment.getExternalStorageDirectory().getPath() + "/FoxitSDK/Sample.pdf";
                    uiExtensionsManager.openDocument(path, null);
                }
            }
        } else {
            if (pdfViewCtrl != null) {
                pdfViewCtrl.handleActivityResult(requestCode, resultCode, data);
            }
        }
    }

    @Override
    public void onStart() {
        if (uiExtensionsManager != null) {
            uiExtensionsManager.onStart(this);
        }
        super.onStart();
    }

    @Override
    public void onStop() {
        if (uiExtensionsManager != null) {
            uiExtensionsManager.onStop(this);
        }
        super.onStop();
    }

    @Override
    public void onPause() {
        if (uiExtensionsManager != null) {
            uiExtensionsManager.onPause(this);
        }
        super.onPause();
    }

    @Override
    public void onResume() {
        if (uiExtensionsManager != null) {
            uiExtensionsManager.onResume(this);
        }
        super.onResume();
    }

    @Override
    protected void onDestroy() {
        if (uiExtensionsManager != null) {
            uiExtensionsManager.onDestroy(this);
        }
        super.onDestroy();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (uiExtensionsManager != null) {
            uiExtensionsManager.onConfigurationChanged(this, newConfig);
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (uiExtensionsManager != null && uiExtensionsManager.onKeyDown(this, keyCode, event))
            return true;
        return super.onKeyDown(keyCode, event);
    }
}

Step 2: Run and Verify

  1. Place test files (for example Sample.pdf) in the FoxitSDK directory on the device or emulator (example path: /sdcard/FoxitSDK/Sample.pdf).
  2. After launching the app, grant file access when prompted.

Android 10/11+ storage (related to sample code)

  • Android 10 (API 29): Legacy external storage may require android:requestLegacyExternalStorage="true" in AndroidManifest.xml.
  • Android 11+ (API 30+): Shared storage paths may require guiding users to grant “All files access” (as in the sample project).