Getting Started with Cross-Platform PDF Processing Using Xamarin.Android and PDFNet SDK

Introduction

This tutorial shows the minimum steps needed to add a PDF viewing and annotating component to a Xamarin.Android app using PDFNet SDK. In this tutorial, you will create a simple PDF viewing and annotating app. You will also create an Android Java Bindings Library Project that allows you to customize our Tools library.

Note that the completed sample project described in Part 2 and Part 3 can be found in the samples folder located inside the PDFNet component package. The completed sample project described in Part 2-4 is available by request from here.

The tutorial is divided into 6 parts:

To complete this tutorial, you will need to install and setup Xamarin.Android as described in this article.

Part 1: Things you should know about the library distribution.

  • Full version vs. Standard version: The PDFNet for Xamarin.Android library is available in two different versions, the Standard version and the Full version. The Standard library offers the same viewing, annotation, and editing capabilities of the Full version, however it is much smaller. The main differences are:
    • The Full library has a built-in digital signature handler, which can be used by calling PDFDoc.AddStdSignatureHandler(); the Standard version does not have built-in signature handler. However, even with the Standard version, you will still be able to use the DigitalSignature tool because the pre-built Tools library includes Spongy Castle.
    • The Standard version does not support converting PDF pages to TIFF and PNG formats (i.e. PDFDraw will not work when using these formats.)
  • Best for app development vs. Best for app deployment: To provide a user-friendly framework for both development and deployment, PDFNet provides two options for using the PDFNetAndroid.dll. (To learn more about Android CPU architecture, please refer to this article.)
    • Best for app development: a single PDFNetAndroid.dll that contains arm64-v8a, armeabi-v7a, x86, and x86_64 architectures that can be used to create a single APK that works on all armv7, arm64, x86 or x86_64 devices/emulators running Android 2.2 or greater. This .dll is located in Lib/Full and Lib/Standard.
    • Best for app deployment: three separate PDFNetAndroid.dlls for each architecture (arm64-v8a, armeabi, armeabi-v7a, x86, x86_64) that can be used to build five separate APKs. This allows an absolute minimum APK download size, and allows you to create APKs that work on arm, armv7, arm64, x86 and x86_64 devices/emulators running Android 2.2 or greater. These .dlls are found in the /arm64-v8a, /armeabi, /armeabi-v7a, /x86 and /x86_64 folders respectively. (These three folders are themselves located in /Lib/Full and /Lib/Standard.)

Part 2: Run the sample project.

  • Open the sample project: In Xamarin Studio or Visual Studio, from the ‘File’ menu select ‘Open…’ and browse to ‘/samples/PDFNetAndroidXamarinSample’ folder shown below, select PDFNetAndroidXamarinSample.sln and click ‘Open’.
  • The project structure will resemble the following screenshot:

  • The project is now ready to run! Press ‘Run’ button to build the project and start the application. The application (running in emulator) will look like the following screenshot:
  • Note that if you don’t need the tools functionality, you can use only PDFNetAndroid.dll library and not set tool for PDFViewCtrl, i.e. remove the following code from the ‘MainActivity.cs’:
ToolManager toolManager = new ToolManager(mPdfViewCtrl);
mPdfViewCtrl.ToolManager = toolManager;
  • With tools functionality, long press on a blank field will bring up the tools popup menu:

Part 3: Create a new application with PDFNetAndroid.dll and Tools.dll.

This part demonstrates how to create a brand new Xamarin.Android application that uses PDFViewCtrl and Tools add-on to build a PDF viewer with a rich set of functionality. (If this is your first Xamarin.Android project, it would be worth following Xamarin’s Xamarin.Android Hello World project in this article before proceeding.)

  • Create a new Xamarin.Android Application solution: In Xamarin Studio or Visual Studio, from the ‘File’ menu select ‘New’ > ‘Solution’ in Xamarin Studio, or ‘File’ > ‘New’ > ‘Project’ in Visual Studio, select ‘Android Application’ in the dialog shown below:

  • Add a reference to PDFNet: Select ‘Edit References…’ in Xamarin Studio, or ‘Add Reference…’ in Visual Studio, browse to ‘/lib/android/Standard’ folder, and add PDFNetAndroid.dll to the references.
  • Add reference to the Tools library: Select ‘Edit References…’ in Xamarin Studio, or ‘Add Reference…’ in Visual Studio, browse to ‘/lib/android’ folder, and add Tools.dll to the references.
  • You are now ready to use PDFNet and Tools libraries for your application!

Some tips to get started:

  • Initialize PDFNet with the following call before using any other PDFNet method:
PDFNet.Initialize(this, Resource.Raw.pdfnet);
  • To create a PDFViewCtrl control and set it as content view:
PDFViewCtrl mPdfViewCtrl = new PDFViewCtrl(this, null);
SetContentView(mPdfViewCtrl);
  • To include a PDF document compiled with the project:
    • Create a sub-folder under Resources (i.e. raw)
    • Add the PDF document to the folder created as described above (i.e. Resources/raw/sample.pdf)
    • Make sure the Build Action of the document is set to AndroidResource
    • Then this document can be accessed as Resource.Raw.sample
  • To set PDFViewCtrl associated with a PDFDoc from resources:
