Tutorial: Building a packaged app

Overview

This tutorial will take you step-by-step through the process of creating and installing a packaged app, which you could then publish in the Chrome Web Store. The app is a simple, customizable clock, and it will implement some HTML5 features, including local storage, requestAnimationFrame, web fonts, and CSS3 transforms, transitions, and gradients. We'll also internationalize the app to make it easier for it to be localized later. Download clock_files.zip, which has the directory structure and empty files to which we'll add content during the tutorial. Extract the contents, and you should see a clock directory with a couple files and some other subdirectories.

The manifest file

To get started, we'll create a manifest file, which for now just specifies the app's name, a short description, the default locale, the URL to launch, and the version number of the app.

In the clock directory, open manifest.json and add the following code:

{
  "name": "BootCamp Clock",
  "version": "1.0",
  "description": "A simple, customizable clock",
  "default_locale": "en",
  "app": {
    "launch": {
      "local_path": "clock.html"
    }
  }
}
Next, open clock.html from the clock directory and add this code:
<!DOCTYPE html>
<html>
<head>
  <title>BootCamp Clock</title>
</head>
<body>
The clock display will go here!
</body>
</html>


Open chrome://extensions, make sure the icon next to "Developer mode" is a "-", not a "+", and then click "Load unpacked extension". Select the "clock" directory to load your app. To test it, open a new tab, click the app to launch it, and you should see the "The clock display will go here!" message.

Adding app icons

All the icons you'll need for the app are located in the clock/images directory. Open manifest.json and add this icons section to the file.

{
  "name": "BootCamp Clock",
  "version": "1.0",
  "description": "A simple, customizable clock",
  "default_locale": "en",

  "icons": { "16": "images/clock16.png", "128": "images/clock128.png"   },
  "app": {
"launch": { "local_path": "clock.html" } } }
In chrome://extensions, click on the "Reload" link below your app. Now you should see the clock icon on the new tab page.

Telling time

Now that our app has nice icons, it's time to actually turn it into a clock.
First, we'll add some code to clock.html. We'll add two lines in the <head> section for JavaScript files we need to include. We'll include the jQuery library and clock.js, which will contain the code we're writing ourselves.
In the <body> section, we'll add a div that will be used to display the time on the clock.
<!DOCTYPE html>
<html>
<head>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
  <script src="scripts/clock.js"></script>

  <title>BootCamp Clock</title>
</head>
<body>
  <div id="clockData"></div>
</body>
</html>

In the clock/scripts directory, open clock.js and add the following code:

// requestAnim shim layer by Paul Irish
window.requestAnimFrame = (function(){
  return  window.requestAnimationFrame       || 
          window.webkitRequestAnimationFrame || 
          window.mozRequestAnimationFrame    || 
          window.oRequestAnimationFrame      || 
          window.msRequestAnimationFrame     || 
          function(/* function */ callback, /* DOMElement */ element){
            window.setTimeout(callback, 1000 / 60);
          };
})();

$(document).ready(function() {
  initializeClock();
  updateClock();
});

function buildTimeString() {
  var d = new Date();
  var hours = d.getHours();
  var minutes = d.getMinutes();
  var seconds = d.getSeconds();

  // For nice formatting, we want to add '0' before single digit hours,
  // minutes, and seconds
  hours < 10 ? hours = "0" + hours : hours;
  minutes < 10 ? minutes = "0" + minutes : minutes;
  seconds < 10 ? seconds = "0" + seconds : seconds;

  return hours + ":" + minutes + ":" + seconds; 
}

function initializeClock() {
  $("#clockData").html(buildTimeString());
}

function updateClock() {
  requestAnimFrame( updateClock );
  $("#clockData").html(buildTimeString());
}

Go to the app's entry in chrome://extensions and click the "Reload" link and launch your app again. You should now have a working clock, although it's not much to look at. In the next section we'll start making it look a bit nicer.

Adding some basic styling

The clock looks very plain right now, so next we'll center the time on the page, add a gradient background, and make the text a bit easier to read.
In the clock/css directory, open clock.css and add the following code:

