WebAPI/SimplePush: Difference between revisions
Line 67: | Line 67: | ||
var reqEmail = navigator.pushNotifications.register(); | var reqEmail = navigator.pushNotifications.register(); | ||
reqEmail.onsuccess = function(e) { | reqEmail.onsuccess = function(e) { | ||
emailEndpoint = e.result.pushEndpoint; | emailEndpoint = e.target.result.pushEndpoint; | ||
storeOnAppServer("email", emailEndpoint); <i>// This is the "Hand wavey" way that the app | storeOnAppServer("email", emailEndpoint); <i>// This is the "Hand wavey" way that the app | ||
// sends the endPoint back to the server</i> | // sends the endPoint back to the server</i> | ||
Line 75: | Line 75: | ||
var reqIm = navigator.pushNotifications.register(); | var reqIm = navigator.pushNotifications.register(); | ||
reqIm.onsuccess = function(e) { | reqIm.onsuccess = function(e) { | ||
imEndpoint = e.result.pushEndpoint; | imEndpoint = e.target.result.pushEndpoint; | ||
storeOnAppServer("im", imEndpoint); | storeOnAppServer("im", imEndpoint); | ||
} | } |
Revision as of 17:36, 5 February 2013
You're a service. Getting clients to talk to you is pretty easy. All you have to do is sit there and wait for them to call. But, what if you want to tell your clients that there's something interesting for them?
SimplePush is a very low cost service that let's servers tell clients "Hey, there's something interesting over here! You ought to do something about that."
Definitions
Before we get into details, it's important that we have a good lexicon.
- App
- The remote receiver of the SimplePush Notification.
The app is what requests things get established, gets pinged when something interesting happens, and connects back to the AppServer.
- AppServer
- The third party publisher of update notices.
This is, more than likely, where all the real work of your App is done. It's what has the mail, or the articles, or where someone whacks serpents with farm implements for slices of virtual dessert.
- UserAgent
- The client acting on behalf of the user and consumer of update notices
This is what handles talking back to the PushServer and wakes up the App when there's something of interest. For example: Firefox Desktop, Firefox OS (a service runs in the background)
- PushServer
- The server managing interactions between AppServers and the UserAgent.
This is what the AppServer is talking to when it wants to tickle the client.
- Endpoint
- Unique URL to be used by the AppServer to initiate a response from the App.
This is generated by SimplePush and sent to the App. The App will need to relay this to the AppServer.
The following are SimplePush hoo-doo things that are probably not important to you. Here, look at this device while I put on my sunglasses.
- Channel
- The flow of information from AppServer through PushServer to UserAgent.
- ChannelID
- Unique identifier for a Channel. Generated by UserAgent for a particular application.
- UAID
- A globally unique UserAgent ID
UserAgent and AppServer will use a RESTful API to interact with the Push Server.
Use Cases
An App wishes to be notified when new email arrives. A User installs an App on a mobile device which notifies her when someone adds a note to her bulletin board. The App calls the Registration function, which returns an EndPoint. The App sends the EndPoint to the AppServer using the magic of "Not-Part-Of-This-Protocol". The AppServer stores the EndPoint in the User's information. When a new note is added, the AppServer fetches the EndPoint and PUTs a new version value to it. This alerts SimplePush, which wakes the App and sends a "push" event. This causes the App to refresh it's messages (again using the magical "Not-Part-Of-This-Protocol" system), and User gets a screen full of adorable kittens.
An AppServer wishes to notify Apps of an update. Since a server doesn't want to be deluged by millions of pings from devices every hour, the developers wisely decide to opt for a Push mechanism. Much like the other example, an App registers with SimplePush, gets an EndPoint which it relays to AppServer. AppServer then PUTs a '000' version to the EndPoint which triggers a "push" event for the App, which silently acknowledges that all is well. At some later time, AppServer PUTs '001' to the EndPoint which SimplePush relays to App which then updates itself using "Not-Part-Of-This-Protocol-Either".
Messy Details
Client Side API
Apps will need to add the following to their manifests. See our Web App Development Guide for what this means and how to use it.
App manifest
{ ... "messages": [ {"push": "/view_to_launch.html"} {"push-register": "/view_to_launch.html"} ] }
JavaScript
We've tried to make the client code as simple as possible. While the following may not be what you use, it shows the general idea.
var emailEndpoint, imEndpoint; function setupAppRegistrations() { // Issue a register() call // to register to listen for a notification, // you simply call push.register // Here, we'll register a channel for "email" updates. Channels can be for anything the app would like. var reqEmail = navigator.pushNotifications.register(); reqEmail.onsuccess = function(e) { emailEndpoint = e.target.result.pushEndpoint; storeOnAppServer("email", emailEndpoint); // This is the "Hand wavey" way that the app // sends the endPoint back to the server } // We'll also register a second channel for "im", because we're social and all about the socialists. Or something. var reqIm = navigator.pushNotifications.register(); reqIm.onsuccess = function(e) { imEndpoint = e.target.result.pushEndpoint; storeOnAppServer("im", imEndpoint); } } // Once we've registered, the AppServer can send version pings to the EndPoint. // This will trigger a 'push' message to be sent to this handler. navigator.mozSetMessageHandler('push', { handleMessage: function(e) { if (e.target.pushEndpoint == emailEndpoint) // Yay! New Email! Steve and blue can dance! getNewEmailMessagesFromAppServer(e.target.version); else if (e.target.pushEndpoint == imEndpoint) // Yay! An IM awaits. I wonder if it's Sam's IM? getNewChatMessagesFromAppServer(e.target.version); } }); // The user has logged in, now's a good time to register the channels AppFramework.addEventListener('user-login', function() { setupAppRegistrations(); }); // to unregister, you simply call.. AppFramework.addEventListener('user-logout', function() { navigator.pushNotifications.unregister(emailEndpoint); navigator.pushNotifications.unregister(imEndpoint); }); // error recovery mechanism // will be called very rarely, but application // should register again when it is called navigator.mozSetMessageHandler('push-register', { handleMessage: function(e) { if (AppFramework.isUserLoggedIn) { setupAppRegistrations(); } else { // since user isn't logged in, when he logs in // registrations will be setup due to event handler } } });
Interface
partial interface Navigator { PushNotification pushNotification; }; interface PushNotification { // registers to receive push notifications for a given topic // DOMRequest.result is a PushRegistration in case of success DOMRequest register(); // registers to stop receiving push notifications for a given topic // DOMRequest.result is a PushRegistration in case of success DOMRequest unregister(DOMString pushEndpoint); // returns the list of all push registrations for this origin PushRegistration[] registrations(); }; interface PushRegistration { // this is the URL to which push notifications from the AppServer // must be sent to. // This is how the AppServer alerts the UserAgent that new data exists. DOMString pushEndpoint; // undefined when obtained from register().onsuccess. // contains version when obtained from PushEvent DOMString version; }; interface PushEvent : Event { PushRegistration target; }
Notes
The current spec works for apps. Ideally it should work for web pages loaded in browsers as well. Current issues blocking this:
- mozSetMessageHandler indexes by app manifest. Web pages don't have app manifests.
- The lifetime of registrations for web pages needs specification.
- Every instance of a web page should be treated differently. So the same URL in two tabs should have different channels (and ask permission?). Again geolocation, desktop-notification and others may provide clues)
- In the case of the b2g browser, the browser is an app and so mozSetMessageHandler gets its manifest, and not access to the pages. We might want to bypass the browser and plug directly into the mozbrowseriframe of each tab. Again within each tab, user might navigate away from page, which may need invalidation.
UI
- During app installation, the user agent should notify the user that the app uses push notifications, and possibly deny permission.
- Web pages using push notification should show a doorhangar notification in the same way (look at geolocation to see how this is done).
Server API
ServerAPI has the details of how the ServerAPI works.
Chances are, all you want is to send a new version update.
The simplest way to do that is to call
POST endpoint version=newversion
Where endpoint is the value that was returned during App's registration.