CocoonJS: ‘onSuspended’ and ‘onActivated’ events

While I’ve been using CocoonJS on and off for most of this year, I haven’t really investigated what the CocoonJS.App functionality was beyond just detecting CocoonJS itself until more recently. However, due to a post on the Phaser forum (as well as my research into Cordova’s own ‘pause’ and ‘resume’ events), I’ve spent the last couple of nights trying to patch in hybrid app support for HTML5 apps being sent to the background or brought to the fore. It’s something that has generated a fair amount of frustration (I’ve put off the Cordova work because of its iOS quirks), but has, as well, finally reached a point where I understand what is going on and can show others.

To start, it’s worth pointing out that the documentation for CocoonJS can be a bit misleading on its ‘onSuspended’ and ‘onActivated’ events. While it does show that both are “CocoonJS.EventHandler object[s]” and that the “callback function does not receive any parameter” for each, it doesn’t show how to actually use them. Unless you are read up on how CocoonJS.EventHandler works, it can be a bit of a mystery.  It takes knowing, for example, that an addEventListener function call is needed to use them at all.

For their most basic usage, both functions (with their EventListeners) look like the following:

CocoonJS.App.onSuspended.addEventListener(someFunction);
CocoonJS.App.onActivated.addEventListener(someFunction);

However, even with with those functions calls (to someFunction), they don’t always help. Because most HTML5 development happens on and is generally for desktop environments, many frameworks and developers expect to feed a number of listeners to various functions and have them sort things out (as per the DOM Core model). In other words, they expect to receive some Event object based on the DOM Core and especially with a ‘type’ property that declares what the event was in the first place. However, as I quoted above, CocoonJS doesn’t do that; its events do not pass an Event object.

However, if you still need that object (as Phaser does), you can create one. It just takes a little bit more code and some understanding of how arguments as passed within JavaScript.

var _this = this;
CocoonJS.App.onSuspended.addEventListener(function () {
someFunction.call(_this, {type: "suspend"});
});
CocoonJS.App.onActivated.addEventListener(function () {
someFunction.call(_this, {type: "activate"});
});

With the above code, the ‘this’ (current function context) is saved first and then the event listeners are added. Within each, a call() is made using the saved ‘this’ (so that the function scope doesn’t change) and an object is created during the function execution (by passing an object with a property). The receiving function (someFunction) will then see one argument, the object, with a single property, ‘type’, set to whatever is needed.

For example, someFunction might then look like the following:

function someFunction(event) {
if(event.type === "suspend") {
pauseExecution();
} else if(event.type === "activate") {
resumeExecution();
}
}

This way, if you have someFunction checking other event types, CocoonJS’ own events will fit that detection model as well. In fact, using the anonymous function as the listener of the CocoonJS events, you can create your own Events directly and pass them as needed too. And if you wanted more than just a ‘type’, you can model different responses or trigger other, document-wide events in response to mirror existing detection you might already have in place too.