Docs

Implementation

Background page

The background page is an invisible, always-on page that may be optionally specified in your app’s manifest. It is ideally suited for powering Badge notifications , listening for Context menu events, and caching data that will be used by the window page.

Background pages are loaded after your app is installed, after the computer restarts and after Pokki is manually restarted. If the memory management service finds your background page is using over 200mb of memory it will be unloaded and then re-loaded. This effectively means a background page is always loaded.

Your app can take advantage of the fact the background is always loaded to pre-load and cache data that will be used by the window. In fact more sophisticated apps may find it easier to structure their app by moving all data retrieval and storage logic into their background page and simply using the window as a view and controller. The background and window pages can communicate by using their shared local storage or via remote procedure calls. Please see  Saving data and Communication between pages for more details.

Communication between pages

At times it may be useful for the window and background page to communicate and exchange data. Pokki facilitates this by means of a remote procedure call API and shared local storage (see Saving data ). Because the window page is not always loaded by Pokki, you should keep in mind that the background page cannot rely on its existence. Whereas the window page can rely on the background page’s existence as it is always loaded (well, almost always – see Advanced Example #2 below).

The remote procedure call API, pokki.rpc , allows one page to execute JavaScript in the context of the opposing page. This method forwards the return value of the specified JavaScript back to the original caller, allowing for quick and simple data exchange between pages. The return data types are limited to primitives so if you wish to exchange a complex data type such as an Object, you will first have to convert it to a string using JSON.stringify().

Basic Examples

Below are examples of operations that can be performed in the opposing page's context. You will note that pokki.rpc calls are very similar to JavaScript’s eval() function. Essentially pokki.rpc eval’s JavaScript in the opposing page’s context and forwards the returned value.


// Accessing a global variable
var global = pokki.rpc('global_variable');

// Executing a global function
var bar = pokki.rpc('foo()');

// Accessing a global object’s method
var some_bar = pokki.rpc('someObject.foo()');

// Executing JavaScript code
var result = pokki.rpc('global_variable = true');

// null is returned by default if the other page is not loaded
// or if the specified RPC JavaScript fails/returns nothing
var failed = pokki.rpc('thisFunctionDoesntExist()');
  
Helper Function

Pokki also provides a helper function called pokki.rpcArgs , which takes a string function name and an arbitrary number of arguments of any data type. It executes the specified function with those arguments in the opposing page’s context and forwards the return value.


// Handy helper function
var bar = pokki.rpcArgs('someObject.foo', true, {foo: 'bar'});
// Executes the following in the opposing page’s context:
// someObject.foo(true, {foo: 'bar'});
  
Advanced Example #1 – Using local storage and RPC

When attempting to transfer large amounts of data between pages, it generally makes the most sense to use shared local storage combined with RPC. In the following example there’s a background page which periodically loads a new article. When it finds a new article it stores it in local storage and uses RPC to notify the window page. The window then loads the article from local storage.

Background JavaScript


var periodically = setInterval(function() {
  var article = app.getNewArticle();
  if (article) {
    var article_key = 'article' + article.id;
    window.localStorage.setItem(article_key, JSON.stringify(article));
    pokki.rpcArgs('view.loadArticle', article_key);
  }
}, 300000);  // every 5 minutes
  

Window JavaScript


var view = {
  ...
  loadArticle: function(article_key) {
    var article = JSON.parse(window.localStorage.getItem(article_key));
    view.renderArticle(article);
  }
}
  
Advanced Example #2 – Polling to ensure the background page is loaded

As first mentioned in this section, the window page can rely on the background page’s existence almost always. The caveat is when an app is still loading, say after a reboot or install, and a user clicks on the app opening the window before the background page has initially loaded. If your window page requires the background page to function, for example to load data, then you should initially poll for the background page when your window loads.

Background JavaScript


// set a variable we can check for
var BACKGROUND_LOADED;
window.addEventListener('DOMContentLoaded', function(){
  BACKGROUND_LOADED = true;
});
  

Window JavaScript


// Declare our interval variable and define our polling function
var interval;
function poll() {
  if (pokki.rpc('BACKGROUND_LOADED') === true) {
    // the background is loaded, clear the interval and do stuff
    clearInterval(interval);
    doStuff();
  }
}
window.addEventListener('DOMContentLoaded', function(){
  interval = setInterval(poll, 50); // poll every 50 ms
});
  

Cross-origin XHR

Pokki apps are allowed to make cross-origin requests using the XMLHttpRequest object. This means that Pokki apps are NOT limited by the same origin policy found in browsers and that they can access any external resource.

Listening for events

Pokki provides a series of custom events in the pokki namespace that are not found in the browser. You can register to listen for these events using pokki.addEventListener from the window and background pages.

The following is list of all available Pokki events with examples and descriptions:

context_menu

Fires when the user selects a developer defined item in the context menu; passes the identifier associated with that menu item.


pokki.addEventListener('context_menu', function(id) {
  console.log('The user selected menu item: ' + id);
});
  
To learn more about creating your own context menu items see Context Menu . We recommend listening for this event from the background page.
hidden

Fires after hiding once the app is hidden from view.


pokki.addEventListener('hidden', function() {
  console.log('The app is now hidden');
});
  
hiding

Fires as the app is animating to a hidden state, due to a user action or pokki.hide being called.


pokki.addEventListener('hiding', function() {
  console.log('The app is about to hide');
});
  
link

Fires when the user clicks a link in the window page. The link's location is provided.


pokki.addEventListener('link', function(url) {
  pokki.openURLInDefaultBrowser(url);
});
  
Useful if you’re working with an existing web app that was intended to be run in the browser.
new_window

Fires when the window page's location (eg. window.location) is changed or window.open is called. The request is ignored, and the location is provided.


pokki.addEventListener('new_window', function(url) {
});
  
Useful if you’re working with an existing web app that was intended to be run in the browser.
showing

Fires when the user clicks on your app’s icon and the window animating.


pokki.addEventListener('showing', function() {
  console.log('The app is about to show');
});
  
Useful for performing an action or refreshing the contents of the app window before it is visible to the user.
shown

Fires after the showing event once the app is done animating.


pokki.addEventListener('shown', function() {
  console.log('The app is now visible');
});
  
unload

Fires four seconds before the app is is about to be unloaded by Pokki. The app's background page is automatically reloaded so it's always running - even if the window page isn't.


pokki.addEventListener('unload', function() {
  console.log('The app is about to be unloaded, save stuff!');
});
  
Useful for saving the state of your app before it is unloaded. See Maintaining state for more information.
work_area_change

Fires when the work area changes due to a user changing their display resolution.


pokki.addEventListener('work_area_change', function() {
  var area = pokki.getWorkAreaSize();
  console.log("Work area is now " + area.width + " by " + area.height);
});
  
Useful if you are trying to maximize the size of your app window. See App window for more details.
fullscreen

Fires when user presses the full-screen button in the window title bar.


pokki.addEventListener('fullscreen', function() {
  if (document.webkitIsFullScreen) {
    console.log("User wishes to exit full-screen");
  } else {
    console.log("User wishes to exit full-screen");
  }
});
  
Your app must listen and handle this event if it has informed Pokki that it is full-screen capable using pokki.setWindowFeature

You'll note there is no special load event provided in the Pokki namespace, thus on load you should listen for standard loading events. We recommend listening for the DOMContentLoaded event which does not wait external resources such as images to load.

Maintaining state

Handling unload

An app can be unloaded as a result of the user pressing the close button in the window title bar, or as a result of system restart or shutdown. When it's the result of the user, the app's background page is automatically reloaded so it may continue it's background processing. Depending on your app’s functionality, it may make sense to maintain the state of your app between loads and unloads.

Pokki fires a special event, unload, four seconds before your app is unloaded. You may use this time to save any data you’d like to have available the next time your app loads. We recommend using local storage as a method for storing persistent data, see Saving data for more details. During development you can right click on your app’s icon and select the “Unload” option from the Development menu to simulate this event.

The following example demonstrates saving the state of a dropdown menu during unload and then loading it on load.


// Save the dropdown’s index on unload
pokki.addEventListener('unload', function() {
  var last_index = $('#dropdown').selectedIndex;
  window.localStorage.setItem('last_index', last_index);
});
// Set the dropdown’s last index on load
window.addEventListener('DOMContentLoaded', function() {
  var last_index = window.localStorage.getItem('last_index');
  if (last_index != null) {
    $('#dropdown').selectedIndex = last_index;
  }
}, false);
  

Manifest file

The manifest file is used to store metadata about your app. Pokki uses the manifest file during the installation, updating and loading of your app. The file is UTF-8 encoded and contains a single JSON object. It is always named manifest.json and should be in the root directory of your app.

Example manifest.json file


{
   "name": "Pokki Atom",
   "version": "2.0",
   "icons": { "19":  "img/icon-19x19.png",
              "29":  "img/icon-29x29.png",
              "42":  "img/icon-42x42.png",
              "256": "img/icon-256x256.png" },
   "description": "A basic foundation from which to build a Pokki.",
   "window": "window.html",
   "background": "background.html"
}
  

Please note that the JSON parser does not support comments and strictly enforces the JSON syntax.

Required fields:

Name Type Description
name String The name of your app. Used by the Pokki interface during development.
icons Array Relative paths to each of your app's icons. The icon keys are: 19 for 19x19, 29 for 29x29, 42 for 42x42, and 256 for 256x256. The icons must be 32-bit PNGs.
window String Relative path to your app’s window HTML file within your app’s directory. It is loaded and displayed to the user when they click on your app’s icon.

Optional fields:

Name Type Description
version String Version number of your app for your reference. Not used by Pokki.
description String Description of your app. Not used by Pokki.
background String Relative path to an HTML file within your app’s directory that is loaded at all times.
menu Array Defines items that appear in the context menu when a user right clicks on your app’s icon. The items are defined as an array of objects with each object representing a single item. Each object has two string fields: text and id. The text field defines the text the user will see in the context menu’s interface and the id field is the internal identifier for this item. The items are displayed in the same order they are defined, from top to bottom.
scrambled_data Array Defines data to be obfuscated when your app is packaged. The data is defined as an array of objects, with each object representing an individual piece of data in the form of a key/value pair. Each object has two string fields: key and value. The key field is an identifier used to reference the data at run-time and the value is the data to be obfuscated.
required_plugins Array Specify any browser plug-ins your app requires. Each entry must contain two members: mime_type and min_version, which specify the mime type of the plug-in and the minimum version of the plug-in. Currently only Flash is supported.

Obfuscating data

At times it may be important to obfuscate sensitive data associated with your app, such as an API secret or session id. Pokki provides simple obfuscation functionality for data packaged in your app’s manifest and for data generated during run-time.

It's important to understand that this is obfuscation, not military grade encryption - it simply creates an additional step for someone other than the Pokki developer to obtain the data in its original form. In light of this, we call it scrambling and ask that you use it accordingly. Scrambling is linked to each app’s internal Pokki identifier, meaning only the app that scrambled the data can unscramble it.

Scrambling data at run-time

Pokki provides a pair of methods, pokki.scramble and pokki.descramble, for scrambling and descrambling data during run-time.


// Obfuscate data using pokki.scramble()
// Takes a noncyclic JavaScript object and returns a scrambled string
var scrambled = pokki.scramble({i_like_eggs: 'scrambled'});
console.log(scrambled); // e.g. "MXpAwOkw7JsJBNnYdfa88Ic/+9uJCT3CjAnpeA=="

// Return the data to its original form using pokki.descramble()
var eggs = pokki.descramble(scrambled);
console.log(eggs); // prints original object
  

Remember that scrambled data can be stored in local storage like any other piece of data.

Scrambling packaged data

Pokki also provides a method for you to scramble data that comes included in your app’s manifest and access it later. This is very useful for things like API secrets. The scrambling takes place when your app is packaged after being uploaded to the Pokki service. Until that time the data remains in its original form.

An example of data to be scrambled in a manifest file:


{
  ...
  "scrambled_data": [
    {"key":"api_key", "value":"KEY"},
    {"key":"api_secret", "value":"ITS_A_SECRET"}
  ]
}
  

In the above example we are scrambling two blobs of data (in this case strings), api_key and api_secret. To access the original strings at run-time we use pokki.getScrambled


var key = pokki.getScrambled('api_key');
var secret = pokki.getScrambled(api_secret');

console.log(key); // "KEY"
console.log(secret); // "ITS_A_SECRET"
  

Note that pokki.getScrambled continues to work as expected during the development of your app, even though the data in your manifest is not yet scrambled.

Storing data

Pokki provides persistent data storage for your app by supporting HTML5 local storage and web databases. The domain of both storage methods is your app, meaning that both the window and background pages access the same local data store. Your app cannot access the storage of another app and vice-versa.

Supported local storage methods:


window.localStorage.setItem(key, value);
window.localStorage.getItem(key);
window.localStorage.removeItem(key);
window.localStorage.clear();
  

For a complete API reference please refer to the following W3C specifications: http://www.w3.org/TR/webstorage/ and http://www.w3.org/TR/webdatabase/

Adobe Flash

If your app requires Adobe Flash, you must specify it in your app's manifest file. For example:


"required_plugins": [{
    "mime_type": "application/x-shockwave-flash",
    "min_version": "11"
}]
  

If the user doesn't have Adobe Flash, or the minimum version of Adobe Flash your app requires, Pokki will manage the installation.