html {
  height: 100%;
}
body {
  margin: 0;
  font-family: sans-serif;
  color: #fff;
  background: -webkit-gradient(linear, 
     		               left top,
			       right top,
			       color-stop(0, rgba(0,0,0,1)), 
                               color-stop(0.5, rgba(0,0,0,.8)),
			       color-stop(1, rgba(0,0,0,1)));
  background-repeat: no-repeat;
  overflow: hidden;
  height: 100%;
}
#clockData  
{
  text-align: center;
  font-size: 128pt;
  position:relative;
  top:0px;
}
.centered {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-box-pack: center;
  -webkit-box-align: center;
  display: box;
  box-orient: vertical;
  box-pack: center;
  box-align: center;
}
We're using the "centered" class to center our clock display vertically and horizontally on the screen. To do this, we're using the flexible box model. When you specify "box" for the
display property, you're opting that element and its immediate children into the flexible box model. The box-orient property determines how the box's children should be aligned.
The box-pack property sets the alignment of the box along the box-orient axis. So in our case, box-orient is vertical and box-pack is center, so the box's children will be centered along the
vertical axis.
The box-align property is kind of the opposite. It sets how the box's children are aligned within the box. So since box-orient is vertical, and box-align is center, the box's children will be
centered horizontally in the box.
Next go to clock.html and add a link to the css file in the head section, followed by adding class="centered" to both the body element and the clockData div.
<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" type="text/css" href="css/clock.css" />
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
  <script src="scripts/clock.js"></script>
  <title>BootCamp Clock</title>
</head>
<body class="centered">
  <div id="clockData" class="centered"></div>
</body>
</html>
Reload and relaunch the app, and you should see a gradient background that's black at the edges and lighter gray in the center, and the clock time is now displayed centered, in a larger font.

Adding a slide-away area for settings using CSS tranforms and transitions

Before we actually add the ability to customize the clock, let's add an area for displaying and changing the settings. 
To keep things simple, we're going to make the settings live in a div within the clock.html page. 
By default, it won't be visible because we'll set the top for the div to be far off the bottom of the page. 
When the user clicks a "Show settings" link, we'll use CSS3 transforms and transitions to slide the settings section into view.

First, open clock.html and add three new divs below the clockData div: <!DOCTYPE html> ... <body class="centered"> <div id="clockData" class="centered"></div> <div id="settingsLink" class="centered slidey settings">Show Settings</div> <div id="settingsContainer" class="centered slidey"> <div id="hideSettingsLink" class="settings">Hide Settings</div> </div> </body> </html>

There are a couple new classes introduced here: settings and slidey, and we'll add them to the clock.css file in a minute.
The settings class is used for making the font size of the "Show Settings" and "Hide Settings" text smaller. 
The slidey class is used for specifying the CSS transitions that should occur with the settings link and settings container slide in and out of view.

Open clock.css and add the following code at the bottom:
.settings {
font-size: 10pt;
}
.slidey {
  -webkit-transition:all 1.0s ease-in-out;
  -transition:all 1.0s ease-in-out;
}
Then, between #clockData and .centered, add this code:
#settingsContainer { position:relative; top: 1800px; }

Now we need to tie it together with a little extra code in the clock.js file to tell our app what to do when someone clicks the "Show Settings" or "Hide Settings" text.
Add the highlighted code in $(document).ready: $(document).ready(function() { initializeClock(); updateClock(); $("#settingsLink").click(function() { $("#settingsLink").css("-webkit-transform", "translate(0px, 1800px)"); $("#settingsContainer").css("-webkit-transform", "translate(0px, -1800px)"); }); $("#hideSettingsLink").click(function() { $("#settingsLink").css("-webkit-transform", "translate(0px, 0px)"); $("#settingsContainer").css("-webkit-transform", "translate(0px, 1800px)"); }); });

Reload and relaunch your app and trying clicking the "Show Settings" link.

Customize the clock font using the Google Web Fonts API


The Google Web Fonts API lets you add high-quality web fonts to your web apps. In the settings section of our app, we'll give the user a choice between three of the fonts: Arvo, Cabin Sketch, and Droid Sans Mono.

First, let's add a few lines to clock.css so we can use these fonts and so that our clock uses Arvo by default. At the top of the clock.css file add these lines:

