Android PDF Viewers In Depth

Helpful? Then DOWNLOAD and RATE my app!

Helpful? Then DOWNLOAD and RATE my app!

Google really dropped the ball when it decided not to provide a native PDF Viewer for Android.  After reading a lot on the subject, I understand that Google believed developers would be fine allowing their apps to open another application to view PDFs using the Intent structure. But, while some developers are OK with this approach many others don’t want to redirect their users to an uncontrolled experience that will close their own app.

Google finally realized this and included a native PDF viewer in KitKat (https://developer.android.com/about/versions/android-4.4.html). But, since the vast majority of users don’t have KitKat this doesn’t solve the problem – unless Google develops a compatibility library.

To frustrate the situation, a query on StackOverflow produces so many responses but no definitive answer to the question “what basic PDF Viewer can be added to my app?”. That is, until now.

Below I discuss every solution I ran across and how to use it – well, when I could get it to work. You can dig through each method if you want or you can trust my conclusion:

MuPDF is the best solution if 1)you have the patience and time to install it and 2)your code can be open source. If this is the case, follow my incredibly thorough instructions below and you will be satisfied.

PlugPDF is the best solution if 1)you want a plug-and-play solution and don’t have the time or patience to for MuPDF or 2)your code must remain closed source and 2)you can pay for it. Honestly, $699 for the code is fair since it’s a one time cost, you don’t have to hire a developer, and their competitors charge more than venture capitalists (not exaggerating).

iText


iText is NOT a PDF viewer! Instead, iText is a library that provides methods for creating a pdf, converting HTML to PDF, converting PDF to Bitmap, and other such PDF creation methods. You could use iText to convert a PDF to a Bitmap which is then displayed in a view, but then you’d be doing all the work to make a PDF Viewer when better solutions exist.

 Intents: Google Docs Reader


Launch a chooser that allows the user to select which web browser to use and then open Google Docs Viewer website to display the PDF.

Cost:

  • Free

Pros:

  • Really easy to implement
  • It’s free
  • PDFs are always loaded correctly
  • Zoom in/out with button

Cons:

  • Online PDF is displayed outside your app, in web browser instead of natively in app, and only with internet
  • Pinch zoom is not available

Features:

  • Display online PDF using a web browser

Usage:

MainActivity.java

import java.net.URLEncoder;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        String myPDFURL = "http://www.metafuture.org/pdf/futureofindonesia.pdf";

        String link;
        try{
            link="http://docs.google.com/viewer?url="
            +URLEncoder.encode(myPDFURL,"UTF-8")
            +"&embedded=true";            

            Uri uri = Uri.parse(link);
            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
            startActivity(intent);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

 Intents: PDF Viewer Chooser


Launch a chooser that allows the user to select which PDF viewer to use for opening the file.

Cost:

  • Free

Pros:

  • Really easy to implement
  • It’s free
  • Rich features without having to code or maintain them

Cons:

  • User is directed away from your app

Features:

  • Depends on the viewer that is selected

Usage:

AndroidManifest.xml




    

    
    
    
        
            
                

                
            
        
    

MainActivity.java
package com.pdfviewer_intentspdfchooser;

import java.io.File;
import java.util.List;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.widget.Toast;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        File file = new File(Environment.getExternalStorageDirectory().toString()
                + "/hospcombrprt.pdf");
        String mimeType = "pdf";
        
        openFile(file,mimeType);
    }
    
    private void openFile(File file, String mimeType){
        Intent viewIntent = new Intent();
        viewIntent.setAction(Intent.ACTION_VIEW);
        viewIntent.setDataAndType(Uri.fromFile(file), mimeType);
        
        // using the packagemanager to query is faster than trying startActivity
        // and catching the activity not found exception, which causes a stack unwind.
        List resolved = getPackageManager().queryIntentActivities(viewIntent, 0);
        
        if(resolved != null && resolved.size() > 0){
            startActivity(viewIntent);
        }else{
            // notify the user they can't open it.
            Toast.makeText(this, "Cannot open file", Toast.LENGTH_LONG).show();
        }
    }
}

