WebAPI/WebActivities
Introduction
Web Activities is a counter-proposal to Web Intents. It is trying to limit the scope of the API to the following use case: APP A wants to delegate an activity to APP B. Web Activities isn't a discovery API or a communication API. Those things happen in the background and are completely transparent to the caller.
Dependencies
This API depends on two APIs that are not currently part of any specification: System Message Handler and DOMRequest.
Proposed API
interface ActivityOptions { attribute DOMString name; attribute Object? data; // a dictionary }; [Constructor(DOMString name)] interface ActivityHandlerDescription { attribute DOMString name; // default has to be passed to ctor attribute DOMString href; // default is current location attribute DOMString disposition; // going to be an enum with a default attribute boolean returnValue; attribute Object? filters; // a dictionary }; interface ActivityRequestHandler { void postResult(any result); void postError(DOMString error); readonly attribute ActivityOptions source; }; [Constructor(ActivityOptions options)] interface Activity : DOMRequest { }; partial interface Navigator { DOMRequest registerActivityHandler(ActivityHandlerDescription d); void unregisterActivityHandler(ActivityHandlerDescription d); bool isActivityHandlerRegistered(ActivityHandlerDescription handler); };
More information
Some various explanation regarding part of this API that are not self-explanatory.
Activity names
Basic activities will have simple names like edit, view, pick or share (this is non-exhaustive). A set of basic activities should be defined in the initial specification. Defining will imply specifying how data should be structured to be considered valid and how the return value (if any) should be structured too.
Any other specification will be able to create new activities. For example, a Messaging specification might add 'send-sms'.
Any application will be able to create new activities. Any application is able to register itself as handling the activity foobar and any application is able to start the activity foobar.
However, to prevent naming collision, we recommend such proprietary naming to be prefixed with an URL. For example: example.org/foobar or org.example.foobar (doesn't matter that much).
Handling an activiy
Handling activities will be done trough System Message Handler. An ActivityRequestHandler will be passed in the Message.
More information about ActivityOptions
Activities are defined with a name and some data. Those data can be stuff like the image to send, the type of the object or anything the activity will require. Activities with a specific name should have
specific data the handlers will expect to see.
That means the initial specification should specify a set of basic activities.
More information about ActivityHandlerDescription
- href: can be used to register an activity handler in another page. Needs to be same origin.
- disposition: could be window or inline for the moment. window means it will show a new window/tab. inline means it will be shown above the current content. This is only a hint for the UA.
- returnValue: the UA might want to know if the activity will return a value. For the basic activities (view, edit, etc.) the UA knows that but we need that at least for proprietary activities.
This seems to be needed to be able to send a success or error event when appropriate. If an application doesn't return a value, the UA might want to send a success event as soon as an application has been picked. If a value is expected, this event will have to wait postResult() to be called. Note that UA is expected to send an error event at some point if neither postError nor postResult are called. For example, if the user leaves the application (close the tab on desktop or goes back to the homescreen on a mobile device). - filters: this object should mirror data from ActivityOptions but the values for each fields can be an Array of string, a string or a regexp. An activity will be considered as able to handle an activity only if the filters are all satisfied. An array means OR for each items. If there is no filter value for a field, that means it is always satisfied.
Arguments for {un,}registerActivityHandler and isActivityHandlerRegistered
You do not need to pass the same ActivityHandlerDescription object to have registerActivityHandler, unregisterActivityHandler and isActivityHandlerRegistered working. You only need to pass an instance of ActivityHandlerDescription with the same attribute values.
Declarative registration
Open Web App Manifest should include a way to register activities declaratively. The format would look like this:
"activities": { "share": { "filters": { type: ["image/png", "image/gif"], } "href": "foo.html", "disposition": "window" } }
For non-installed applications, this API doesn't yet define how to do a declarative registration. However, it doesn't sound very useful for the moment to have such mechanism. However, if it had to be added, adding a new element into the <head> would seem like the most appropriate solution (or using an already existing one). The only advantage of adding a new element inside the <body> is that we don't have to worry about the <head> parsing issues.
Examples
The data structure used in those the activities used in those examples shouldn't be considered as near to anything final. It is just a snapshot on how it could look like. Those examples goal is to underline the use of the API.
Launch an activity
View a png image:
var a = new Activity({ name: "view", data: { type: "image/png", url: ... }}); a.onerror = function() { alert("Can't view the image!"); };
Pick an image:
var a = new Activity({ name: "pick", data: { type: "image/png", multiple: false }}); a.onsuccess = function() { var image = a.result; doSomethingWithImage(image); }); a.onerror = function() { alert("Failure when trying to pick an image!"); });
Register to handle an activity
View a png image:
var r = navigator.registerActivityHandler({ name: "view", disposition: "inline", filters: { type: "image/png" }}); r.onerror = function() { alert("failed to register activity"); }
Pick a png image and return what the user had picked:
var r = navigator.registerActivityHandler({ name: "pick", disposition: "inline", filters: { type: "image/png" }, returnValue: true}); r.onerror = function() { alert("failed to register activity"); }
View a png/gif image in another page than the current one:
navigator.registerActivityHandler({ name: "view", href: "image-viewer.html", disposition: "inline", filters: { type: ["image/png", "image/gif"] }});
View only HTML pages from example.org:
navigator.registerActivityHandler({ name: "view", filters: { url: /https?:\/\/example.org\/.*/ }});
Open Web Apps can alternatively register in their webapp manifests.
Handle an activity request
View a png image:
navigator.setMessageHandler('activity', function(a) { // We can't be handling an activity that isn't what we asked, because of |filters|. var i = getImageObject(); i.src = a.source.url; // We do not call a.postResult() or a.postError() because this activity shouldn't return a value. });
Pick an image:
navigator.setMessageHandler('activity', function(a) { var image = getImageToReturn(); if (!image) { a.postError("NoImage"); return; } a.postResult({ type: "image/png", url: image }); });