Stream fis = this.Resources.OpenRawResource(Resource.Raw.sample);
PDFDoc docToOpen = new PDFDoc(fis);
mPdfViewCtrl.Doc = docToOpen;
  • To set PDFViewCtrl associated with a PDFDoc from a URL:
string cache_file = this.CacheDir.Path + "/pdfref.pdf";
mPdfViewCtrl.OpenURL("http://www.pdftron.com/downloads/pdfref.pdf", cache_file, "", null);
  • To use Tools with PDFViewCtrl:
ToolManager toolManager = new ToolManager(mPdfViewCtrl);
mPdfViewCtrl.ToolManager = toolManager;

Part 4: Create a new application with PDFNetAndroid.dll and customized PDFViewCtrlTools.zip or PDFViewCtrlTools.aar library.

In the previous section you have seen how to use PDFViewCtrl with the tools add-on. If you want to customize the tools functionality, you will need to do so using the Java source code which is available by request on our website. And then prepare the .zip or .aar for use in Xamarin. This section demonstrates how to build a Xamarin.Android application that uses PDFViewCtrl and your own version of PDFViewCtrlTools.zip or PDFViewCtrlTools.aar to build a PDF viewer.

The following section covers the steps to create Xamarin bindings for the PDFViewCtrlTools.zip or PDFViewCtrlTools.aar library and use it in your application. If this is your first Xamarin bindings project, it would be worth following Xamarin’s Binding a Java Library project in this article before proceeding, pay special attention to section 5: Android Library Project.

Preparation: To use your own customized version of the PDFViewCtrlTools, you will need to build the PDFViewCtrlTools Java library using either Eclipse or Android Studio.

Using Eclipse:

1. Have the corresponding version of the PDFViewCtrlTools library ready (included in the package).

2. In Eclipse, make sure the Support Library is setup as described in Support Library Setup. Pay special attention to step “Adding libraries with resources”.

3.  Follow the section “Adding support for Annotations, Text Selection and Form Filling” from our Android tutorial on building Tools library in Eclipse.

4. Clean and build the library. Make sure there is no error before proceeding. Close Eclipse then go to the PDFViewCtrlTools project folder. Create a PDFViewCtrlTools.zip file that contains the bin and res folder. This PDFViewCtrlTools.zip file will be embedded into the .NET assembly of the library project. Note: if for some reason, there is a PDFViewCtrlTools\bin\res\crunch folder, you will need to copy all the files from this crunch folder and paste them directly under res folder and delete the crunch folder before creating the PDFViewCtrlTools.zip file!

Using Android Studio:

1. Have the corresponding version of the PDFViewCtrlTools library ready (included in the package).

2. Add the following to the beginning of PDFViewCtrlTools\build.gradle:

buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
}
}

repositories {
mavenCentral()
}

3. In Android Studio, click ‘File’ > ‘New’ > ‘Import Project…’, select root folder PDFViewCtrlTools and follow the gradle guide to import the project.

4. Create a build of the project in Android Studio. (For release build, you will need to add keystore information to the build.gradle)

5. Obtain the PDFViewCtrlTools.aar from build\outputs\aar