Intents: Intents Adobe Reader


Open the file by forcing Adobe Reader to be launched. This will fail to open the document if the app is not already installed.

Cost:

  • Free

Pros:

  • Really easy to implement
  • It’s free
  • Rich features without having to code or maintain them

Cons:

  • User is directed away from your app

Features:

  • Depends on Adobe’s mood

Usage:

AndroidManifest.xml




    
    
    

    
        
            
                

                
            
        
    

MainActivity.java

package com.pdfviewer_intentadobereader;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        String filePath = Environment.getExternalStorageDirectory().toString()
                + "/hospcombrprt.pdf";
        
        try {
            loadDocInReader(filePath);
        } catch (ActivityNotFoundException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private void loadDocInReader(String filePath)
        throws ActivityNotFoundException, Exception {

        try {
            Intent intent = new Intent();
    
            intent.setPackage("com.adobe.reader");
            intent.setDataAndType(Uri.parse(filePath), "application/pdf");
    
            startActivity(intent);

        } catch (ActivityNotFoundException activityNotFoundException) {
            activityNotFoundException.printStackTrace();

            throw activityNotFoundException;
        } catch (Exception otherException) {
            otherException.printStackTrace();

            throw otherException;
        }
    }
}

PDF Viewer v1.1 (aka EbookDroid)


PDF Viewer v1.1 is the same as EbookDroid. This used to be an open source project but has become closed source. They may do licenses but I have no clue. If it ever becomes open source again or if they provide an API for use in other applications, it would be great since this viewer is blazing fast, reliable, very popular on the market, and could be embedded into your app.

Since it’s closed, I’m not going to discuss it more.

GitHub: https://github.com/mortenpi/ebookdroid

Quoppa Android PDF Toolkit


I do not know much about the functionality, useability, extensiveness, or much else about this product because I abandoned all notion of using this API after receiving the following response to my inquiry about pricing:

When the app produces revenue, then we use a royalty based license, the license is set at 8% of any revenue that is produced by the app, with a minimum of $3000 per year.  Royalties include free upgrades as well as technical support, there is no other fees.

I think this is nonsense, no matter their product, when considering the fact that a venture capitalist has to invest $15,000 for that percentage of a start-up. For this reason, and given the other great options on the list (MuPDF and PlugPDF) I hope nobody buys into this product!

VuDroid


VuDroid loads a PDF pages in rectangular sections and rather slowly. It was too slow for my taste, especially given the other viewers, and so I have no more info on it.

GitHub Repo: https://github.com/xiedantibu/vudroid

Android-pdfview


I found this while looking for VuDroid and It seems to be based on VuDroid. According to its website, it’s a “fast pdf reader component for Android” with animations, gestures, and zoom. I tried importing into Eclipse but ran into many problems. First of all, it requires actionbarSherlock for the example. Secondly, it requires the VuDroid library. Finally, it was built using Maven which has some commands that aren’t recognized in my Eclipse since I don’t have Maven plugins installed. Finally, there was no .apk for me to download just to review the speed and functionality. For these reasons, I stopped trying and have no further information.

Site: http://joanzapata.com/android-pdfview/

GitHub Repo: https://github.com/JoanZapata/android-pdfview

WebView: Google Docs Reader


This is almost the same approach used in “Intent: Google Docs Reader,” except that it doesn’t redirect the user away from your application to a web browser. Instead, your application is creates a webView and acts like a web browser in order to display the Google Docs Viewer webpage inside your app.

Cost:

  • Free

Pros:

  • Really easy to implement
  • It’s free
  • Online PDF can be viewed inside your app
  • Pinch zoom automatic and works well
  • PDFs are always loaded correctly

Cons:

  • PDF cannot be loaded from device
  • Google Docs Viewer theme will likely conflict with your app’s custom theme
  • Panning the document is jerky
  • No control over viewer’s buttons
  • Must have internet to view PDF