@import url(http://fonts.googleapis.com/css?family=Arvo);
@import url(http://fonts.googleapis.com/css?family=Cabin+Sketch:bold);
@import url(http://fonts.googleapis.com/css?family=Droid+Sans+Mono);

Next, we'll add a select box for the user to choose the font they want to use. We'll save the selected value using localStorage. To get started, add the highlighted code to the settingsContainer div in clock.html:
<div id="settingsContainer" class="centered slidey">
  <div id="fontSetting">
    <label id="fontLabel">Font</label>
    <select id="clockFont" name="clockFont">
      <option value="Arvo" id="fontArvo">Arvo</option>
      <option value="Cabin Sketch" id="fontCabinSketch">Cabin Sketch</option>
      <option value="Droid Sans Mono" id="fontDroidSansMono">Droid Sans Mono</option>
    </select>
  </div>
  <br>
  <div id="hideSettingsLink" class="settings">Hide Settings</div>
</div> 

Next in clock.js we'll add some code to load and save the selected font. First, add the following change handler for the clockFont element in $(document).ready:

$(document).ready(function() {
  ...
  $("#clockFont").change(
    function() {
      
localStorage["clockFont"] = $("select[name='clockFont'] option:selected").val();

      //now we need to re-load the settings so they take effect.
      loadSettings();
  });
 ...
});

Then add a new loadSettings function in clock.js, as shown below:

function loadSettings() {
  if(localStorage["clockFont"]){
    var savedFont = localStorage["clockFont"];        
    $("#clockData").css("font-family", savedFont);
    $("select[name=clockFont] option[value='" + savedFont + "']").attr("selected", true);       
  } else {
    $("#clockData").css("font-family", "Arvo");
  }
}

Finally, add a call to loadSettings() in the initializeClock() function so that any previously saved settings are applied when the app loads.

function initializeClock() {
  $("#clockData").html(buildTimeString());
  loadSettings();
}

Now reload and relaunch the app. You should be able to click "Show Settings" and then change the font by making a choice from the select box. For the purposes of the tutorial, we're only adding this one simple setting, but now you have the framework for adding other settings, like 12 or 24 hour time format, background color, font color, etc.

Internationalizing the app

An internationalized app or extension can be easily localized and adapted to additional languages and regions. By internationalizing our app, we'll make it easier to localize it and publish localized versions when the Chrome Web Store launches in several international markets later this year. To internationalize our app, we need to put all the user-visible strings into a file named messages.json. Then for each locale, you put a messages file in a directory named _locales/localeCode, where localeCode is a code like en for English.

Our manifest.json file already specifies the default_locale field, which is required for internationalized apps, so we don't need to make any changes there.
Next, open messages.json from the clock/_locales/en directory and you'll see that the following code is already there for you:
{
  "app_name": {
    "message": "BootCamp Clock",
    "description": "The name of the app"
  },
  "app_desc": {
    "message": "A simple, customizable clock",
    "description": "The short description of the app"
  },
  "show_settings": {
    "message": "Show Settings",
    "description": "The text for the Show Settings link"
  },
  "hide_settings": {
    "message": "Hide Settings",
    "description": "The text for the Hide Settings link"
  },
  "font_label": {
    "message": "Font",
    "description": "The label for the font select box"
  }
}
Next, open manifest.json so we can replace the strings with references to messages in messages.json. Update the highlighted sections.
{
  "name": "__MSG_app_name__",
  "version": "1.0",
  "description": "__MSG_app_desc__",
  "icons": {
    "16": "images/clock16.png",
    "128": "images/clock128.png"
  },
  "default_locale": "en",
  "app": {
    "launch": {
      "local_path": "clock.html"
    }
  }
}
Now we need to add in some code to set the strings in our HTML file from the messages.json file. Open clock.js and add the highlighted code:
$(document).ready(function() {
  initializeMessages();
  initializeClock();
  updateClock();
...
});

function initializeMessages() {
  // Set the title of the app
  document.title = chrome.i18n.getMessage("app_name");
	
  //Set the text of the Show Settings link
  $("#settingsLink").html(chrome.i18n.getMessage("show_settings"));
	
  //Set the text of the Hide Settings link
  $("#hideSettingsLink").html(chrome.i18n.getMessage("hide_settings"));
	
  //Set the text of the Font label
  $("#fontLabel").html(chrome.i18n.getMessage("font_label"));
}
Reload and relaunch the app. It should look the same as before, but now the strings are being pulled in from the messages.json file. You can confirm this by changing one of the 
strings and reloading and relaunching the app again. Now you have the structure in place to easily localize your app for other locales.

Uploading to the Chrome Web Store and publishing 

The steps for publishing an app in the Chrome Web Store are detailed here in this doc, and the steps we'll take below are mostly the same as what you'll find there.

Step 1: Choose a developer account
Before you upload the app, think about which Google Account you want to use for your developer account. This will be the account that's associated with your app and will also receive any payments you receive from the Chrome Web Store if you have a paid app. In addition, if you want multiple people to be able to administer the app in the Chrome Developer Dashboard, you may want to use a dedicated account rather than your personal account. You can create a new Google Account here.

Step 2: Create a zip file for your app
Browse to the clock directory and make a zip file of all the contents except the other_files directory. You can name it whatever you like, for example clock.zip. For this tutorial, clock.zip should contain:
_locales/en/messages.json
css/clock.css
images/clock16.png
images/clock128.png
scripts/clock.js
clock.html
manifest.json

Step 3: Upload the app
Go to the Chrome Developer Dashboard and sign in using the developer account you chose in Step 1. 
Click the Add new item button. If this is the first time you're uploading an item, you'll need to read and accept the developer agreement at this time before continuing.
Next click Choose file, select your clock.zip file, and then click Upload. If everything is valid in the file, you'll soon be taken to a page that will let you edit the app's listing in the Chrome Web Store.

Step 4: Provide the content for the app's listing page in the Chrome Web Store
There are several sections on the Edit Item page that you'll need to complete before you can publish your app. We'll look at each section now.

Payments
If you wish to charge for your app, using either Chrome Web Store payments or if you use third-party in-app payments, then click the Change payment button to choose the correct option. For this tutorial, we're creating a free app, so you can skip this step.

Locales
In this section, you can choose the markets where you want your app to be listed. At the moment the Chrome Web Store is only available for the US. When the Chrome Web Store launches internationally later this year, you'll be able to publish your app in other markets as well. For this tutorial, we'll just select "United States".

Categories
You can select one or two categories for your app. In the case of the Bootcamp Clock, "Utilities" is probably the most accurate category, so choose that one.

Language
In the select box, choose English.

Description
In the description section, you should include a detailed description of what your app does and why users should install it. We'll just include a short overview of the app. Copy and paste this text into the description text area:
BootCamp Clock is a simple, customizable clock. 

Features:
*Displays the time in 24-hour format
*Offers a choice between three different fonts for the displayed time


Verified website
This field doesn't apply to packaged apps, so we'll skip it. However, for a hosted app, you would need to verify that you own the website via one of several options through Google Webmaster Tools.

OpenID
As we'll cover in the best practices section, if your app requires users to sign in, then you should support OpenID so users can authenticate with their Google Accounts. Since Bootcamp Clock does not require users to sign in, we'll leave the box unchecked.

Google Analytics tracking
Enter your Google Analytics ID here if you have a Google Analytics account. It's recommended to fill this out, since it will give you the ability to track and measure traffic on your app's detail page in the Chrome Web Store.

Links
If you have a website or FAQ page for your app, you can enter those links in this section.

Mature content 
If your app contains content that's not suitable for all ages, you should check this box. Our clock definitely does not contain mature content, so we will not check the box.

Icon
Click the Upload New Image button to upload the clock128.png image that you have in the clock/images directory.

Appearance of header
You can either use the default background for the header or upload your own custom image. For the tutorial, we'll use the header.png file found in the clock/other_files directory.

Upload screenshots
You must upload at least one (but ideally more) screenshot for your app's listing page. Screenshots must be 400x275 pixes or proportionally larger. There are two screenshots that you should have in your clock/other_files directory. Upload screen1.png and screen2.png now. You can also optionally link to a YouTube video or Google Docs presentation if you wish. These can be great ways of giving users a feel for what your app does before they install it.

Promotional images
While it's not required, you're strongly encouraged to provide promotional images for your app. These are the images that would be used if your app is featured in the Chrome Web Store. The detailed requirements for the small and large promotional images are listed here. In the clock/other_files directory, you'll find smallbanner.png and largebanner.png. Upload those files now.


At the bottom of the page you will see five buttons. Click 'Preview changes' to see a preview of what your app's listing page will look like. If you're happy with it, you can publish it to the store by clicking 'Publish changes'. Before you publish your first app, you must pay a one-time $5 developer signup fee. You'll see a reminder in the dashboard until you pay the fee. For more information, including troubleshooting tips, see the Registration article. Once you publish your app, it will be available in the store immediately, and available in search in the store soon afterwards. You can also optionally publish just to a set of test accounts. Learn more about test accounts here.

Best practices, resources, and more ideas

Best practices and recommendations
There are several best practices recommended in the documentation. We'll go over a few now.
  • Design a great app. See this article on Thinking in Web Apps for recommendations.
  • Support lazy registration or passive registration and support OpenID for Google Accounts. You can read more about supporting authenticating with OpenID for Google Accounts in this article.
  • Create a compelling store listing. You can find specific tips here.
  • Don't forget to promote your app! Use your existing social media channels, press releases, etc. Also consider using the Badgemator tool to create and customize a badge that will let existing users of your hosted app know that they can install it from the Chrome Web Store.
  • Internationalize your app. Unless your app has very country-specific content, we recommend you internationalize your app in advance of the Chrome Web Store launching to international markets later this year.
Resources

More ideas
Now that you have a working app, you can expand it and add new features if you'd like. Some ideas:
  • Make it work offline
  • Add additional settings, such as the ability to change the background gradient color or an option to choose between 12- and 24-hour format.
  • Make it a hosted web app and use Chrome Web Store payments.