Then follow the following steps:

  • Open the Android Java Bindings Library project provided in the package: located in samples\PDFNetAndroidXamarinSample\Tools\PDFViewCtrlTools.csproj:
  • Next, add either the PDFViewCtrlTools.zip or PDFViewCtrlTools.aar to the project, and set the build action to LibraryProjectZip (see screenshots below). Note, only one of the two is necessary, not both.xamarin-tools
  • Add a reference to the PDFNet library: Select ‘Edit References…’ in Xamarin Studio, or ‘Add Reference…’ in Visual Studio, browse to ‘/lib/android/Standard’ (or ‘/lib/android/Full’) folder, and add PDFNetAndroid.dll to the references.
  • For easy access of managed class names, we can map the Java package name to C# namespace, remove unnecessary classes to reduce the library size and solve binding errors. This can be done by adding the following lines to ‘Transforms/Metadata.xml‘:
  <remove-node path="/api/package[starts-with(@name, 'org.spongycastle')]" />
 <remove-node path="/api/package[starts-with(@name, 'com.google.gson')]" />

 <remove-node path="/api/package[starts-with(@name, 'pdftron.Common')]" />
 <remove-node path="/api/package[starts-with(@name, 'pdftron.FDF')]" />
 <remove-node path="/api/package[starts-with(@name, 'pdftron.Filters')]" />
 <remove-node path="/api/package[starts-with(@name, 'pdftron.PDF.Annots')]" />
 <remove-node path="/api/package[starts-with(@name, 'pdftron.PDF.OCG')]" />
 <remove-node path="/api/package[starts-with(@name, 'pdftron.PDF.PDFA')]" />
 <remove-node path="/api/package[starts-with(@name, 'pdftron.PDF.Struct')]" />

 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Bookmark']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='CharData']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='CharIterator']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='ColorPt']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='ColorSpace']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='ContentReplacer']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Convert']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Date']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Destination']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Element']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='FieldIterator']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='FileSpec']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Flattener']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Font']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='FontCharCodeIterator']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Function']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='GSChangesIterator']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='GState']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Image']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Optimizer']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Page']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='PageIterator']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='PageLabel']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='PageSet']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='PathData']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='PatternColor']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='PDFDocInfo']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='PDFDocViewPrefs']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='PDFRasterizer']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Point']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='QuadPoint']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Redactor']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Shading']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Stamper']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='TextExtractor']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='TextSearch']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='TextSearchResult']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Image2RGB']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Image2RGBA']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='ElementBuilder']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='ElementWriter']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='ElementReader']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Field']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='PDFDraw']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Rect']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Action']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='Annot']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='PDFDoc']" />
 <remove-node path="/api/package[@name='pdftron.PDF']/class[@name='PDFViewCtrl']" />

 <remove-node path="/api/package[@name='pdftron.SDF']/class[@name='DictIterator']" />
 <remove-node path="/api/package[@name='pdftron.SDF']/class[@name='NameTree']" />
 <remove-node path="/api/package[@name='pdftron.SDF']/class[@name='NameTreeIterator']" />
 <remove-node path="/api/package[@name='pdftron.SDF']/class[@name='NumberTree']" />
 <remove-node path="/api/package[@name='pdftron.SDF']/class[@name='NumberTreeIterator']" />
 <remove-node path="/api/package[@name='pdftron.SDF']/class[@name='Obj']" />
 <remove-node path="/api/package[@name='pdftron.SDF']/class[@name='SDFDoc']" />
 <remove-node path="/api/package[@name='pdftron.SDF']/class[@name='ObjSet']" />
 <remove-node path="/api/package[@name='pdftron.SDF']/class[@name='SecurityHandler']" />
 <remove-node path="/api/package[@name='pdftron.SDF']/class[@name='SignatureHandler']" />
 
 <attr path="/api/package[@name='pdftron.PDF.Tools']/class[@name='FreehandCreate']" name="visibility">private</attr>
 <attr path="/api/package[@name='pdftron.PDF.Tools']/class[@name='Tool']" name="visibility">private</attr>
 <attr path="/api/package[@name='pdftron.PDF.Tools']/class[@name='Pan']" name="visibility">private</attr>
 <attr path="/api/package[@name='pdftron.PDF.Tools']/class[@name='Signature']" name="visibility">private</attr>
 <attr path="/api/package[@name='pdftron.PDF.Tools']/class[@name='TextMarkupCreate']" name="visibility">private</attr>
 <attr path="/api/package[@name='pdftron.PDF.Tools']/class[@name='TextHighlightCreate']" name="visibility">private</attr>
 <attr path="/api/package[@name='pdftron.PDF.Tools']/class[@name='TextSquigglyCreate']" name="visibility">private</attr>
 <attr path="/api/package[@name='pdftron.PDF.Tools']/class[@name='TextStrikeoutCreate']" name="visibility">private</attr>
 <attr path="/api/package[@name='pdftron.PDF.Tools']/class[@name='TextUnderlineCreate']" name="visibility">private</attr>
 <attr path="/api/package[@name='pdftron.PDF.Tools']/class[@name='DigitalSignature']" name="visibility">private</attr>
 <attr path="/api/package[@name='pdftron.PDF.Tools']/class[@name='Eraser']" name="visibility">private</attr>
 
 <attr path="/api/package[@name='pdftron.PDF.Controls']/class[@name='OutlineDialogFragment']" name="visibility">private</attr>
 <attr path="/api/package[@name='pdftron.PDF.Utils']/class[@name='StampManager']" name="visibility">private</attr>
 
 <attr path="/api/package[@name='pdftron.PDF.Tools']" name="managedName">pdftronprivate.Tools</attr>
 <attr path="/api/package[@name='pdftron.PDF.Controls']" name="managedName">pdftronprivate.Controls</attr>
 <attr path="/api/package[@name='pdftron.PDF.Utils']" name="managedName">pdftronprivate.Utils</attr>
  • Use the Binding Library:
    • Create a new Xamarin.Android Application Project
    • Add a reference to the PDFNet library: Select ‘Edit References…’ in Xamarin Studio, or ‘Add Reference…’ in Visual Studio, browse to ‘/lib/android/Standard’ (‘/lib/android/Full’) folder, add PDFNetAndroid.dll to the references
    • Add a reference to the binding project: add PDFViewCtrlTools project to the references
    • You are now ready to use PDFNet and Tools libraries for your application!

Part 5: FAQ.

    • 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 PDFNet’s Java API, and mapped to the idioms used in .NET using Xamarin C# bindings of Java APIs. If you are interested in customize how users interact with the PDF, the tools source code is available by request on our website.

  • 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:
    PDFNet.Initialize(this, Resource.Raw.pdfnet);
  • This method will copy the file from “Resources/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:
    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().

Part 6: Next steps.

This concludes our introductory PDFNet for Xamarin.Android Tutorial. The completed tutorial project is available by request from here. For more help, please see the sample code, and other tutorials. You can also browse our public forum for more information about PDFNet. For details related to technical support, please refer to PDFTron support page.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s