Skip to main content
October 1, 2013
PC

Blending apps and sites with the HTML x-ms-webview



The x-ms-webview is a powerful control that lets you embed web content directly in your app’s UX. This control has been available to XAML Windows Store apps since Windows 8, and in Windows 8.1 we’ve made lots of great updates, which are described in Sam Spencer’s blog post, What’s new in WebView in Windows 8.1. As noted in Sam’s post, one of the biggest updates is that the control is now available for apps written in HTML and JavaScript!

If you’re an HTML/JS app developer, the x-ms-webview offers you a great way to add web content to your app’s experience. In this post we’ll dive into why you’ll want to upgrade your app to use x-ms-webview. I’ll also give some tips on how to take advantage of all the x-ms-webview has to offer.

Why did we build an HTML x-ms-webview?

When I talk to HTML developers about the new x-ms-webview control the most common initial reaction I hear is, “Why would I need that?” Because apps written in JavaScript already have the ability to host web content in an iframe element, it’s a great question. But iframes have several limitations that make embedding web content cumbersome, or even impossible, in certain situations. For example:

  • Framebusting sites – A lot of major web properties detect if they are being hosted in an iframe and simply don’t render. The x-ms-webview acts like a browser when communicating with the underlying content.
  • Document loading events – For iframes, detecting when content was loaded was either a waiting game or an art form. By trying to use postMessage() to detect when content the DOM content is loaded, the x-ms-webview exposes a rich set of events to make this deterministic for app development.

The x-ms-webview solves all these problems. Additionally the x-ms-webview provides new functionality that was never possible with an iframe:

  • Better access to local content – Access to local state folder content to load into x-ms-webview. This provides ebook readers with a means to render books that are stored locally.
  • Screenshots of web content – The ability to take a screenshot of the x-ms-webview content to make it easy provide content to the Share contract.

So to answer the original question, of why an HTML and JavaScript app needs a webview… All these features mean the x-ms-webview is simply the best way for your app to display web content.

What does the x-ms-webview look like?

Just to cover the basics, the Webview is an HTML element that’s part of the DOM for JavaScript apps. We use x-ms- appended to the x-ms-webview element name to denote this is a vendor specific HTML feature (e.g. “x-vendor-feature”). Using this element should seem familiar as the syntax is similar to an iframe.

HTML element

<x-ms-webview id="webview" src="http://www.bing.com"></x-ms-webview>

JavaScript

var webview = document.createElement("x-ms-webview");

Adding a basic x-ms-webview control to the default.html page in a Windows Store app written in JavaScript looks like this:

HTML

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8" />

<title>WebView</title>

<!-- WinJS references -->

<link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />

<script src="//Microsoft.WinJS.2.0/js/base.js"></script>
   1:  

   2:  

   3: <script src="//Microsoft.WinJS.2.0/js/ui.js">

   1: </script>

   2:  

   3: <!— app references -->

   4:  

   5: <link href="/css/default.css" rel="stylesheet" />

   6:  

   7: <script src="/js/default.js">

</script>

</head>

<body>

<x-ms-webview id="webview" src="http://www.bing.com" width="500px" height="500px"></x-ms-webview>

</body>

</html>

When simply adding a x-ms-webview control, the default size is 100px by 100px. You can specify the width and height just like an iframe, or you can use CSS styles for the iframe.

Navigation with x-ms-webview

Now that you have a sense for the x-ms-webview control and how it loads content, understanding the navigation workflow helps you control when things happen. One common problem for Windows 8 developers, when incorporating web content in their apps, was detecting when the entire DOM was loaded in order to start manipulating DOM objects or executing JavaScript. x-ms-webview supports the navigation flow events, as well as the navigation history, in order to give you control over web content loading in your app.

Navigation history properties and methods

Navigation history properties and methods

API for handling x-ms-webview navigation

navigate() – When you call this API you can also subscribe to these events that are raised during a Navigation request:

DOM event name

Description

MSWebViewNavigationStarting

Indicates the WebView is starting to navigate

