As discussed in prior posts on the Developer Blog (here and here), Intents are one of the most powerful features of Android. They allow you to leverage existing applications installed on an Android device to do your work for you. In today’s example, I’m going to show you how to use Intents to display a PDF from your Android applications.
The iOS browser displays PDFs, the Android browser does not. It’s that simple. Nothing we can do about it except account for it. So when we need to show a PDF in an Android app, we can’t just open it in a Titanium.UI.WebView, we need to use an Intent. But there’s an additional wrinkle or two to consider…
Let’s say we want to use a local project file as the data for an Intent. And by local I mean a file that resides in your project’s
Resources directory. In the upcoming example we’ll use a local PDF that we would like to view via Android Intent. The problem is that Intents don’t have access to your local files. In order to circumvent this limitation, we are going to use Titanium’s ability to access external storage to make our local project files available to all applications on the device.
Note: While this example addresses viewing local PDFs, the same principles can be applied to sharing any local project files among Android Intents.
There are a few important things to consider before attempting to run the example, or use its principles in your own code.
- You must have an app on your device that receives PDF intents. If you don’t you’ll be greeted with the
alert()that informs you that need one. I’d suggest Adobe Reader or Quickoffice.
- You’ll likely need to run this on an Android device. Your emulator won’t support it, unless you’ve installed an app to your emulator that receives PDFs via an Intent Filter.
- If your device is connected via USB while testing, make sure it is in “Charge Only” mode or you won’t be able to access your SD card for external storage. To do so:
- When your device is connected, pull down your Android task bar
- Tap the “USB Connection” row
- From the list, select “Charge Only”
PdfIntent App (Full project available here)
Below is the app.js for our example. In brief, we copy a local project file (w4.pdf) to external storage, then use this externally stored PDF as the data to be viewed by an Android Intent.
OK, let’s rip apart this code to fully understand what’s going on here.
Here we are just setting up our UI. Nothing fancy, just a window and a button. The button will eventually fire our PDF viewing Intent.
Above we define the path for our local PDF, w4.pdf. It is located in our project’s
Resources directory. Next we create a Titanium.Filesystem.File object out of it by using its path.
We need to ensure that we have access to external storage otherwise the called Intent won’t be able to access our PDF. To do so we utilize the built-in Titanium.Filesystem.isExternalStoragePresent() function. If external storage is available, we are going to create a temporary file in it that Android Intents can access to view our PDF. To do so we take the following steps.
- Create a temporary file in external storage via the Titanium.Filesystem.createTempFile() function.
- Rename the temporary file with a ‘pdf’ extension via the move() function. We do this because many PDF readers will not recognize the file without it.
- Finally, we get a file reference to the newly renamed temporary file. We then copy the contents of our project’s local PDF (
appFile) to the externally accessible temporary file (
Here’s where the magic happens. In our button’s click listener, we first test to make sure our tmpFile was created successfully. If it has been, we create our Intent via Titanium.Android.createIntent(). Let’s discuss the 3 properties set here.
- action – Specifies the action we want our Intent to handle. In this case we use the Titanium.Android.ACTION_VIEW constant as we want the receiving application to be able to view our PDF. More details about Android Intent constants can be found in Google’s extensive documentation.
- type – a MIME type on which Intent Filters, well, filter. Applications that intend to handle our Intent must be configured to handle this type. In this case, they must be able to handle PDFs.
- data – The path to the PDF. For other Intents, the value of this field will depend entirely on what you specified for
All we need to do now is grab our currentActivity and start a new one via startActivity(), using our newly created Intent as its only parameter. We wrap the call in a try/catch to handle the scenario where the device running this sample application has no applications installed that handle the viewing of PDFs.
Note: It is good practice to always perform exception handling when attempting to launch an Android Intent. Your users will be assaulted with an ugly exception in your app otherwise if there’s a failure.
Finally we make sure to clean up our temporary file when the application exits and we open our main window. If you read the prerequisites and ran this app, clicking the button should get you something that looks very similar to this:
So as you can see, you can show PDFs in Android, but it’s just a little bit trickier than iOS. In the process, though, you learned two incredibly powerful bits of Android knowledge. You now know how you can use Android Intents to do a lot of your app’s heavy lifting, and you know how to supply those Intents with your project’s local assets via external storage.
So while it may have seemed a bit difficult to perform this seemingly simple task, you are now equipped to handle much more. With this knowledge, and that in upcoming Android blog posts, you’ll be sharing your project’s PDFs, images, videos, text, and more with all the other Android applications on your device. This will have you spending less time on the boring stuff and more time on developing your app’s unique functionality.