If you have not done so already, download the SDK for Android, available by request on the PDFTron website. There are three package samples in the SDK (please follow the instructions on the readme document included in the packages for running each application):

  • PDFDrawDemo
  • MiscellaneousSamples
  • PDFViewCtrlProjects

PDFDrawDemo is a simple example that shows how PDFDraw can be used to make a simple PDF viewer. Tap top (bottom) half of the viewer to turn pages backward (forward). To see how to use all PDFNet APIs, check out MiscellaneousSamples application.

The PDFViewCtrlProjects package itself consists of two applications:

  • PDFViewCtrlDemo
  • CompleteReader

The PDFViewCtrlDemo sample application showcases a basic PDF viewer and editor, where it is possible to perform annotations (lines, arrows, free text, sticky notes, etc.), fill forms, zoom in/out, browse bookmarks, highlight/underline text, navigate the document with different presentation modes and much more. Feel free to browse the project and see how the control is used in the layout xml file, or how you can initialize it programmatically.

pdfviewctrldemo

PDFViewCtrlDemo in action

CompleteReader is an advanced version of PDFViewCtrlDemo, including a file browser with five different file views, by folder, by listing all files, by SD card (Lollipop+), a list of favorite documents and a list of the last accessed documents (including thumbnails), and a viewer activity that uses the controls available in the Tools library, such as the bookmark list, annotation list, annotation toolbar, thumbnail slider, and thumbnails viewer. Besides this, it also includes reflow, text search, sharing, annotations, page editing, page cropping, custom color mode, support to right-to-left languages, undo/redo and much more.

completereader

CompleteReader in action

OK, the sample apps are fantastic! But how do I use the SDK with my app?

Before proceeding, it’s worth knowing what makes up the core components of PDFNet for Android. Typically you only need to include 4 items in your project (we highly recommend not change the names):

Capture2

PDFNet.jar

This jar file contains all the JAVA APIs available to be used by your application. You can find the documentation online or in the “docs” folder of the SDK package.

libPDFNetC-v7a.so

This file contains the core functionality of PDFNet and it is the heart of the SDK. The file is built separately for each architecture, and currently it is available for ARM, ARM-v7, ARM64-v8a, x86 and x86-64. (The example above uses only the ARM-v7 version of the library to keep the final APK size to a minimum.)

pdfnet.res

This file contains standard PDF resources that must be included to ensure all PDF documents will display correctly. Please check “What is the pdfnet.res file?” for more information on the resource file.

Tools Library

The preceding files are sufficient for viewing PDF documents. The Tools library adds support for text selection, interactive annotation creation and editing, form filling, link following, and etc. Please check “What is the Tools library?” for more information.

Creating a basic PDF viewer

Now that you understand the components of the SDK, let’s build a bare bones PDF viewing app. As secondary steps we will also add support for annotation creation and editing, and opening encrypted documents.

In this example we will use Android Studio 2.3, however if you are already comfortable with another IDE then feel free to use it as well. A completed version of the project can be found on our GitHub repository.

Displaying a PDF

1. Create a new Android project and add the required PDFNet files

Start a New Project in Android Studio and fill the Application name as pttest and Company domain as tutorial.android.pdftron.com (so the package name will be com.pdftron.android.tutorial.pttest.) In the next dialog set Minimum SDK as API 16 and finally select Add No Activity and press Finish button.

Next we need to add the required PDFNet files to the project (it is assumed that you already downloaded the SDK package, which contains the required files. If not, please check the First Steps section at the beginning of this document):

  • Copy PDFNet.jar from the downloaded package’s “lib” folder to the “libs” folder of your project;
  • Copy libPDFNetC-v7a.so from the downloaded package’s “lib\standard\armeabi-v7a” to the project’s “jniLibs\armeabi-v7a” folder (note that you might need to create this folder on your project);
  • Copy pdfnet.res from the package’s “resource” folder to the project’s “res\raw” folder;
  • Add a PDF document named “sample.pdf” to the “res\raw” folder.

Your project should look like the screenshot below:

Capture

Adding PDFNet files to the project