MSWebViewContentLoading

The HTML content is downloaded and is being loaded into the control

MSWebViewDOMContentLoaded

Indicates that the main DOM elements have finished loading

MSWebViewNavigationCompleted

Indicates the navigation is complete, and all media elements are rendered

MSWebViewUnviewableContentIdentified

The WebView found the content was not HTML

In addition to these events in case the site being loaded has iframes there is another set of events exposed for you to detect sub content loading via iframes:

DOM event name

Description

MSWebViewFrameNavigationStarting

Indicates an iframe within a WebView is starting to navigate

MSWebViewFrameContentLoading

The HTML content is downloaded and is being loaded into the control iframe

MSWebViewFrameDOMContentLoaded

Indicates that the main DOM elements have finished loading in the iframe

MSWebViewFrameNavigationCompleted

Indicates the navigation is complete, and all media elements are rendered in the iframe

x-ms-webview navigation history. Detecting if a user has navigated inside the x-ms-webview is simple with these properties and methods.

Properties:

  • canGoBack – returns true/false if the control can navigate back.
  • canGoForward – returns true/false if the control can navigate forward.

Methods:

  • goBack() – Navigates the control to the previous location.
  • goForward() – Navigates the control to the next location.

JavaScript navigation history

HTML



<body>

<p>Content goes here</p>

<x-ms-webview id="webview" src="http://t.msn.com"></x-ms-webview>

<div id="webviewNavigationButtons"><button id="goBack" onclick="goBack()" disabled>Back</button><button id="goForward" onclick="goForward()" disabled>Forward</button></div>

</body>


CSS

#webview{

width:500px;

height:500px;

}

button{

margin-right:15px;

}

JavaScript

webview.addEventListener("MSWebViewContentLoading", webViewContentLoading);

function webViewContentLoading(e) {

document.getElementById("goBack").disabled = !webview.canGoBack;

document.getElementById("goForward").disabled = !webview.canGoForward;

}

function goBack() {

webview.goBack();

}

function goForward() {

webview.goForward();

}

Content sources

Now that we know the WebView is a straightforward HTML element, let’s look at the types of content you can load into a x-ms-webview and the different methods available for each.

Graphic showing the methods designed for internet and local content navigation

Graphic showing the methods designed for internet and local content navigation

Internet content

Integrating online content from the internet is the most common way to use an x-ms-webview. For example, one of the demo apps we built for Build 2013 showed a local product catalog, that used an x-ms-webview to handle the customer checkout with an existing website. For more details, see John Hazen’s Build talk, WebView: Bringing the Web to Your App.

One way to load web content in an x-ms-webview is to set the src attribute on the HTML element. Setting the src attribute automatically calls the navigate() method and passes in the attributes URI string.

<x-ms-webview id="webview" src="http://www.bing.com"></x-ms-webview>

Another way to load web content is to call navigate() directly. The x-ms-webview control navigates and loads websites, even ones that traditionally wouldn’t be loaded by an iframe due to framebusting.

NOTE: If the src attribute of the HTML element is set, and a call is made to the navigate method on load of an app, double navigation occurs.

Navigation supports different protocols to access both web and local content. JavaScript examples are provided for each protocol.

This table contains the different URI schemas supported by x-ms-webview. See MSDN for more details about these URI schemas.

URI schema

Description

http://

Arbitrary web content

https://

Web content over secure socket layer

ms-appdata:///

Content placed in the app’s local state folder

ms-appx-web:///

Content a developer has included within their app package but should be treated as web content. This HTML cannot access Windows RT APIs

ms-local-stream://

Content a developer has loaded into a memory stream

JavaScript navigation to web content

//Navigate the webview

webview.navigate(new Windows.Foundation.Uri("http://www.msn.com"));

//Navigate to SSL content

