Wholesale Application Community Device API Specifications 2.1

Webview API

The Webview API lets you pop-up a mini browser inside your application.

Contents

  1. 1 Introduction
  2. 2 Feature String
    1. 2.1 Processing feature declarations
  3. 3 CloseURL params
    1. 3.1 Processing the param elements
  4. 4 The webview of a widget
    1. 4.1 When to use the Webview
    2. 4.2 Relationship to window.open()
    3. 4.3 Relationship to WARP
    4. 4.4 Privacy considerations
    5. 4.5 User interface considerations
    6. 4.6 States
    7. 4.7 Waiting for the webview to close
    8. 4.8 Close conditions
    9. 4.9 Scheme white list and navigation
    10. 4.10 Exception handling
    11. 4.11 Opening the webview
    12. 4.12 Closing the webview
    13. 4.13 Matching and comparison
  5. 5 DeviceapisWebview Interface
    1. 5.1 The webview attribute
  6. 6 Webview Interface
    1. 6.1 The closed attribute
    2. 6.2 The onclose attribute
    3. 6.3 The open() method
  7. 7 WebviewEvent interface
    1. 7.1 The url attribute
  8. Reference implementation
  9. Change Log

1 Introduction

The Webview API provides a means for a widget to asynchronously open a mini Web-browser (also known in HTML parlance as a secondary browsing context) without leaving the execution context of a widget. Through the webview, an end-user can perform tasks on the network and then return to a widget once the task is complete. Examples of potential actions that can be performed via a webview:

2 Feature String

The webview feature declaration represents a developer's intention to use the functionality provided by this specification. A configuration document can contain multiple webview feature declarations, but which feature declaration is used by a widget runtime is determined by running the steps for processing webview feature declarations.

The webview feature string is: http://wacapps.net/api/webview

2.1 Processing feature declarations

A widget runtime processes feature elements in accordance with the W3C's Widget Packaging and XML Configuration specification. If the feature-list contains any features whose feature-name exactly matches the webview feature string, then the widget runtime MUST apply the steps for processing webview feature declarations.

The steps for processing webview feature declarations is given by the following algorithm:

  1. With the first encountered feature in tree order that matches the webview feature string, run the steps to process closeURL params. Ignore all subsequent webview feature declarations. Retain the resulting list of closeURL params to be used once the Webview API is made available at runtime (i.e., through the DeviceapisWebview interface).

  2. When the widget's start file is instantiated at runtime, implement the DeviceapisWebview interface.

XML Example

<widget xmlns="http://www.w3.org/ns/widgets">
  <feature name="http://wacapps.net/api/webview"/>
 
  <!-- the following declaration is ignored --> 
  <feature name="http://wacapps.net/api/webview">
     <param name ="closeURL"
            value="http://example.com/close/me"/>
  </feature>
</widget>

The above example shows how to enable the Webview API in an application.

3 CloseURL params

Through the use of param elements as child elements of a webview feature declaration, a developer can optionally specify one or more URLs that, when matched, will cause the webview to close. This collection of URLs is referred to as the list of closeURL params and each valid URL in the list is referred to as a close URL. The list of closeURL params are unique to a widget instance, and are not shared across widgets. That is, one widget's list of closeURL params have absolutely no relationship to the list of closeURL params of any other widget.

3.1 Processing the param elements

