You don't need to use platform-specific technologies to develop powerful and engaging apps. This series will teach you how to create a hybrid app - specifically an audio player - using web technologies and frameworks like jQuery Mobile and Cordova (also known as PhoneGap). The first framework will be used to create the interface, while several of the APIs of the second, like Media and File, will be used to develop the business logic.
Series Overview
The Project Features
The app we'll start developing in a few moments will be a basic audio player called Audero Audio Player. It will have minimal utility requirements. This app will search through the file system and collect any audio files, which the user can then listen to. The app will collect files with any of the following extensions: .mp3, .wav, .m4a. Keep in mind that the formats supported depend heavily upon the platform from which you run the application, so choose formats that work in many platforms.
Audero Audio Player also enables the user to update the list at any time to include other files that they may have downloaded after running the operation for the first time. The user can also remove any unwanted audio from the list by clicking the icon on the right side of the audio's name. The list is ordered alphabetically with letter dividers to organize and group list items. The list has a search box to filter the files as well.
You can see the described page by looking at the screenshot below:
Once the user chooses a file, the player's controller will then be shown. The controller shows the file name, location path, playing time and duration. It includes buttons for play/pause, stop, and a slider to move the audio back and forth.
You can see the look and feel of the player in the photo below:
Technologies Involved
The following list will give you a detailed understanding of what we'll be utilizing:
- HTML: It will be used to create the markup of the pages. When appropriate, I will use some of the new HTML5 tags.
- CSS: Most of the CSS enhancements will be done by jQuery Mobile, so I will only be using a few lines of custom CSS code. It's mainly used for the player itself.
- JavaScript: This is the language I will use to develop the business logic.
- jQuery: I will use jQuery mainly to select elements and attach event handlers.
- jQuery Mobile: It will be used to enhance the application interface and optimize it for mobile devices. Some of the widgets used include Listview, Dialog, and Slider. I will also put some buttons inside the header and footer of the pages to build a simple toolbar. The version used is 1.3.0.
- Cordova (PhoneGap): Cordova will be used to wrap the files so you can compile them as if you built a native app. To build Audero Audio Player we'll take advantage of several of the APIs offered by the framework, such as Storage, InAppBrowser, Notification, File and Media. The version used is 2.3.0.
In addition to the above list, I'll use also these Cordova APIs:
-
File API: An
API to read, write and navigate file system hierarchies, it
provides a set of objects to work with files and directories. For example, we'll use theDirectoryReader
object to navigate the file system, using its methodreadEntries()
, and search the sounds. We'll also use theLocalFileSystem
object to obtain the root file systems of the device using itsrequestFileSystem()
method. You can find more information in the File API official doc. -
InAppBrowser API: It's
a web-browser shown in your app when you use the
. It isn't much more than that but, as you'll discover later in this article, managing external links properly with this API is of vital importance. If you want to read more about the methods offered by this API, you can take a look at the InAppBrowser official doc.window.open
call - Storage API: This API provides access to the device's storage options. We'll specifically be using the Cordova implementation of the Web Storage API and its methods to store and load the list of the audio files. In case you need an in-depth explanation, refer to the Local Storage API doc.
-
Media API:
The Media object provides the ability to record and play back audio files on a device.
This is a key API for our player and we'll use almost all of its methods. For example, we'll use theplay()
method to play the sounds, thestop()
method to stop playing the audio, and thegetDuration()
method to retrieve the duration of the current processed file. More on this topic can be found in the Media API docs. -
Notification API: It allows you to notify the user with visual and audible notifications. We'll use its
alert()
method to notify the user in case of errors. For a more in-depth overview on this API, read the Notification API docs.
Before continuing our tutorial, I want to emphasize that Cordova uses a different JavaScript file for every operating system. Therefore, if you want to compile the application on your own, you will need to use a specific IDE-SDK bundle. For example, if you want to create the Android version of our player (thus creating the relative .apk), you should use Eclipse and the Android SDK. Using different bundles for each platform can be problematic, so Audero Audio Player will be developed with the assumption that the compilation will be done using the Adobe cloud service, called Adobe PhoneGap Build. This service will include the correct Cordova library for each platform at compilation time.
The Project's Structure
The structure of the project will be quite straightforward. To start building the player, create a folder and rename it "audero-audio-player". Now, create three folders inside this folder with the following names: css, images, and js. Once you've done this, download the jQuery (I'll use version 1.8.3) and jQuery Mobile (version 1.3.0) libraries. Move the jQuery and the JavaScript file of jQuery Mobile inside the "js" folder, and then put the jQuery Mobile CSS file into the "css" folder. Finally, place the jQuery Mobile bundled images into the "images" folder. Because we've slightly changed the native structure of jQuery Mobile, we need to adjust the paths pointing to the images inside its CSS file. Specifically, we need to replace the "images/" part with this string "../images/". If you're using an automated feature of your chosen editor, check that it replaced the string five times.
Now that you have set up the framework, you can proceed to the next step. In the root of the project folder, we'll create the HTML files, and place the default application's icon, the Adobe PhoneGap Build configuration file, and the default splash screen. In this tutorial we'll also create the following files:
-
index.html: This is the entry point of the application and where we will put the links to the libraries used, inside the
<head>
section. - files-list.html: This is the page where you'll have a list of the sounds stored on your device, grouped as I explained back in the introduction of this article. As you'll see later, you'll also have a little toolbar that allows you to go back to the homepage (the button in the upper-left corner) and to refresh the sounds list (the button in the upper-right corner).
- player.html: This simply contains the markup of the audio player.
- aurelio.html: This is the app credits page; it contains information about the app's author.
- style.css: This file contains the few custom lines of CSS used by the app, which are mainly used to style the player buttons.
- jquery.mobile.config.js: This will contain our custom configuration for the jQuery Mobile framework.
-
appFile.js: This file contains the class called
AppFile
that we'll use to manage the sounds. It acts as an interface for the files table of our database. This class also allows us to retrieve and edit audio information in addition to allowing us to add and delete files from the stored list. -
player.js: The file including the class, called
Player
, that manages the player and resets the player interface. - utility.js: This is just a couple of utility functions used by our project, which I'll explain further in the next article of the series.
- application.js: This is like a glue that merges all of the pieces of our project together. This class is responsible for initializing the behavior of the pages described before attaching events using the classes seen thus far.
- config.xml: This XML file will have the metadata of the application and will be used by the Adobe cloud service to store settings like the app version number and its description.
This is a lot of stuff to create, but I promise you'll have a good time with this project. As a final note, in addition to the listed files, Audero Audio Player will include some additional images - like the play/pause and stop buttons - that will be placed in the "images" folder.
The Homepage
jQuery Mobile will load all of the pages using AJAX, so unless you build explicit custom configurations, all the files needed by Audero Audio Player, such as the CSS and JavaScript files, must be loaded by the entry point, index.html
. This page, apart from being the application's title and description, has a button to access the sounds list. It also includes a footer with a button to access author info.
The full source of the homepage is shown below:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Audero Audio Player</title> <link rel="stylesheet" href="css/jquery.mobile-1.3.0.min.css" type="text/css" media="all" /> <link rel="stylesheet" href="css/style.css" type="text/css" media="all" /> <script src="js/jquery-1.8.3.min.js"></script> <script src="js/jquery.mobile.config.js"></script> <script src="js/jquery.mobile-1.3.0.min.js"></script> <script src="cordova.js"></script> <script src="js/appFile.js"></script> <script src="js/application.js"></script> <script src="js/utility.js"></script> <script src="js/player.js"></script> <script> $(document).on('pagebeforecreate orientationchange', Application.updateIcons); $(document).one('deviceready', Application.initApplication); </script> </head> <body> <div id="home-page" data-role="page"> <header data-role="header"> <h1>Audero Audio Player</h1> </header> <div data-role="content"> <p id="app-description"> Audero Audio Player is a basic audio player that searches the file system of a device, collects the audio files found and then allows the user to listen them. This app also enables the user to update the list at any time to include files that might have been downloaded after running the operation for the first time. You can also remove any unwanted audio - for example, sounds used as notifications in other applications - by clicking an icon on the right side of the song name. The sound list is ordered alphabetically with letter dividers to organize and group list items, and it has a search box to filter files. You can see the described page by looking at the screenshot below. </p> <a href="files-list.html" data-role="button">File List</a> </div> <footer data-role="footer"> <h3 id="copyright-title">Created by Aurelio De Rosa</h3> <a id="credits-button" href="aurelio.html" data-icon="info" data-iconpos="notext" class="ui-btn-right">Credits</a> </footer> </div> </body> </html>
As you'll see in the next section, the buttons inside the <header>
and the <footer>
tags, use the attribute data-iconpos="notext"
. This attribute is very important for achieving the effect I want: a responsive layout. The cited attribute tells jQuery Mobile to hide the link text, which is very useful in saving space for smaller screens. In the next section, I will demonstrate how to attach a handler to the pagebeforecreate
and the orientationchange
events so that we can test for the screen size. If a large enough screen is found, the attribute will be removed and the text will be shown. In this case, "large enough" means the screen's width is larger than 480 pixels.
Observant readers may also have noticed the two JavaScript lines just above the <body>
. Disregard this for the moment; we'll delve into their meaning later.
This screenshot will give you an example of what the page will look like:
The List Page
This small page, called files-list.html
, has a couple of interesting widgets like the autodivider and the search box. Those widgets are created for you by jQuery Mobile simply by adding a couple of attributes to the <ul id="files-list">
tag: data-autodividers="true"
and data-filter="true"
. You have already seen how this page appears in a previous section, and you should have noted that each list item has a big "X" on the right side. This is the button that allows the user to delete the file from the list and the database. These two items are a standard effect achieved using jQuery Mobile. You can read more about them by looking at the official documentation page.
The last piece of code worth discussing is the <div id="waiting-popup">
element. This is shown when the code digs into the operating system's folders to search for sounds. Searching audio is quite a heavy operation and even my device (a Galaxy S3) suffered, blocking the entire software. A better solution for this problem would be to use multi-threading. This way, while the app searches for files, the user can still play around. Unfortunately, as you may know, JavaScript doesn't have multi-threading capabilities, and there is nothing you can do to change that. Another solution might be showing the loader during this process, but this approach also failed; it completely froze. For this reason, I chose to block user interaction completely with a dialogue that can only be closed with programming.
Now that you are fully aware of this page's key points, I can list the full source:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <div id="files-list-page" data-role="page"> <header data-role="header"> <a href="#" data-icon="back" data-iconpos="notext" data-rel="back" title="Go back">Back</a> <h1>Media List</h1> <a href="#" id="update-button" data-icon="refresh" data-iconpos="notext">Update List</a> </header> <div data-role="content"> <ul id="files-list" data-role="listview" data-autodividers="true" data-filter="true" data-split-icon="delete"> </ul> </div> <footer data-role="footer"> <h3 id="copyright-title">Created by Aurelio De Rosa</h3> <a id="credits-button" href="aurelio.html" data-icon="info" data-iconpos="notext" class="ui-btn-right">Credits</a> </footer> <div id="waiting-popup" data-role="popup" data-position-to="window" data-dismissible="false"> <header data-role="header"> <h1>Updating</h1> </header> <div data-role="content"> <p>Searching audio files, please wait...</p> </div> </div> </div> </body> </html>
The Player Page
The player page (player.html
) doesn't have many exciting facts to point out. It's a set of labels and links with events attached to manage the sound. The only element worth mentioning is the slider used to move the audio forward and backward, created using the jQuery Mobile slider widget.
You can see the code of the page below:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <div id="player-page" data-role="page"> <header data-role="header"> <a href="#" data-icon="back" data-iconpos="notext" data-rel="back" title="Go back">Back</a> <h1>Player</h1> </header> <div data-role="content"> <div id="player"> <div id="media-info"> <p>You're listening to: <span id="media-name"></span></p> <p>Located at: <span id="media-path"></span></p> <div> Played: <label id="media-played">-</label> of <label id="media-duration">-</label> <input type="range" name="time-slider" id="time-slider" value="0" min="0" max="100" data-highlight="true" /> </div> </div> <a href="#" id="player-play" title="Play / Pause"></a> <a href="#" id="player-stop" title="Stop"></a> </div> </div> <footer data-role="footer"> <h3 id="copyright-title">Created by Aurelio De Rosa</h3> <a id="credits-button" href="aurelio.html" data-icon="info" data-iconpos="notext" class="ui-btn-right">Credits</a> </footer> </div> </body> </html>
The Credits Page
The page aurelio.html
is surely the least important one, and it's also very simple. Nonetheless I want to mention two things. The first is the use of two new HTML5 tags, <figure>
and <article>
. The <figure>
element represents a unit of content, with an optional caption that is self-contained.
The caption described is provided using the element <figcaption>
. The <article>
element represents a component of a page that consists of a self-contained composition in a document, page, application, or site.
The second is the use of the attribute target="_blank"
which is applied to all of the contact listing links on the page. This attribute is very common. However, in our player, we'll use it to attach a handler to all of the external links, as you'll learn in the next part of this series.
The whole code of aurelio.html
is shown below:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Aurelio De Rosa</title> </head> <body> <div id="aurelio-page" data-role="page"> <header data-role="header"> <a href="#" data-icon="back" data-iconpos="notext" data-rel="back" title="Go back">Back</a> <h1>Aurelio De Rosa</h1> </header> <div id="content" data-role="content"> <div class="person"> <figure class="photo"> <img src="images/aurelio-de-rosa.png" alt="Photo of Aurelio De Rosa" /> <figcaption>Aurelio De Rosa</figcaption> </figure> <article> <p> I am an Italian web and app developer with a Bachelor's degree in Computer Sciences and more than 5 years' programming experience using HTML5, CSS3, JavaScript and PHP. I mainly use the LAMP stack and frameworks like jQuery, jQuery Mobile, Cordova (PhoneGap) and Zend Framework. My interests include web security, web accessibility, SEO and WordPress. </p> <p> I'm currently self-employed, working with the cited technologies, and I'm also a contributor to the SitePoint and Tuts+ network where I write articles pertaining to the topics I work with. </p> </article> <article> <h2>Contacts</h2> <ul data-role="listview" data-inset="true"> <li> <a href="http://www.audero.it" target="_blank"> <img src="images/website-icon.png" alt="Website icon" /> Visit my website: www.audero.it </a> </li> <li> <a href="mailto:[email protected]" target="_blank"> <img src="images/email-icon.png" alt="Email icon" /> Drop me an e-mail: [email protected] </a> </li> <li> <a href="mailto:[email protected]" target="_blank"> <img src="images/email-icon.png" alt="Email icon" /> Drop me an e-mail (alternative address): [email protected] </a> </li> <li> <a href="https://twitter.com/AurelioDeRosa" target="_blank"> <img src="images/twitter-icon.png" alt="Twitter icon" /> Follow me on Twitter (@AurelioDeRosa) </a> </li> <li> <a href="http://it.linkedin.com/in/aurelioderosa/en" target="_blank"> <img src="images/linkedin-icon.png" alt="LinkedIn icon" /> View my profile on LinkedIn </a> </li> <li> <a href="https://bitbucket.org/AurelioDeRosa" target="_blank"> <img src="images/bitbucket-icon.png" alt="BitBucket icon" /> Visit my repository on BitBucket (AurelioDeRosa) </a> </li> </ul> </article> </div> </div> </div> </body> </html>
Next Part
In the second installment of this series, we'll take an in-depth look at the app's business logic by looking at the JavaScript files that power our player.
Comments