webview.navigate(new Windows.Foundation.Uri(https://www.facebook.com));

navigateWithHttpRequestMessage() – The control supports adding HTTP request information before navigating. This allows the server to potentially take action on the request before returning content.

JavaScript – Get example

// Create a URI describing the site to navigate to

var siteUrl = new Windows.Foundation.Uri("http://www.msn.com");

// Specify the type of request

var httpRequestMessage = new Windows.Web.Http.HttpRequestMessage(Windows.Web.Http.HttpMethod.get, siteUrl);

// Append headers to request the webserver to check against the cache

httpRequestMessage.headers.append("Cache-Control", "no-cache");

httpRequestMessage.headers.append("Pragma", "no-cache");

// Navigate the WebView with the request info

webview.navigateWithHttpRequestMessage(httpRequestMessage);

JavaScript – Post example

// Create a URI describing the site to navigate to

var siteUrl = new Windows.Foundation.Uri("http://www.msn.com");

// Specify the type of request

var httpRequestMessage = new Windows.Web.Http.HttpRequestMessage(Windows.Web.Http.HttpMethod.post, siteUrl);

// Set post data

httpRequestMessage.Content = new Windows.Web.Http.HttpStringContent("cookie=abcxyz123");

// Navigate the WebView with the request info

webview.navigateWithHttpRequestMessage(httpRequestMessage); webview.navigateWithHttpRequestMessage(httpRequestMessage);

Local content

You can also point an x-ms-webview at locally stored content that was either included in your package, or downloaded into a local state folder. Creating offline experiences for apps helps to ensure no matter what a person’s connected state is, you’re still able to provide an optimal app experience. A common scenario for this is to enable a game to run when not connected to the network.

In other cases your app might need better performance for loading and rendering content that can only be achieved through local content. A common scenario for this pattern is creating an electronic publication (EPUB) reader. EPUB 3 formats support rich HTML 5, CSS, and JavaScript content, which is easily displayed in the x-ms-webview control. Let’s look at the APIs you can use to load local content into the x-ms-webview.

JavaScript – Navigating to local content

//Navigate to content included in your appx package

webview.navigate("ms-appx-web:///localPage.html");

//Navigate to content stored in your local state directory

webview.navigate("ms-appdata:///local/MyAppsLocalFolder/local.html");

JavaScript – Navigating to local content

While the simple example above works, you can use this example to create a simple HTML file in your local state directory.

// Vars for local storage

var applicationData = Windows.Storage.ApplicationData.current;

var localFolder = applicationData.localFolder;

// Write HTML file locally

function writeLocalHTMLThenNavigate() {

localFolder.createFolderAsync("MyAppsLocalFolder", Windows.Storage.CreationCollisionOption.openIfExists).then(function (folder) {

localFolder.createFileAsync("MyAppsLocalFolderlocal.html",

Windows.Storage.CreationCollisionOption.replaceExisting).then(function (htmlFile) {

var html = "<!DOCTYPE html><html><head>";

html += "<title>Local HTML Content</title></head>";

html += "<body><h1>Local HTML Content</h1></body></html>";

Windows.Storage.FileIO.writeTextAsync(htmlFile, html).then(function (e) {

document.getElementById("webview").navigate("ms-appdata:///local/MyAppsLocalFolder/local.html");

});

}).done(function () {

console.log("Local.html file created successfully.");

});

})

}

writeLocalHTMLThenNavigate();

navigateToLocalStreamUri() – This method provides the ability to intercept content before it’s loaded into the control. A common scenario is to decode local content before the output is sent to the x-ms-webview. An IUriToStreamResolver must be written in either C#/VB, or C++, so JavaScript developers need to include an extra project type in order to utilize this functionality. The SDK has an example of this baked in.

Example – Calling a navigateToLocalStreamUri from JavaScript, relies on underlying C# code to perform the stream resolution. For the complete example, look at the SDK.

JavaScript – Navigating to a stream

function navigateToStreamWithCSResolver() {

var contentUri = document.getElementById("webview").buildLocalStreamUri("NavigateToStream", "simple_example.html");

var uriResolver = new SDK.WebViewSampleCS.StreamUriResolver();

document.getElementById("webview").navigateToLocalStreamUri(contentUri, uriResolver);

}

navigateToString() – Constructing and rendering dynamic HTML is common for apps that want to use HTML layout for a small amount of content, either for a quick overlay of content, or a rich in-app ad experience.

JavaScript – Navigating to string HTML content

var strHTML = "<!DOCTYPE HTML>";

strHTML += "<HTML>";

strHTML += "<HEAD><TITLE>NavigateToString() Example</TITLE></HEAD>";

strHTML += "<BODY><H1>HTML markup from a string</H1></BODY>";

strHTML += "</HTML>";

webview.navigateToString(strHTML);

App to WebView communication

It’s very common that your app will need to communicate with the web content within your x-ms-webview to create the appropriate user experience. You can communicate between the app and the website by integrating your app with Windows features like AppBar, Search charm, or Share charm to send messages between the two.

The invokeScriptAsync method is similar to using a postMessage() call into an <iframe> element.

The app is always allowed to use the controls invokeScriptAsync method call to execute script inside the embedded content. However, the embedded content has some restrictions when trying to send messages via the MSWebViewScriptNotify event to the parent app container.

Host app to webcontent communication graphic

Host app to webcontent communication graphic

This table shows when the webview control allows messages to flow to the parent app.

URI schema

MSWebViewScriptNotify

http://

No

https://

Yes*

ms-appdata:///

No**

ms-appx-web:///

Yes

ms-local-stream://

Yes

*Only if ContentURIs are declared in the Package.appxmanifest

**Can use a UriResolver to have ScriptNotify enabled

 

 

DOM event name

Description

MSWebViewScriptNotify

This event fires when a page inside the webview calls the window.external.notify method.

JavaScript

webview.addEventListener("MSWebViewScriptNotify", scriptNotify);

function scriptNotify(e) {

// check URI sending the notification

if (e.callingUri == "https://myUri.com") {

doSomething(e.value);

}

}

JavaScript

var operation = webview.invokeScriptAsync("startAnimation", "500");

operation.oncomplete = function (e) {

console.log(e.target.result);

};

operation.start();
Interacting with x-ms-webview content
Graphic showing the capturePreviewToBlogAsync method call to output image format

Graphic showing the capturePreviewToBlogAsync method call to output image format.

You can now get a screenshot of the content within an x-ms-webview built into the API. <iframe> can’t render arbitrary HTML into a bitmap. However, the x-ms-webview capturePreviewToBlobAsync() method allows for producing an image.

JavaScript

var operation = webview.capturePreviewToBlobAsync();

operation.oncomplete = function (e) {

var url = window.URL.createObjectURL(e.target.result);

document.getElementById("imagetag").src = url;

};

operation.start();
Graphic showing Selected HTML (text+image) to output in the host application

Graphic showing Selected HTML (text+image) to output in the host application.

You are able to easily share content from an x-ms-webview control via the Windows Share contract. A built in API can extract content selected by a user. This content can then be returned to your app for sharing with other apps that support the share target contract.

JavaScript – Get user selected content

var operation = webview.captureSelectedContentToDataPackageAsync();

operation.oncomplete = function (e) {

// Check for a valid selection

if (e.target.result) {

var data = e.target.result.getView();

if (data.contains(Windows.ApplicationModel.DataTransfer.StandardDataFormats.html){

// Data contains HTML, so grab it!

data.getHtmlFormatAsync().then(function (htmlFormat) {

var htmlFragment = Windows.ApplicationModel.DataTransfer.HtmlFormatHelper.getStaticFragment(htmlFormat);

document.getElementById("output").innerHTML = htmlFragment;

});

}

}

};

operation.start();

Want to learn more?

As you can see, the x-ms-webview is a powerful tool for displaying web content in your HTML and JS apps. If you already have a Windows 8 app that uses iframes to embed web content, I highly recommend updating to the x-ms-webview in Windows 8.1. And if you’re starting a new app, definitely use the x-ms-webview control from the beginning.

If you’re interested in learning more about x-ms-webview, check out these great links

-Kevin Hill, Senior Program Manager, Windows