The steps to process closeURL params of a webview feature declaration are given by the following algorithm. The algorithm assumes that the webview feature was processed in conformance with the Widget Packaging and XML Configuration specification (though any XML parser will do).

  1. Let close-urls be an empty list.

  2. If the webview feature declaration contains any parameters, for each parameter of the webview feature declaration:

    1. Let param be the current parameter.

    2. If the param-name of param does not exactly match the string "closeURL", then ignore this parameter and move onto the next parameter of the webview feature declaration (if there are any left to process).

    3. Let potential-url be param-value of param.

    4. Let url be the result of trying to parse the potential-url into its component parts: If potential-url is in error (as a result of parsing) then ignore this parameter and move onto the next parameter of the webview feature declaration (if there are any left to process). If the widget runtime is operating in developer mode, warn the developer with an informative message that potential-url was ignored because it was in error.

    5. If url is not an authority-based URL, or contains a userinfo component then ignore this parameter and move onto the next parameter of the webview feature declaration (if there are any left to process). If the widget runtime is operating in developer mode, warn the developer with an informative message as to why the url was ignored.

    6. If the widget has a recognized origin (meaning it has been signed for the purposes of distribution):

      1. If url's scheme, authority, and port components do not exactly match those of the widget's recognized origin, then ignore this parameter and move onto the next parameter of the webview feature declaration (if there are any left to process). If the widget runtime is operating in developer mode, warn the developer with an informative message as to why the url was ignored.

    7. If close-urls does not already contain the url, append url to the close-urls list.

  3. Return close-urls.

XML Example

<widget xmlns="http://www.w3.org/ns/widgets">	
  <feature name="http://wacapps.net/api/webview">
     
     <!-- this close URL is trusted, so it's used --> 
     <param name ="closeURL" 
            value="http://trusted.url.com/close/me"/>

     <!-- this one is not, so it's ignored --> 
     <param name ="closeURL" 
            value="http://untrusted.url.com/close/me"/>

  </feature>
</widget>

4 The webview of a widget

A webview is a secondary browsing context that is associated with a widget instance. Each instance of a widget that declares the webview feature will have its own unique webview (see privacy considerations). Being a  secondary browsing context, a webview can be navigated, follows redirects, and can execute scripts in a Document (hence, acts pretty much the same as a regular window in a web browser). Upon opening, the end-user can close the webview at any time (either through a user interface element or through a physical button on the device). See the close conditions for more information.

For security reasons, and being a secondary browsing context, the webview has no knowledge of its opener browsing context (i.e., the Webview's Window object's opener attribute returns null).