For this project we will add only the ARM-v7 library (to keep the final APK file to a minimum size), but you could also add the ARM and x86 variants to their respective folders.

2. Update build.gradle

For this project we only need to add ARM-v7 architecture to build.gradle. Make sure that you add this to the module gradle (the build.gradle file in the “pttest\app\” folder):

1
2
3
4
5
6
7
productFlavors {
    armv7a {
        ndk {
            abiFilters "armeabi-v7a"
        }
    }
}

So the entire build.gradle file in “pttest\app” folder will be like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
apply plugin: 'com.android.application'
 
android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "com.pdftron.android.tutorial.pttest"
        minSdkVersion 16
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    productFlavors {
        armv7a {
            ndk {
                abiFilters "armeabi-v7a"
            }
        }
    }
}
 
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.2.0'
    testCompile 'junit:junit:4.12'
}

3. Add a layout for our activity

Now let’s add a layout called main.xml into the “res\layout” folder which will contain the PDFViewCtrl element:

1
2
3
4
5
6
7
8
9
10
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <com.pdftron.pdf.PDFViewCtrl
        android:id="@+id/pdfviewctrl"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars = "vertical|horizontal" />
</LinearLayout>

4. Add code to show PDF

Now create a new class that extends android.app.Activity called PTTestActivity, using the package com.pdftron.android.tutorial.pttest:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package com.pdftron.android.tutorial.pttest;
 
import android.app.Activity;
import android.content.res.Resources;
import android.os.Bundle;
 
import com.pdftron.common.PDFNetException;
import com.pdftron.pdf.PDFDoc;
import com.pdftron.pdf.PDFNet;
import com.pdftron.pdf.PDFViewCtrl;
import com.pdftron.pdf.tools.ToolManager;
 
import java.io.IOException;
import java.io.InputStream;
 
public class PTTestActivity extends Activity {
 
    private PDFViewCtrl mPDFViewCtrl;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        // Initialize the library
        try {
            PDFNet.initialize(this, R.raw.pdfnet);
        } catch (PDFNetException e) {
            // Do something...
            e.printStackTrace();
        }
 
        // Inflate the view and get a reference to PDFViewCtrl
        setContentView(R.layout.main);
        mPDFViewCtrl = (PDFViewCtrl) findViewById(R.id.pdfviewctrl);
 
        // Load a document
        Resources res = getResources();
        InputStream is = res.openRawResource(R.raw.sample);
        try {
            PDFDoc doc = new PDFDoc(is);
            mPDFViewCtrl.setDoc(doc);
            // Or you can use the full path instead
            //doc = new PDFDoc("/mnt/sdcard/sample.pdf");
        } catch (PDFNetException | IOException e) {
            e.printStackTrace();
        }
    }
 
    @Override
    protected void onPause() {
        // This method simply stops the current ongoing rendering thread, text
        // search thread, and tool
        super.onPause();
        if (mPDFViewCtrl != null) {
            mPDFViewCtrl.pause();
        }
    }
 
    @Override
    protected void onResume() {
        // This method simply starts the rendering thread to ensure the PDF
        // content is available for viewing.
        super.onResume();
        if (mPDFViewCtrl != null) {
            mPDFViewCtrl.resume();
        }
    }
 
    @Override
    protected void onDestroy() {
        // Destroy PDFViewCtrl and clean up memory and used resources.
        super.onDestroy();
        if (mPDFViewCtrl != null) {
            mPDFViewCtrl.destroy();
        }
    }
 
    @Override
    public void onLowMemory() {
        // Call this method to lower PDFViewCtrl's memory consumption.
        super.onLowMemory();
        if (mPDFViewCtrl != null) {
            mPDFViewCtrl.purgeMemory();
        }
    }
}

5. Configure the manifest file

The last step is to configure the manifest file to start our PTTestActivity. Change the AndroidManifest.xml to the content below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    package="com.pdftron.android.tutorial.pttest">
    <application android:allowBackup="true"
        android:label="@string/app_name"
        android:icon="@mipmap/ic_launcher"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name="PTTestActivity"
            android:windowSoftInputMode="adjustPan" >
            <intent-filter>
                <action
                    android:name="android.intent.action.MAIN" />
                <category
                    android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

6. Run the app

Now if you build and run the sample project on a device, you will be able to scroll and zoom pages (pinch or double tap to zoom). You are also able to turn pages by fling to left or right.

fling

PTTest in action

Adding support for Annotations, Text Selection and Form Filling

PDFNet comes with built-in support for text selection, interactive annotation creation and editing, form filling, link following and etc. These features are implemented using PDFNet’s Android API, and are shipped in a separate library, PDFViewCtrlTools (see “What is the Tools library?” for more information).

To add support for annotations, text selection, etc, you need to reference the Tools library in your project. The SDK package is included with the PDFViewCtrlTools source package (existing in the “lib\src\PDFViewCtrlTools\” folder) and PDFViewCtrlTools library (which is “lib\PDFViewCtrlTools.aar”). You can either add the source package or include the library into your workspace.

A- Add PDFViewCtrlTools source package

If you decide on adding the source packagae, you first need to delete “app\libs\PDFNet.jar” (PDFViewCtrlTools package has its own PDFNet.jar file). Now, copy all folders including PDFViewCtrlTools, PageCropper and FloatingActionButton in the “lib\src\” folder from SDK package to the root folder of pttest. Our project should look like the screenshot below:

Capture3

Now, we need to include the external projects in “settings.gradle” file:

1
2
3
4
include ':PDFViewCtrlTools'
include ':FloatingActionButton'
include ':PageCropper'
include ':app'

and include dependency to PDFViewCtrlTools in build.gradle:

1
2
3
dependencies {
    compile project(':PDFViewCtrlTools')
}

At this point you should be able to build your project again. Make sure it compiles without errors (note that sometimes you will need to trigger the build action more than once so Android will generate the intermediate files appropriately).

B- Include PDFViewCtrlTools library

Instead of adding source package, you are able to include PDFViewCtrlTools AAR library that is provided in the SDK package (in the “\lib\” folder). First delete “app\libs\PDFNet.jar” (PDFViewCtrlTools library has its own PDFNet.jar file). Then, copy all aar files (including PDFViewCtrlTools.aar, FloatingActionButton.aar and PageCropper.aar) from the SDK package in the “\lib\” folder to the “app\libs\” folder. You also need to add the followings to the “\app\build.gradle” file:

1
2
3
4
5
6
7
8
9
10
11
12
13
allprojects {
    repositories {
        flatDir {
            dirs 'libs'
        }
    }
}
 
dependencies {
    compile(name:'PDFViewCtrlTools', ext:'aar')
    compile(name:'FloatingActionButton', ext:'aar')
    compile(name:'PageCropper', ext:'aar')
}

At this point you should be able to build your project again.

Now that PDFViewCtrlTools is added to the project, you can use Tool Manager in your code. In this order, add the call to set the tool manager just after the call to findViewById(R.id.pdfviewctrl):

1
2
3
4
5
// Inflate the view and get a reference to PDFViewCtrl
setContentView(R.layout.main);
mPDFViewCtrl = (PDFViewCtrl) findViewById(R.id.pdfviewctrl);
 
mPDFViewCtrl.setToolManager(new ToolManager(mPDFViewCtrl));

You are now ready to build and run the project again. Now, when you run the project, you can select text, follow links and create and edit annotations. To create a new annotation, long press on an area of the document without text to trigger a popup with annotation types to create. This behavior is shown in the below screenshot:

sample

Opening encrypted documents

PDFNet supports opening encrypted PDF documents. If you try to open an encrypted document, PDFViewCtrl will pop up a dialog to request the password from the user. If you would like to implement your own interface or system for acquiring the password, you can first initialize the PDFDoc’s security handler before passing it to the PDFViewCtrl. An example of this is shown following code snippet after creating the PDFDoc in order to display an encrypted PDF:

1
2
3
4
if (!doc.initStdSecurityHandler("password")) {
    // Wrong password...
    return;
}

What is the Tools library?

PDFNet comes with built-in support for text selection, interactive annotation creation and editing, form filling and link following. These features have been implemented using two interfaces from PDFViewCtrl (PDFViewCtrl.ToolManager and PDFViewCtrl.Tool), and are shipped in a separate Android library project, PDFViewCtrlTools. This library also contains an implementation of a floating quick menu to access all these functionalities, a basic slider to navigate through pages and a text search toolbar.

With the source code of the library developers have complete flexibility and control to customize how users interact with the PDF. More information on how the tools work and how to customize them for your app can be found in our documentation:

How make use of the PDFNet Android PDFViewCtrl’s Tool and ToolManager interface:

https://groups.google.com/d/msg/pdfnet-sdk/fG-20n1gcPU/4Zslh603PZ8J

What are the differences between the “Standard” and “Full” libraries?

The SDK package includes two versions of the native libraries: standard and full.

In order to help our customers to create applications with a smaller file size, the standard version omits the following rarely used features (which are present in the full version):

  • Convert, Optimizer, Redactor and Flattener classes;
  • PDF/A validation/conversion;
  • Converting PDF pages to TIFF and PNG formats (i.e., PDFDraw will not work when using these formats).

Rendering speed and quality are the same for both versions of the library.

What is the pdfnet.res file?

This file contains fonts, CMaps and other standard PDF resources that are needed for the correct displaying of generic PDF documents (e.g., forms, text, free text annotations). If your documents are largely images and do not have text or annotations, then it may not be necessary. There are two ways to properly use this file in your project:

  1. PDFNet.initialize() method includes an extra parameter that can be used to load the resource file from the application bundle. For example:

1
PDFNet.initialize(this, R.raw.pdfnet);

This method will copy the file from “res/raw/pdfnet.res” to the private storage area of the application, and an exception will be thrown if there is no sufficient space to save the file, or if the resource ID can’t be found. Please note that the resource file must be named “pdfnet.res” when using this approach.

  1. You can call PDFNet.initialize() without the resource parameter, and use:

1
PDFNet.setResourcesPath(“path/to/resources/file”);

With this method you are handling installation of the resource file on your own. For example, the resource file can be downloaded on demand and saved at any location. When the resource file is ready for use it can be loaded using setResourcesPath().

How do I configure my ProGuard configuration file to properly obfuscate PDFNet?

Due to the nature of the SDK in using native and managed code, you will need to tell ProGuard not to obfuscate some classes. You need to include the following in your config file:

  • -keep class com.pdftron.pdf.PDFViewCtrl$RenderCallback { *; }
  • -keep class com.pdftron.pdf.PDFViewCtrl$PrivateDownloader { *; }
  • -keep class com.pdftron.filters.CustomFilter$CustomFilterCallback { *; }
  • -keep class com.pdftron.pdf.PDFViewCtrl$LinkInfo { *; }
  • -keep class com.pdftron.pdf.ProgressMonitor { *; }
  • -keep class com.pdftron.sdf.ProgressMonitor { *; }
  • -keep class com.pdftron.common.PDFNetException { *; }
  • -keep class com.pdftron.pdf.PreviewHandler { *; }
  • -keep class com.pdftron.pdf.RequestHandler { *; }
  • -keep class com.pdftron.pdf.TextSearchResult { *; }

How do I add views/widgets on top of PDFViewCtrl?

Since PDFViewCtrl extends a ViewGroup, it is possible to add views or widgets on top of a page programmatically using PDFViewCtrl.addView(…). One important point when using this approach is that you will have to set the layout of the view to be inserted (i.e., view.layout(…)), since PDFViewCtrl does not handle the views like a LinearLayout or RelativeLayout. Also, depending on your requirements you will have to extend PDFViewCtrl to be able to override the touch event methods and perform actions on the view(s) added.

Another option is to use a different view/layer and position it on top of PDFViewCtrl through the layout xml file.

Additional Resources

Samples

CompleteReader sample in the SDK package is a light version of our Xodo app in the play store. The CompleteReader sample has almost all functionalities of Xodo app except collaboration. Feel free to download and run Xodo and compare it with CompleteReader!