Features:

  • Display online PDF using a web browser while connected to internet
  • Next/Previous page
  • Zoom in/out using button or pinch

Usage:


AndroidManifest.xml




    
    
    

    
        
            
                

                
            
        
    



MainActivity.java

package com.pdf_webview_googdocspreviewer;
import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.webkit.WebSettings.PluginState;

public class MainActivity extends Activity {
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        WebView mWebView=new WebView(MainActivity.this);
        
        //Tell app to load webpage in app
        mWebView.setWebViewClient(new WebViewClient());
        
        //Use webview's built-in pinch and zoom
        mWebView.getSettings().setBuiltInZoomControls(true);
        
        //Makes webview more viewable...i.e. without this it seems
        //like android loads the webpage at too large a scaling
        mWebView.getSettings().setLoadWithOverviewMode(true);
        mWebView.getSettings().setUseWideViewPort(true);
        
        //Google docs viewere requires this
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.getSettings().setPluginState(PluginState.ON);
        
        //Load the page into the webview
        mWebView.loadUrl("http://www.metafuture.org/pdf/futureofindonesia.pdf");
        
        //Set the app's main view to the webView that displays the pdf
        setContentView(mWebView);
    }
}

Android-Pdf-Viewer-Library


I tried on two devices 4.0 and 4.3 and is not good. Load takes forever and usually doesn’t work. When it works the next/previous page works inconsistently. Functionality when a page does load the responsiveness is poor.

Site: http://andpdf.sourceforge.net/

GitHub: https://github.com/jblough/Android-Pdf-Viewer-Library

Cost:

  • Free

Pros:

  • Really easy to implement
  • It’s free

Cons:

  • It just doesn’t work for me
  • Your activity must extend PdfViewActivity rather than using a PdfView – sure, some re-coding may provide that capability but it’s not worth it based on the speed

Features:

  • Displays PDF(supposedly)
  • Next/Previous page

Usage:

  1. Clone the repo from GitHub
  2. Import the cloned repo library into Eclipse
  3. Create a new project in Eclipse and add the library to the new project
  4. Copy and paste the MainActivity.java code from below into your MainActivity.java file in the new project.
  5. Create PdfViewerActivity.java in the same package as MainActivity.java and copy the following code into it.
PdfViewerActivity.java

package com.pdfviewer_usingactivity;

public class PdfViewerActivity extends net.sf.andpdf.pdfviewer.PdfViewerActivity {
     public int getPreviousPageImageResource() { return R.drawable.left_arrow; }
     public int getNextPageImageResource() { return R.drawable.right_arrow; }
     public int getZoomInImageResource() { return R.drawable.zoom_in; }
     public int getZoomOutImageResource() { return R.drawable.zoom_out; }
     public int getPdfPasswordLayoutResource() { return R.layout.pdf_file_password; }
     public int getPdfPageNumberResource() { return R.layout.dialog_pagenumber; }
     public int getPdfPasswordEditField() { return R.id.etPassword; }
     public int getPdfPasswordOkButton() { return R.id.btOK; }
     public int getPdfPasswordExitButton() { return R.id.btExit; }
     public int getPdfPageNumberEditField() { return R.id.pagenum_edit; }

}
MainActivity.java

package com.pdfviewer_usingactivity;

import java.io.File;
import java.io.FilenameFilter;

