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
- Complete Integrate Foxit Android SDK (project setup, SDK integration, and license initialization).
- Ensure UI Extensions dependencies are enabled (see Enable UI Extensions).
Step 1: Integrate UI Extensions for a Full Reader
The core approach:
- Create
PDFViewCtrlas the rendering and interaction container. - Create
UIExtensionsManagerand bind it toPDFViewCtrl. - Open documents with
UIExtensionsManager.openDocument()and use itsContentViewas 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.NoActionBarinYourProjectName/app/src/main/res/values/themes.xml
- For example, set
- 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();
}1.5 Update AndroidManifest.xml (Recommended)
Update AndroidManifest.xml so built-in features work correctly:
- 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" />- 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
- Place test files (for example
Sample.pdf) in theFoxitSDKdirectory on the device or emulator (example path:/sdcard/FoxitSDK/Sample.pdf). - 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"inAndroidManifest.xml.- Android 11+ (API 30+): Shared storage paths may require guiding users to grant “All files access” (as in the sample project).