A Webview MUST NOT expose any API enabled by a feature in the Webview (i.e., the Widget does not share or otherwise expose the WAC Device APIs within the browsing contexts of the webview). However, a webview will generally enable APIs that are commonly part of the Web Platform (e.g. the W3C's Geolocation API, Web Storage, WebGL, etc.).

The webview is orthogonal to the widget that instantiated it: it has no knowledge of, or direct means to communicate with, the widget that created it.

4.1 When to use the Webview

This section is non-normative.

Although this API allows an end-user to browse the Web, it is recommended that general Web browsing be performed in the default system browser rather than through a webview. That is, the Webview API is intended to perform focused tasks that are directly relevant to the application (e.g., authorizing an application, mking a quick purchase, or reading an article). This is because the browsing experience provided by a webview will likely pale in comparison to the browsing experience provided by a full web browser (e.g., the ability to bookmark a page, open tabs, manage passwords, etc.).

4.2 Relationship to window.open()

This section is non-normative.

Unlike the window.open() API of HTML, the Webview API only allows one window to be opened by an application.

4.3 Relationship to WARP

Unlike the widget instance that owns the webview, whose security policy may be governed by the Widget Access Request Policy (WARP), the security policy of a webview is governed by HTML's same-origin policy and not by WARP. This means that:

  1. A webview can be used to attempt to open any URL, not just those that match a WARP access request.

  2. A webview can navigate freely: the access request policy of WARP has no effect on the browsing context of the webview.

4.4 Privacy considerations

Implementers need to take the following privacy considerations into consideration when implementing the Webview API.

Each webview is unique and does not share cookies, cache, Web Storage areas, or browsing history with any other application or widget (not even with instances of the same widget).

Upon closing the widget, the WRT SHOULD remove all privacy sensitive information generated by the browsing context of the webview. This includes, but is not limited to, cookies, Web Storage areas, browsing history, form data, stored passwords, and granted API permissions (e.g., access to Geolocation information) pertaining to the webview's browsing history. In other words, the webview works much like a browser running a private browsing session.

Upon uninstalling a widget that makes use of the Webview API, the widget runtime MUST destroy any cache, storage areas, cookies, form data that was created by the webview during the lifetime of the widget.

4.5 User interface considerations

This section is non-normative.

A widget runtime needs to make sure the webview provides sufficient user-interface chrome to allow end-users to make informed decisions. As such, it is recommended that the webview's user-interface components include:

When the webview is presented to the end-user, the end-user needs to be able to clearly associate the creation of the view with the initiating action in the application (i.e., when the user clicks something, the webview animates or slides-in in a way that is obvious that it is happening as a result of some user interaction).

4.6 States

At runtime, a webview can be in one of four states. The ability to perform certain actions at a given moment in time are governed by these states:

Opening:

The webview has received a request via the open() method to be shown, and the widget runtime is capable of granting the request.

Open:

The widget runtime has finished presenting the webview and it is now ready to be navigated and waits for a close condition to be satisfied.

Closing:

A close condition was met and the widget runtime is in the process of removing the webview from the user interface.

Closed:

The webview is closed and not interactive. This is the default state of the webview when the webview is initialized.

4.7 Waiting for the webview to close

When instructed to wait for close, the widget runtime waits indefinitely until one of the close conditions is met.

4.8 Close conditions

A close condition is an action that, when it occurs, causes the webview to be removed from the user interface (by putting the webview into the closing state). This specification defines the following close conditions:

Closed through user interaction:

The user performed an action that causes the webview to close through user-interaction. This can include activating a physical user interface control such as the back-button on many Android devices; or through some other user interface control, such as a close button.

Closed through script:

A script caused the window to close through a script, which caused the webview's browsing context to be discarded. For example, a script calls window.close().

Closed through URL matching:

The webview attempted to navigate to a URL that matches a close URL in the list of closeURL params: The widget runtime checks if two URLs match by running the steps to determine if a URL matches a close URL. The algorithm is run prior to any attempts by the widget runtime to navigate the browsing context of the webview (i.e., checks are always done prior to navigating the webview, and before any content is loaded). For example, the algorithm is run before following a redirect or immediately after a user clicks on a link.

4.9 Scheme white list and navigation

The scheme white list is a list of schemes that the widget runtime allows the webview to access. Attempting to access schemes not on the white list through the webview interface results in a security error being thrown by the widget runtime. WAC itself does not define any schemes for the scheme white list: what schemes are on the white list is left up to implementations (i.e., widget runtime vendors are expected to define the scheme white list).

Nevertheless, it is RECOMMENDED that http and https be included in the scheme white list.

A widget runtime MUST ignore attempts to navigate a webview to schemes that are not in the scheme white list from within the webview itself (e.g., via a hyperlink, or changing the document's location).

Example

<!doctype html>
<!-- assuming file:// is not on the white list -->
<a href="file://">This will likely go nowhere.</a>

4.10 Exception handling

This section defines the exception handling rules used by the Webview API. Exceptions are gathered here for the reader's convenience (and to avoid some duplication of text in the specification).

When instructed to throw an InvalidStateError, the widget runtime throws a "InvalidStateError" DOMException, with the message "Webview must be closed to perform this operation." and terminates the algorithm that threw the exception.

When instructed to throw a SecurityError, the widget runtime throws a "SecurityError" DOMException, with its message set to "Access to scheme 'x:' is not allowed.", where x is replaced by the name of the disallowed scheme (e.g., "Access to the 'widget:' scheme is not allowed.").

When instructed to throw a NetworkError, the widget runtime throws a "NetworkError" DOMException with message: "No permission to access this network resource. No network access or blocked by policy." and terminates the algorithm that threw the exception.

When instructed to throw an InvalidAccessError, the widget runtime throws an "InvalidAccessError" DOMException with its message set to "Unable to open a webview with invalid URL: x" (where x is the value of the offending URL) and terminates the algorithm that threw the exception.

4.11 Opening the webview

The steps to open the webview are given by the following algorithm.

  1. If the webview is not in the closed state, throw an InvalidStateError.

  2. If the first argument is undefined, null, or an empty string, then let url be "about:blank". Otherwise:

    1. Let parsed-url be the result of trying to resolve and parse the first argument. If parsing fails with an error, then throw an InvalidAccessError.

    2. If the <scheme> component of the parsed-url is not in the scheme white list, then throw a SecurityError.

    3. If parsed-url is not authority-based URL, then throw a NetworkError.

    4. Otherwise, let url be the value of parsed-url.

  3. Set the state of the webview to opening.

  4. Continuing asynchronously, present the webview to the end-user.

  5. Once the webview is displayed, set the state of the webview to open.

  6. Wait for close and attempt to navigate to url: when one of the close conditions is met, run the steps to close the webview.

4.12 Closing the webview

The steps to close the webview are given by the following algorithm.

  1. If the webview is closed or closing, then terminate this algorithm.

  2. Set the state of the webview to closing.

  3. If the webview was closed through URL matching, let address be a normalized string representation of the webview's top-level browsing context's document's address. Otherwise, let address be null.

  4. If already displayed, remove the user interface component that represents the webview, discarding of the browsing context being used by the webview.

  5. Set the state of the webview to closed.

  6. Let close-event be an event that implements the WebviewEvent interface, with the name "close", which does not bubble and is not cancelable. Set the url attribute of close-event to address.

  7. Fire the close-event at devicesapis.webview (which will dispatch the event to any event listeners, including those added via the onclose attribute or the addEventListener() method of the EventTarget interface).

4.13 Matching and comparison

The steps to determine if a URL matches a close URL are given by the following algorithm. This algorithm requires a widget runtime to use scheme based normalization when comparing URLs (for http and https, see http and https URI Normalization and Comparison). The algorithm returns either true (a match is made) or false. Returning a value terminates the algorithm.

  1. Let input-url be the URL to which the webview is intending to navigate.

  2. Normalize input-url by parsing it (for http and https, see http and https URI Normalization and Comparison of httpbis).

  3. For each close-url in the list of closeURL params (if any), using scheme based normalization compare close-url to input-url:

    1. If the <scheme>, <hostport>, <path> component match, and close-url either does not have a <fragment> component or <fragment> component of both URLs match:

      1. If close-url does not have a <query> component, return true.

      2. If input-url has a <query> component:

        1. If the name-value pairs that make up close-url's <query> component are a subset of input-url's <query>component (in any order), return true.

  4. Return false.

Matching Examples

The table below presents some examples to show the expected behavior of a user agent running the steps to determine if a URL matches a close URL. Please note that the Webview API is protocol-agnostic, so some test cases that don't comply to OAuth may be valid cases for other protocols.

URL Comparison and Matching examples
closeURL (config.xml, normalized) input-url (navigated) Match Reason
http://example.com/ http://example.com true Normalization automatically includes "/"
http://example.com: true Normalization removes ":" and adds "/"
http://example.com:/ true Normalization removes ":"
http://example.com:80/ true Normalization removes ":80"
http://example.com/? false Query does not match.
http://example.com? false Query does not match.
http://example.com/?? false Query component is "??"
http://example.com# false Fragment does not match.
http://example.com/# false Fragment does not match.
http://example.com:80?# false :80 is stripped and "/" is added by normalization but query and fragment don't match.
http://example.com:80/?# false :80 is stripped, but query and fragment don't match.
http://www.example.com false Different subdomain
http://example.com/path https://example.com/path false Different scheme
http://elpmaxe.com/path false Different authority
http://example.com/path/hello/ false Different path
http://example.com/path/ false Trailing slash on path
http://example.com:8080/ false Different port
http://user:pass@example.com/ false UserInfo not allowed
http://example.com/path#fragment true  
http://example.com/path?key2=val2 true  
http://example.com/path?key2=val2#fragment true  
http://example.com:80/path true  
http://example.com/%70%61%74%68 true Decodes to "path"
http://example.com:/path true ":" removed by normanlization.
http://EXAMPLE.com/path true  
http://example.com/../path true Resolving removes "../"
http://example.com/Path false Path case differs in path
https://example.com/?param=bar https://example.com:443 true default port
https://example.com:443/ true Default path and port
http://example.com/?Param=bar false First case of Param differs
http://example.com/?param=Bar false First case of Bar differs
http://example.com/some path http://example.com/some%20path true  
http://xn--exmple-cua.com/ http://www.exämple.org/ true Normalized to punycode
http://example.com/path?key1=val1 http://example.com/path?key1=val1&key2=val2 true  
http://example.com/path?key1=val1#frag true  
http://example.com/path?key2=val2& key1=val1 true Order of query parameters is irrelevant to matching algorithm
http://example.com/path?key2=val2 false Missing key1=val1in query component
http://example.com/path#fragment http://example.com/path false Missing fragment on input-url
http://example.com/path?key=val#fragment true  
http://example.com/path#fragment2 false Fragment differs
http://example.com/path?key1=val1#fragment http://example.com/path?key1=val1 false Missing fragment
http://example.com/path?key1=val1#fragment2 false wrong fragment
http://example.com/path?key1=val1&key2=val2#fragment true  

5 DeviceapisWebview Interface

[NoInterfaceObject] 
interface DeviceapisWebview {
    readonly attribute Webview webview;
};
Deviceapis implements DeviceapisWebview;

When a webview feature declaration appears in the widget's configuration document, a conforming widget runtime implements the DeviceapisWebview interface; thus providing access to Webview API through the deviceapis.webview attribute.

5.1 The webview attribute

The webview attribute is the point of access to the Webview API.

JavaScript example

var wv = window.deviceapis.webview; 
if (wv.closed) {
	wv.open("http://example.com");
}

6 Webview Interface

interface Webview : EventTarget {
   readonly attribute boolean closed;
   void open ( optional DOMString url ); 
   [TreatNonCallableAsNull] attribute WVHandler? onclose;
}
callback WVHandler = void (WebviewEvent event);

The webview interface provides a developer with the means of interfacing with the attributes and methods of the webview.

6.1 The closed attribute

On getting the closed attribute, the user agent MUST return true if the webview is in the closed state. Otherwise, it returns false.

JavaScript example

var wv = window.deviceapis.webview
if (wv.closed) {
   wv.open("http://example.com");	
}

6.2 The onclose attribute

The onclose attribute is an event handler IDL attribute that a developer can use to be notified when the webview closes.

When getting and setting, a widget runtime MUST conform to the behavior for an event handler IDL attribute as defined in HTML.

JavaScript example

var wv = window.deviceapis.webview;
wv.onclose = function (e) {
   if (e.url) {
     console.log("Webview close at: " + e.url);
     return; 
   }
   console.log("The user or some script closed the webview."); 
   //remove the listener 
   wv.onclose = null; 
}

//add custom event listener 
wv.addEventListener("close", 
   function customHandler (e) {/* custom handler */}, 
   false); 

6.3 The open() method

The open() method asynchronously requests that the widget runtime open the webview at a given url.

When the open(url) method is invoked, the widget runtime MUST run the steps to open the webview.

Javascript example

var wv = window.deviceapis.webview; 
try{
  if (wv.closed) {
    wv.open("http://example.com");
  }
}catch(e){
	//catch any potential errors (e.g., network error) 
}

7 WebviewEvent interface

interface WebviewEvent : Event {
  [Unforgeable] readonly attribute DOMString? url;
};

The WebviewEvent interface is used to represent a close condition being met. This kind of event is dispatched during the steps to close the webview.

7.1 The url attribute

The url attribute represents the URL at which the webview was closed.

When getting, if the webview was closed through URL matching, the user agent must return a string representation of a URL. Otherwise, the user agent must will return null, which means the webview was closed through one of the other close conditions.

Javascript example

var wv = window.deviceapis.webview; 

wv.addEventListener("close", 
   function checkURL (e) {
      if(e.url.search("http://some.url.com")){
         //do something useful with the returned URL
         return; 
      }
   }, 
false);

Reference implementation

A reference implementation is available. Please note that it is restricted by the browser's same origin policy so only URLs in the "specs.wacapps.net" space will work.

Change Log

This specification was last updated on 18 May 2012. A complete list of changes are kept on our GIT repository.