import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class MainActivity extends ListActivity {

    String[] pdflist;
    File[] imagelist;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.main);

        File images = Environment.getExternalStorageDirectory();
        imagelist = images.listFiles(new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return ((name.endsWith(".pdf")));
            }
        });
        pdflist = new String[imagelist.length];
        for (int i = 0; i < imagelist.length; i++) {
            pdflist[i] = imagelist[i].getName();
        }
        this.setListAdapter(new ArrayAdapter(this,
                android.R.layout.simple_list_item_1, pdflist));
    }

    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        String path = imagelist[(int) id].getAbsolutePath();
        openPdfIntent(path);
    }

    private void openPdfIntent(String path) {
        try {
            final Intent intent = new Intent(this, PdfViewerActivity.class);
            intent.putExtra(PdfViewerActivity.EXTRA_PDFFILENAME, path);
            startActivity(intent);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

PlugPDF


Simply put, if you have the money and don’t have the time or patience for MuPDF, buy this! It’s fast and has great functionality. The demos can be downloaded from the link below and are truly simple to install.

My main quarrel is that the out-of-the box API requires that your app extend PlugPdf’s activity. It would be preferable to have a view that displays the pdf since we are trying to incorporate the functionality inside our own app. I asked if it were possible to use a view rather than Activity and hear was the response is below. In short, it’s possible but you’ll have to do a little more work.

Plug-and-play solutions requires your Activity to extend You can refer SimpleDocumentReader source code. SimpleDocumentReader is a basic viewer class for user convenience. Actually it accesses to a PDF file through a ReaderView instance. As the source code of simpleDocumentReader is open to you, you can freely modify and use it to add ReaderView function to your own View. For controls UI, please refer SimpleDocumentReader.java::onLoadFinish.

My second quarrel is that they claim it’s free for independent developers and personal use. This is not true. They allow you to download the example app for free and play around. But, there is a key that you must buy in order to use the library in your own app. This key is mapped to the package name of a single app.

This leads me to my final quarrel…purchase agreement is a little much. There are several API levels to buy starting at $699. You must buy this library for each app that you want to use it in, for each developer, and you must buy library updates after a year.

Ok, it may seem like I hate this product, but I don’t. I highly recommend it for groups that have the money and don’t have the time, or don’t want to hire a specialized pdf developer just for a short time. It’s worth the time and is a quality product and is certainly cheaper than hiring somebody or buying from one of their competitors.

Site: http://plugpdf.com/download/

Cost:

  • Starts at $699

Pros:

  • Really easy to implement
  • A business that supports the product when things don’t work
  • One time cost that beats its competitors and is less than hiring your own specialized developer

Cons:

  • Too expensive for single developers who are making their first app
  • Your activity must extend PdfViewActivity rather than using a PdfView

Features:

The simple demo:

  • Loads PDF from Http (assumed based on demo name)
  • Loads PDF really slowly (maybe it’s because the pdf is very heavy in images and being downloaded from online?)
  • PDF updates well after downloaded
  • PDF scrolls from left to right, fits page to screen width, and snaps page to screen center
  • No other features shown-if this is all that’s provided in the lowest cost then it’s not much

The Premium Demo:

  • Loads pdf quickly
  • Draw with grey pen and save
  • Draw rectangles,ovals, line and save
  • Add note symbol->hit edit->add header and text
  • Long-click to select text-works pretty well but it would be nice to see different handles. Drag two circular handles to make selection. When selected prompt allows copy to clipboard, highlight texts, underline, strikeout, squiggly(like a mispelled word)
  • Pinch zoom in/out works pretty well though a little jerky (not terrible)
  • Pan/fling when zoomend in
  • Thumbnail scrollview at bottom that lets you select a page and go to it
  • Search for text works well
  • Available Memory is also displayed (nice for development)

Usage:

  1. Download library from website
  2. Import library into Eclipse
  3. Import PDFHttpDemo(simple demo) into Eclipse and link to the library
  4. Import PDFReaderDemo(premium demo) into Eclipse and link to the library
  5. Create a new project in Eclipse and add the library to the new project
  6. Run both projects and poke around

MuPdf


This is the best solution for developers who 1)have no money – or don’t want to pay 2)can open source their code 3)have the time and patience to follow the instructions below. It is the best solution out there, period. It is very fast, always displays PDFs correctly, is feature rich, and is free if you can open source your code. It provides a PDF view that can be placed in any layout rather than having to extend an Activity – which is my biggest turnoff from any API. The only downside is that it does take half a day to install all the pre-reqs just to get the example app running – which is actually the same MuPDF Reader that is on the Android Market.

