So far you’ve concentrated on using the Cordova CLI to translate web stuff (HTML, JavaScript, and CSS) to native code. You’ve seen how to create a Cordova project and how to test it as a native application on either an emulator or a real device. The last piece of the puzzle is tapping into the rich set of device features that websites do not have access to: the filesystem, the camera, and so on. This was mentioned in chapter 3 as a problem with your simple application. This is where plugins enter the picture.
Suppose you want to write a Cordova application to access your phone’s camera and take a picture. JavaScript, by itself, doesn’t have access to the camera. One of the great features of Cordova is that it provides a mechanism to allow JavaScript to access things it normally wouldn’t be able to. This is done via plugins.
Plugins work by providing a way for your JavaScript to communicate to the device. Figure 4.1 illustrates this.
Plugins are code written in native languages (Objective-C, Java, and so forth) that provide a hook that can be called by a JavaScript file loaded by your Cordova application. They allow your JavaScript code to do things it wouldn’t normally be able to do. There’s no camera.getPicture() function available to mobile browsers, but by using plugins, Cordova provides support for doing just such a thing. The Cordova version (and you’ll see a full example later in this chapter) looks like so: navigator.camera.getPicture(). This only works because the plugin behind the camera support adds this functionality.
For a plugin to work across multiple platforms, multiple versions of the plugin are built. Taking the Camera plugin feature as an example, someone must create native code for Android, Windows Phone, iOS, and other platforms that can access the device camera. Once that’s done, one JavaScript API can be used so your code will work the same (or close enough) on all those platforms. Luckily there are quite a few plugins available for you to use in your Cordova projects.
Before we get into using plugins in your Cordova project, let’s discuss how you find them. While you can write your own plugins (to be discussed in chapter 8), most people find their plugins online. You used the command line npm to install Cordova; as mentioned previously, npm is a tool often used to install other programs. Cordova plugins are now (a very recent change) stored at www.npmjs.com so you can search for them there. At the time this chapter was written, there were nearly 150,000 npm packages available, but you can search for Cordova plugins using ecosystem:cordova in the search box. Or simply bookmark www.npmjs.com/browse/keyword/ecosystem:cordova. The search results are shown in figure 4.2.
Note that this search returns plugins and related Cordova assets. For example, cordova-app-hello-world is the source for the www folder in new Cordova projects. Providing a way to search for only plugins is something that’s currently being worked on.
You probably won’t have any trouble finding a plugin for common needs. What’s more difficult is evaluating which plugin makes the most sense for your project. Given that you can find a plugin to support some particular need, how do you handle figuring out if the plugin is well written? Or what do you do when multiple options exist? In general, the same types of checks you should make for any open source project will apply here as well.
For the most part, we’ll be focused on the core plugins that are maintained by the Apache Cordova project. Technically every plugin is just as usable as any other, but there is a set of plugins maintained by the Apache Cordova team that is kept up to date and tested on the platforms supported by Cordova. These plugins once were part of the core Cordova framework itself, but in version 3, every feature was converted into a plugin. This was done so that developers didn’t have to ship code for a feature they weren’t using. The core plugins are:
We’ll discuss those cordova-plugin values in a bit.
You can also browse plugins at Telerik’s Verified Plugins Marketplace (http://plugins.telerik.com/). Telerik constantly updates this list to ensure the listed plugins actually work and are well maintained.
Now that you know what plugins do and where to find them, how do you get them into your project? The Cordova CLI provides a method to add new plugins, remove existing plugins, list what’s installed, and search against the main registry. The simplest action to take is to list the current plugins for a project. Navigate to any existing project, and simply type cordova plugin. This will output a list of plugins that for you will most likely be blank. Note that you can use the alias plugins instead of plugin. Either works just fine.
Adding a plugin is done via the cordova plugin add command. There are a couple of different options you have in terms of from where the plugin will be loaded, but for the purposes of this book you’ll use the pluginid value—that is, the cordova-plugin values you saw in the list of core plugins. The command diagram at right demonstrates this.
The result of this command can be seen in figure 4.3. In the figure, pay particular attention to the last line. For this project, the only installed platform was for iOS. Basically, the Cordova CLI grabbed the plugin and then prepared it for the platforms your project supports. The CLI is intelligent enough to know that if you decide to add Android, it needs to install the Camera plugin, as demonstrated in figure 4.4.
Removing a plugin is simply a matter of using cordova remove and the ID of the plugin you want to remove. As before, the CLI is intelligent enough to know what platforms you’ve installed for a project and will correctly remove the plugin from each, as shown in the command diagram at right.
The search option is useful if you can’t remember the name of a plugin. The CLI searches against the website (http://plugins.cordova.io) and returns the results at your command prompt. Figure 4.5 demonstrates the result of searching for “camera.”
Once you’ve installed a plugin, you can begin using it in your code. How you use a plugin will depend on what it does. Each plugin has its own API and documentation. Later in the chapter we’ll go over a few example plugins so you can see them in action. Just remember that every plugin is unique. Be sure to carefully read its documentation to know how to correctly use it.
In chapter 3 we outlined the development cycle for a typical Cordova project. How does working with plugins change this? Not much! Figure 4.6 demonstrates the updated process.
As you can see, we’ve simply added a new step (add plugins) to the flow. You can add plugins late in the development process (perhaps the client changes the requirements right before release, something that never happens, right?). But typically, much like with platforms, you’ll set up your plugins at the beginning of your project.
You’ve seen how to find plugins. You’ve read about how to perform due diligence and judge the health of a plugin. You’ve seen how easy it is to use the CLI to install, list, and remove plugins from your project. Most likely you’re excited to jump into development and start doing cool things with the camera and other device features.
First, there’s a critically important aspect of Cordova development that you need to learn. Before your application can talk to a plugin, Cordova has to set up a line of communication between your code and the device. That sounds complex, but it really isn’t. Basically, Cordova knows what it has to do on each supported platform to let plugin code access device hardware. All you have to do is wait for Cordova to finish. So how do you know when this has happened? All Cordova applications will fire an event called deviceready which can be listened to in your JavaScript code. So why did the real (but simple) application in chapter 3 work? Because you weren’t doing anything special. Listening to events in JavaScript is fairly simple.
At the most simple level, the DOM method addEventListener() is what you’d use to create a listener for an event. If you use jQuery, you’d use the on API. The following listing demonstrates this.
Pretty much every single Cordova application will make use of the preceding code block. The name of the function that will be run, init in the listing, is completely up to you, but should be named something obvious. If you do any jQuery work you may be familiar with using $(document).ready as a way of delaying your code until the DOM is ready. For the most part you can mentally exchange that with the deviceready handler and use it in much the same way.
For our first example of a plugin we’ll look at the Cordova Dialogs plugin. It provides native dialogs and audio notifications to your Cordova application and is a big improvement over what JavaScript provides by default. After I demonstrate how to use the plugin and why it’s better than the default JavaScript method, you’ll use it in a sample application.
JavaScript has long had a way to create dialog, or modal, windows. While these methods work, they tend to be avoided as they cannot be styled and can be overly obtrusive. When used in a mobile browser they can be even more obtrusive. In figure 4.7, a Cordova application is using the alert() method to display a message to the user.
Notice that the dialog has a title on top, index.html. This cannot be changed or modified and immediately flags your application as being a web page. The OK button cannot be changed either. Now compare the same (well, a similar) use of the Dialogs plugin’s alert() method in figure 4.8.
By switching to the Dialogs plugin, you have a much nicer dialog. You can customize the title as well as the button. You cannot control things like color and fonts, but you can still create a much better-looking dialog with minimal effort.
Dialogs are used to alert the user about something important happening in your application. What that important event is doesn’t necessarily matter, but the idea is that you want to get the user’s attention. For this first example you’ll create an application that lets you test all of the methods of the Dialogs plugin:
Beeps are—obviously—not a dialog but an auditory alert; but as they’re pretty simple to use we’ll demonstrate them as well. Your final application, as shown in figure 4.9, will provide a set of buttons to test each aspect of the plugin.
Each of the buttons tests one aspect of the plugin and is labeled appropriately. To create this application, you can follow the same procedure you did in chapter 3. If you extracted the book’s zip file to /Users/mary/Downloads/cordovabook, you can create a new Cordova project and seed it with the code for this example like so:
cordova create notificationdemo --copy-from=/Users/mary/Downloads/ cordovabook/c4/dialog_demo
Don’t forget that before you can make use of a plugin, you need to install it. In the new project you created, run the following command:
cordova plugin add cordova-plugin-dialogs
You can also create a new project and then modify the code to match the code displayed next. Let’s begin by looking at the index.html file shown in the following listing.
For the most part there isn’t much to talk about here. The application is rather simple—four buttons and nothing more—so the HTML part of the project is only a few lines long. This example calls out to an application-specific CSS file and a JavaScript file . You may be curious about the line that loads cordova.js . If you look at your project folder, this file doesn’t actually exist because this JavaScript file is injected by the Cordova CLI itself when you create a platform-specific build. So when you tell it to create an iOS build, for example, an iOS version of the cordova.js file will be copied along with everything else you write. If you have an Android version, the same thing happens but an Android-specific version is used instead. As a Cordova developer, you don’t have to worry about providing the file, but you must include a <script> tag loading it so your project can function correctly.
Let’s look at the CSS file shown in listing 4.3. Note the use of app.css and app.js in this application just because it makes it obvious that these files are application-specific and not part of some third-party library. There’s nothing special about “app” being used in the name. It’s nothing more than a convention.
body { margin: 20px; } button { padding: 10px; width: 100%; font-size: 1em; }
That’s it. Only a few lines to add a margin around the body and make the buttons a bit easier to see on a mobile screen. In later chapters we’ll look at how to make this better. Now let’s look at the final part of the project, the JavaScript file, shown in the following listing.
The more important aspect of this JavaScript file is the initial event listener for deviceready. As noted earlier in the chapter, before you do anything with device features you must listen for this event. Therefore, the majority of the code for this application is nestled inside that function. The Dialogs plugin is documented at www.npmjs.com/package/cordova-plugin-dialogs, and the code simply demonstrates an example of each of the four methods supported by the plugin.
The alert() method allows for customization of the body (first argument) and title (third argument), as well as the button (fourth argument). The second argument, which is specified as null, is a callback function to run after the alert is dismissed. If you wanted your application to do anything at that point you could define it there. Figure 4.10 demonstrates the result.
The confirm() method works similarly to the alert() method. Note though that you can actually specify multiple buttons instead of a default set of two. For the confirm() method example you want to display what the user clicked so you use the callback to alert it, as shown in figure 4.11.
The prompt() method is also pretty similar to the last two—you provide a default prompt, a callback, the title of the dialog, a set of buttons, and an optional default. The callback is a bit more complex. It’s passed a result object that contains a key for the input (input1) and the index of the button selected (buttonIndex). For your application you alert back what the user entered, as shown in figure 4.12.
The most simple method of the plugin is beep(). You simply pass in the number of beeps to make; the sound will be based on the user’s default notification sound. Please use this method with caution and resist the urge to pass an incredibly large number to it. In case you’re curious, you can do both a beep and an alert at the same time to get the user’s attention:
navigator.notification.beep(2); navigator.notification.alert( "Wake up! ", null, "Alert Test", "OK! ");
If you click the buttons and nothing happens, most likely you forgot to include the plugin as instructed earlier. Figuring out mistakes like this will be covered in chapter 8 when we cover debugging techniques.
Now that you’ve seen the power of a simple plugin in action, let’s kick it up a notch and talk about one of the more popular plugins, Camera. From Instagram to Facebook, users love taking pictures. The Camera plugin lets you prompt the user to take a new picture or select from the gallery. It has multiple options for where the image ends up and lets you control the size of the picture returned to your application. At the most simple level you can prompt the user to take a picture and then render that picture in your application. More advanced applications can use these pictures by uploading them to other services and manipulating them.
This demo provides buttons to prompt the user to either take a new picture or select one from the device, as shown in figure 4.13.
Once the user has selected an image, it will be displayed in the application and styled a bit, like figure 4.14.
Now let’s look at the code. Don’t forget to actually create the new project. As before, you can use the CLI’s --copy-from feature to point to the code you downloaded for the book. For this application to work correctly in your emulator, or device, you’ll need to install not one but two plugins:
cordova plugin add cordova-plugin-camera cordova plugin add cordova-plugin-dialogs
Using multiple plugins is a perfectly normal part of Cordova development and it will not be unusual for your application to use many of them.
Let’s begin by looking at the HTML for the application, shown in the following listing.
As before, because the application is so simple, the HTML doesn’t have much to it. For the most part it comes down to the two buttons (, ) used to prompt the user to take or select a picture. The empty image will be used to display what the user takes or selects. The CSS file shown in the following listing is similar to the previous application with the addition of a new style for the image.
The sepia filter is used to colorize the selected image. You can think of it as an Instagram filter done simple. Now review the JavaScript in the following listing.
Once again the code begins with an event listener for deviceready , a consistent technique for your Cordova applications. Both buttons (shown in figures 4.13 and 4.14) make use of touch events to listen for user action. Both make use of the core Camera plugin functionality to get pictures, navigator.camera.getPicture. The only difference in the two calls (, ) are the options. The first button that’s requesting a new picture uses a source of Camera.PictureSourceType.CAMERA. This means a new picture driven by the device camera. The second button uses a source of Camera.PictureSourceType.PHOTOLIBRARY, which represents an existing picture from the device’s photo gallery.
The Camera plugin can send the picture as either Base64 data (a text representation of binary data) or from the location of the picture on the device’s filesystem. In general, using the FILE_URI destination as used here is almost always preferred because it uses less memory then the Base64 version. (This is discussed on the plugin’s documentation page.) Once the camera action is complete, the success handler is run and, because you’re passing in a file URL, you can set that to the blank image created in the HTML page. Note as well the error handler. It’s using the nice dialogs described earlier.
For our final example we’ll work with the Contacts plugin, which (no surprise here) lets you add, edit, and delete contacts. That’s handy. A more typical use for contacts is to find a contact to be used in some other action. Imagine you’ve made use of the Camera plugin. Because you’ve just taken what is obviously the best picture of a cat ever, it would be even cooler if you could share that picture with a friend. The Contacts plugin would make it easy to let you find that friend and fetch their email address, or phone number, so that your friend too can bask in the awesomeness of your cat photo.
While the plugin provides a find() method for low-level searching, it has a better method of asking the user to select a contact. The plugin can ask the device to use its default Contact Picker UI that’s shared among other native applications. This provides a familiar user experience to the person working with your application. By using the navigator.contacts.pickContact() method as provided by the plugin, you can display the appropriate UI for the device’s OS, as shown in figure 4.15.
The application will make use of this API to simply prompt the user to select a contact. After a contact is selected, information about the contact will be displayed in the application, as shown in figure 4.16.
In doing so though, you’ll discover one of the issues you run into from time to time with plugins: platform quirks.
The documentation for the Contacts plugin (www.npmjs.com/package/cordova-plugin-contacts) discusses how the plugin works and points out oddities or quirks for an individual plugin. While all plugins strive to work exactly the same across their supported platforms, sometimes this is not possible.
While most developers know it’s important to read the documentation, most of us probably don’t do a great job of it. I recommend paying attention to the quirks when using any plugin. Many times I’ve lost time to debugging something that ended up being a quirk that I simply didn’t pay attention to.
For the Contacts plugin there’s one quirk in particular that’s going to impact the sample application. The docs say this:
displayName: Not supported on iOS, returning null unless there is no ContactName specified, in which case it returns the composite name, nickname, or “ ”, respectively.
Interesting. So if the application is going to display a contact, it will need to be prepared to handle running under iOS and not having access to that particular property.
I know you didn’t forget to create a new project and add the plugins, right? This project makes use of both the Contacts plugin (cordova-plugin-contacts) and Dialogs plugin (cordova-plugin-dialogs).
Let’s look at the code. The first template is the index.html file for the application shown in the following listing.
As with the other examples, the HTML is rather simple. You’ve got one button you’ll use to fire off the Contacts plugin and an empty div that will be filled with details from the selected contact .
Now let’s look at the JavaScript code for the application shown in the following listing.
As in the previous examples, the code begins with a listener for deviceready. By now this should be familiar territory. The plugin API, navigator.contacts.pickContact , only takes two arguments: a success callback and a failure callback. The success callback is passed an instance of a Contact object, a basic representation of a particular contact. The documentation fully covers all the keys but for the purposes here, only a few are displayed. Note that some properties are arrays and can be iterated over. Make note of how to handle the iOS issue mentioned earlier. The getName() function will check to see if displayName() is null and, if so, try to find an appropriate value elsewhere. If all else fails it will return Nameless.
In the previous chapter, we discussed a few problems with the sample application you created. It didn’t make use of any native features. In this chapter you’ve seen how easy it is to make use of those features using plugins. We also demonstrated how the application wasn’t necessarily designed well for the mobile environment. The next chapter will cover this.
Let’s review the major topics covered in this chapter.
In the next chapter we’ll cover how to design applications for the mobile environment.
34.231.180.210