Getting Started with Android
There are many apps in which data from the app is provided to users in the downloadable PDF file format. So in this case we have to create a PDF file from the data present inside our app and represent that data properly inside our app. So by using this technique, we can easily create a new PDF according to our requirements. In this article, we will take a look at creating a new PDF file from the data present inside your Android app and saving that PDF file in the external storage of the users’ device. So for generating a new PDF file from the data present inside our Android app we will be using Canvas. Canvas is a predefined class in Android which is used to make 2D drawings of the different objects on our screen. So in this article, we will be using canvas to draw our data inside our canvas, and then we will store that canvas in the form of a PDF. Now we will move towards the implementation of our project.
Introduction
PDFNet Mobile SDK for Android brings the full power of the PDFNet library to Android devices. The SDK ships with simple to use Java APIs that allow developers to seamlessly integrate PDF viewing, creation, searching, annotation, and editing capabilities with their Android apps. This document will explain how to download the SDK, describe its basic components, step you through creating a simple PDF viewing app, and point you towards helpful resources. It is organized into the following sections
First Steps
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.
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.
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):
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:
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 | <manifest xmlns:android= "http://schemas.android.com/apk/res/android" 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.
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:
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:
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:
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.
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!
Post a Comment
0Comments