If you have Windows then follow the procedure below and you will get this running in the end. I know because I had not installed anything on my brand new computer and ran into pretty much every possible bug and resolved it – hopefully.

Site: www.mupdf.com/docs/how-to-build-mupdf-for-android

GitHub: https://github.com/muennich/mupdf

Cost:

  • Free

Pros:

  • Display pdf in your app using a view
  • Blazing fast
  • Always loads PDF correctly
  • Feature rich

Cons:

  • Takes a lot of time to install all the required components
  • The license means your project must be open source or pay for a license-no clue how much it would be

Features:

  • Text Selection: Works really well with single column but not with multiple columns. If multiple columns then text of all columns is selected if those columns have text at same vertical position on screen (maybe a bug?)
  • Navigate to a specified page
  • Search for text
  • Pinch zoom works well

Installation Instructions :

Set-up an Android Build Environment

  1. Downlaod and install the Android SDK
  2. Run the Android tool to install the platform tools
  3. Add the tools and platform-tools directories inside the SDK directory to your PATH
  4. Download and install the Android NDK (THIS IS DIFFERENT than SDK)
  5. Install a Java JDK (THIS IS DIFFERENT than JRE)
  6. Install ANT
  7. Install GIT (http://msysgit.github.io/) then Tortoise GIT(https://code.google.com/p/tortoisegit/wiki/Download)
  8. Install CYGWIN (https://www.cygwin.com/install.html) with everything marked for Development, Debug, and X11. This will take hours, but I don’t know which individual packages are used and this is the best way to guarantee all commands will be available that are needed.

Prepare the source

1. Open C:\

2. Right-click -> Git Bash (if you don’t see the option, GIT and/or TortoiseGit aren’t installed). In the Git Bash window, clone the main project by typing the following:

$ git clone git://git.ghostscript.com/mupdf.git

3. Update the third party submodules by typing the following:

$ cd C:\mupdf\

$ git submodule update –init

4. Populate the generated directory with the necessary files by opening a CYGWIN terminal and running the following commands:

$ cd “/cygdrive/c/mupdf/”

$ make generate

NOTES:

  • Error: make command does not exist or is not recognized. Potential causes: was typed into windows terminal or GIT Bash terminal instead of CYGWIN terminal. If it was typed into CYGWIN terminal then the make package was not installed so open the CYGWIN installed and install every package in Dev,Debug,X11 and try again
  • cygdrive is the “virtual Linux drive” for cygwin and /cygdrive/c/ represents C:/
  • Use parentheses around the entire filepath just in case there are spaces in the folder or file name

Build and Debug

1.Create a copy of the properties file by running the following commands in the CYGWIN prompt:

$ cd “/cygdrive/c/mupdf/platform/android”

$ cp local.properties.sample local.properties

2. Open local.properties from C:/mupdf/platform/android in a text editor of your choice (I use Notepad++)

3. Remove the # in the following line and save:

#sdk.dir=C:\\Program Files (x86)\\Android\\android-sdk

NOTE: This assumes your Android SDK is located at C:\Program Files (x86)\Android\android-sdk If it is located at a different path then use that path but replace \ by \\

 4. Build the native code libraries by running the following command in the CYGWIN prompt (still in c/mupdf/platform/android):

$ cd “/cygdrive/c/program files (x86)/ndk/”

$ cd ndk-build

NOTE: ndk command not found

  •  This assumes your NDK is located at the stated filepath
  • Likely this is because you have installed the SDK, the package you’ve been using to code in Android. So, install the NDK

5. Build the java application by calling the following commands in CYGWIN prompt:

$ cd “/cygdrive/c/mupdf/platform/android”

$ ant debug

Install on Device

  1. Add at least one pdf to the downloads folder on the sdCard
  2. Import MuPDF into Eclipse.
  3. Run the Android Application on your device
Helpful? Then DOWNLOAD and RATE my app!

Helpful? Then DOWNLOAD and RATE my app!

Leave a comment