How to Write an HTML to PDF App for Android/iOS Using Cordova
Learn how to install and use this plugin for Cordova, which will allow you to generate reports in PDF format without complicating things with a server-side API.
Join the DZone community and get the full member experience.
Join For Free
Some of my day-to-day work is to design and develop hybrid mobile/desktop applications using Apache Cordova and Node.JS. One of the typical challenges I face when working with customers is how to generate reports or other documentation in PDF format. The usual way to solve this was to use a server-side API, render the document there, and send it to the phone. This is far from good, the first reason being that you need network connectivity for this to work, the second being the lack of good and free PDF APIs on the server side, so I decided to write a plugin to move this job to the mobile device. The advantages of doing this are:
You can use this functionality offline.
The user has more control over the experience.
You can share the document across apps (Print, Email, Cloud Storage, etc...).
Offloading tasks from the servers.
How It Works
So basically, to make this, I wanted to use HTML/CSS as the template engine, so you can use these familiar markup languages to define how your PDF is going to look, then load the content via network or local to an offscreen Webkit object both in Android or iOS, then just render the content to a PDF file.
Getting Started
Assuming you have installed the latest version of Cordova, let's try to write a simple example for both platforms.
cordova create hello-pdf # this will create a new cordova project
# initializing mobile platforms
cd ./hello-pdf/
cordova platform add ios # Make sure you installed XCode
cordova platform add android # Make sure you have Android Studio
# installing the plugin
cordova plugin add cordova-pdf-generator
Now we need to do some coding to create our PDF. To start, we need to use our favorite editor to open the JavaScript entry file located in ./hello-pdf/www/index.js. The content should be something similar to this:
var app = {
// Application Constructor
initialize: function() {
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
},
// deviceready Event Handler
// Bind any cordova events here. Common events are:
// 'pause', 'resume', etc.
onDeviceReady: function() {
this.receivedEvent('deviceready');
},
// Update DOM on a Received Event
receivedEvent: function(id) {
var parentElement = document.getElementById(id);
var listeningElement = parentElement.querySelector('.listening');
var receivedElement = parentElement.querySelector('.received');
listeningElement.setAttribute('style', 'display:none;');
receivedElement.setAttribute('style', 'display:block;');
console.log('Received Event: ' + id);
}
};
app.initialize();
We need to edit the function receivedEvent; this function will be called after Cordova is done initializing the framework, so it's the place where we should place our code.
var app = {
// Update DOM on a Received Event
receivedEvent: function(id) {
var parentElement = document.getElementById(id);
var listeningElement = parentElement.querySelector('.listening');
var receivedElement = parentElement.querySelector('.received');
listeningElement.setAttribute('style', 'display:none;');
receivedElement.setAttribute('style', 'display:block;');
// Our code start here
var opts = {
type: "share", //Open a context menu and ask the user what to do next (print, mail, etc..).
fileName: 'v8-tutorial.pdf' //it will use this filename as a place-holder
}
pdf.fromURL('https://cesarvr.io/post/2015-11-20-javascript-v8/', opts)
.then((status) => console.log('success->', status))
.catch((error) => console.log(error));
// It end here
console.log('Received Event: ' + id);
}
};
app.initialize();
Now its time to run deploy our code in the device of our choice:
#put our www/ folder inside our target platform.
cordova prepare
#Deploy in Android.
cordova run android
#Deploy in iOS.
cordova run ios
Above: Android.
Above: iOS.
We should see our beautiful PDF being generated for us. In this example, I use a external web as my template, and as you can see, I used the option {type: 'share'} to the plugin; this means it will pop up a contextual menu with some helpful options. This is a good choice if you want your app to integrate with the OS ecosystem, or to give the option for the user to have full control over the experience, which is important because it gives the user flexibility.
If you just want to have control over the document, you can use the option {type: 'base64'}. This will transform it to a base64 string that you can upload to a server, encrypt, or display using your own library.
Conclusion
I hope this plugin helps to simplify this task, and maybe helps in moving some server load to the phone.
If you need more info, you can find it in the documentation; also, you can access this demo with more use cases, like loading files from the phone file system, etc.
Also, this project is open source, so if you want to contribute, here is the GitHub repository.
Published at DZone with permission of Cesar Valdez, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments