May 2016

Volume 31 Number 5

[Universal Windows Platform Apps]

Hosted Web Applications for the Enterprise

By Tim Kulp | May 2016

Developers who work in a structured enterprise know that it’s not always easy to implement new technologies. Introducing something new to the enterprise like a Universal Windows Platform (UWP) app project can be a challenge when you don’t have teams versed (or confident) in their ability to deliver this type of app. Many enterprises have a significant investment in their intranet Web applications and the teams to support them. Hosted Web applications (HWAs) provide a bridge for enterprise intranet Web apps to join the Windows Store for Business with little effort.

In this article, I’ll convert an existing intranet Web application to a UWP app for the Windows Store and then enhance the app with native Windows functionalities. As shown in Figure 1, the Web application is a social recognition app called “Gotcha” that enables employees at Contoso Corp. to recognize their peers for acts of kindness or to show appreciation. Gotcha is meant to celebrate one another and build a stronger, happier team. This Web application is a great candidate for the Windows Store in that it provides easy integration with contacts, sharing and the camera.

Gotcha Web Application
Figure 1 Gotcha Web Application

Bridges and Hosted Web Applications for the Enterprise

For enterprise developers, UWP Bridges and HWAs make sense because developers can maintain their existing tools, processes and deployment systems for their apps. The concept driving Bridges is to enable developers to bring their existing iOS, Android, Win32 or Web applications to the UWP and the cross-platform Windows Store. The goal is to enable developers to bring their existing code base to the UWP with the ability to light up the user’s experience with features specific to Windows, such as Xbox achievements.

Bridges make bringing code to the UWP easy, but enterprise developers face other challenges that can make converting their code difficult. Developers in a corporation can face restrictions on what code editors are available to them, or where code can be deployed based on the sensitivity of the information within the application. The real value of UWP Bridges to the enterprise isn’t the ease of converting apps, but the value from the ability to maintain existing enterprise software development tools, practices and change management to deliver UWP apps via the Windows Store.

As an example of this, HWAs (aka “Project Westminster”) enable developers to embed Web applications into a UWP app. Once the UWP app is built to use the HWA content, developers can use their existing practices to maintain the Web application, which will automatically update the Web application experience of the UWP app. Using the HWA Bridge, developers can focus on their Web application and include features specific to UWP through feature detection. Working with an existing intranet is a great use case for UWP Bridges, but developers outside the enterprise also can leverage HWAs to take their Web apps into the Windows Store. Any Web site can become an HWA as long as that site passes the Windows Store certification process.

The basics of HWAs are covered thoroughly in Kiril Seksenov’s blog post, “Project Westminster in a Nutshell” (bit.ly/1PTxxW4). I recommend reading this post to get a deeper understanding of the ideas behind HWAs.

Starting a Web HWA Project

To start converting the Gotcha Web application to an HWA, I create a new JavaScript UWP App in Visual Studio. Once the app is created, I open the package manifest and set the app’s start page to be the URL of the Web application, as shown in Figure 2. In this case, the Gotcha Web application runs off of localhost:6107. With this start page set, the app will display the Web page at the specified address instead of the local content for the app.

Set the Start Page on the Package Manifest
Figure 2 Set the Start Page on the Package Manifest

Finally, set the content URIs in the package manifest. These URIs will tell your app what pages can access Windows Runtime (WinRT) libraries and what level of access those URIs can have. I’ve heard this described as defining where the app stops and the Internet starts, and I think of this as a great mental image of how to use content URIs. In the existing Gotcha Web application, there are clear distinctions between what the app does and what it can use the Internet to do. As an example, within Gotcha, users can share recognition to social networks like LinkedIn. The LinkedIn Web site isn’t part of the Gotcha UWP app; it’s part of the Internet. I would include only URIs that are directly used within the application and only those that need access to UWP APIs.

Using content URIs lets the developer protect the app’s users by preventing access to WinRT libraries for unregistered URIs. For each URI, specify which level of access to WinRT libraries is needed:

  • All: JavaScript code running on the Web application (in this case Gotcha) can access any and all UWP APIs that are defined through the App Capabilities.
  • Allow for Web Only: JavaScript code running on the Web application can execute custom WinRT components included in the app package, but can’t access all UWP APIs.
  • None: JavaScript code running on the Web application can’t access local UWP APIs (this is the default setting).

When setting content URIs, remember that this is a key component to application security for the UWP app user. Make sure to only provide the minimal permissions necessary to a URI for the necessary functions of the UWP app, as shown in Figure 3. Try to avoid setting the root URI WinRT Access to All if that’s not truly needed within the app.

Set Content URIs with the Least Privilege Needed to Run the App
Figure 3 Set Content URIs with the Least Privilege Needed to Run the App

I don’t recommend removing the existing content that comes with the project creation process (such as the .css, .js and WinJS folders). This existing content gives developers an excellent framework that can be used to add local content to the Web HWA. Later in this article, I’ll use these folders for local content to create some capabilities supplementing the Web HWA offline experience.

With the package manifest configured, run the UWP app. As shown in Figure 4, the Web application will now appear in an app window just like any other UWP app.

Gotcha App Ready for the Windows Store
Figure 4 Gotcha App Ready for the Windows Store

Debugging a Hosted Web Application

HWAs have a slightly different debugging experience than a pure native app. With the UWP app open, press F12. This will show the F12 Developer Tools for the UWP app. Through the F12 Developer Tools I can debug, profile and test the Web application just like I can in a browser. While all the features of the F12 Developer Tools are useful for HWA developers, the components I’ve found most useful are debugging outside of Visual Studio and profiling network activity. I use these features to dig into a specific app’s behaviors and understand any problems (like caching) that are providing an unexpected experience in the app.

Just like using F12 in the browser, developers can also alter the DOM and try out different UI experiences based on screen size or window size. This can be used to explore the layout changes of a Web application based on the responsive needs of the app. As an example, snapping the UWP app to display as a sidebar should reflow the app to present a great experience. If the resize doesn’t reflow the app, F12 Developer Tools can be used to determine why not and experiment with the DOM to see what’s needed to achieve the desired reflow.

Adding Functionality for Your UWP App

With a basic HWA ready, I’m going to dive into the Web application’s capabilities to enable some UWP APIs and light up the user’s experience. Intranet Web applications can have some limitations that HWAs don’t have. Using the UWP APIs, an HWA can have access to many of the local capabilities of the UWP device (such as camera, location and other sensors). To start, think about the use cases that are driving the implementation of the Web application to a hosted Web application. In the Gotcha app, I want users to be able to select from their Contacts who to give an award instead of just typing in the person’s name and attaching a picture to the recognition.

To start, I create a remote GotchaNative.js code file on the Web application (the GotchaNative.js script file will be on the remote Web application server) that’ll detect native API namespaces and execute the appropriate code to trigger our native use cases. Add the following code to the NativeGotcha.js code file:

var GotchaNative = (function () {
  if (typeof Windows != 'undefined') {
    // Add find contact here
    // Add capture photo here
  }});

This code builds the GotchaNative object, which will hold all the functionality of the UWP APIs. Centralizing these APIs allows for a single file to include on pages that will have added UWP API functionality. I isolate this file so that I can explicitly declare content URIs that include this specific file as URIs with access to the needed UWP APIs. This way I can implement the security concept of least privilege and only give permission to URIs that require access to the UWP APIs.

Another benefit of isolating this file is to prepare for other native platforms, as well. I’ll explore this later in the article but for now, consider this file to be the home for all native functionality that will be included in the Gotcha Web application.

Extending Existing Functionality

Now with the GotchaNative object created, I can add the specific functionality to connect the HWA to the UWP APIs. For the first use case, the Gotcha Web application lets users enter in a person to recognize. In the UWP, users have the People app that stores contacts and would be much easier for the user to select than to type in the person’s name. Replace the “Add find contact here” comment in the GotchaNative.js code file with the following:

this.FindContact = function () {
  var picker = new Windows.ApplicationModel.Contacts.ContactPicker();
  picker.desiredFieldsWithContactFieldType.append(
    Windows.ApplicationModel.Contacts.ContactFieldType.email);
  return picker.pickContactAsync();
}

This code is a basic connection to the ContactPicker API to select a contact from the list of contacts. A list of UWP APIs that can snap into Web HWAs can be found at rjs.azureWebsites.net. This Web site lists some of the more popular APIs with copy/paste-ready code to help build out a Web HWA project.

The functionality to add a person can be found on the Person View Model for the Gotcha Web site. Add the code in Figure 5 to the Person View Model.

Figure 5 Code to Add to Person View Model

if (Windows != undefined) {
  var nativeGotcha = new NativeGotcha();
  nativeGotcha.FindContact().done(function (contact) {
    if (contact !== null) {
      $("#txtWho").val(contact.displayName);
    } else {
      // Write out no contact selected
    }
  });
}
else {
  $('#add-person').on('shown.bs.modal', function () {
    $("#txtWho").focus();
}

The code in Figure 5 uses the FindContact method if the Windows object is defined due to the script running as an HWA. If the Windows object isn’t defined, then the Web application will continue to use the existing Bootstrap modal window to collect information about the person to recognize. This code enables the Web application to use one approach to enter a person for recognition while the UWP app can leverage a different, more tailored, experience for the user.

Adding New Functionality

Sometimes enabling the UWP APIs will allow new functionality that would not normally exist in the Web application. In the Gotcha HWA, I want to enable users to take pictures and send those photos for recognition to other Gotcha users. This functionality would be new to the application and wouldn’t exist in the Web application. When building an HWA, consider opportunities the UWP APIs open up for the app.

To start implementing this new functionality, first I replace the “Add capture photo” comment with the following code in the GotchaNative.js code file:

this.CapturePicture = function () {
  var captureUI = new Windows.Media.Capture.CameraCaptureUI();
  captureUI.photoSettings.format =
    Windows.Media.Capture.CameraCaptureUIPhotoFormat.png;
  return captureUI.captureFileAsync(
    Windows.Media.Capture.CameraCaptureUIMode.photo);
}

In this code, I open the capture UI, allow the user to take a picture and then return the picture to the caller. This new feature needs to be enabled on the Web application if the Windows object is defined. Using the feature detection like I did in the Person View Model, I add the code in Figure 6 to the Home View Model, which is where the code is for adding the recognition.

Figure 6 Feature Detection Code to Add to Home View Model

$('#give-modal').on('shown.bs.modal', function () {
  if (typeof Windows != 'undefined') {
    var gotchaNative = new NativeGotcha();
    $("#btnCamera").click(function () {
      gotchaNative.CapturePicture().then(function (capturedItem) {
        // Do something with capturedItem;
      });
    }).show();
  }
  else {
    $("#btnCamera").hide();
  }
})

In the code in Figure 6, I hide the btnCamera if the Windows object is undefined. If the Windows object isn’t undefined, then I configure the click event to trigger the CapturePicture function. For brevity, I’ve left a comment of what to do with the picture. With enabling the camera, I need to keep in mind that this HWA is still a UWP app and needs the Webcam capability enabled for the app, which can be done through the package manifest.

Enterprise Web applications can be converted to HWAs and leverage the UWP APIs of the Windows Store. Using existing Web applications makes it easy to build up UWP apps in the Windows Store, but HWAs assume an Internet connection. Next, I’ll show you how to ensure a working app even without Internet access.

Connecting Offline

The UWP app can have local files to provide an offline or local experience. Using local content lets you disconnect some of the UWP API calls from the hosted Web application. Like the feature detection that has already been done, linking to local content can be done through activating links. For Gotcha, I’ll add a mapping feature that’ll use the local mapping controls.

In the HWA, I can use the same feature detection that was used previously in the Home View Model. Using the right URI scheme will enable the HWA to jump between the Web content and local content. On the home screen I add the following link:

<a href="ms-appx:///default.html" id="lnkMap">
  <span class="glyphicon glyphicon-map-marker">&nbsp;</span> Show Map
</a>

The link connects to the ms-appx:/// scheme, which lets the application connect to local content within the application package. When working within the ms-appx scheme, the app can connect to the UWP APIs necessary. This is similar to using the content URIs to declare what level of access a page has for access to APIs. Using ms-appx is like marking a URI as All. In this case, the default.html page has access to the UWP APIs. When the link appears within the HWA, users can click it to work within the app package.

For enterprise developers, this feature allows isolation of use cases that are specific to the UWP and not necessarily connected to the Web application. Connecting to package content also can allow you to avoid providing access to the UWP APIs for the Web application and keep all that access within the package.

What About More Than One Store?

Depending on the enterprise, a Bring Your Own Device environment might exist. This means that an enterprise could already be targeting iOS or Android devices with existing apps. Android and iOS apps have concepts similar to HWAs called the WebView control. WebView lets developers provide a window within their app to an existing Web application and then interact with that Web application as if it were part of the native app (sound familiar?). HWAs can be built to play well with others, tailoring the functionality of an existing Web application to the platform delivering the Web app. Next, I’ll update GotchaNative.js to support Android and show how HWA code would live side-by-side with JavaScript targeting other platforms.

Earlier, I set up GotchaNative.js, which is meant to hold all the native code in the app. The ViewModels will process the output of these native methods. To use APIs in any platform is similar to HWAs:  First, the app must determine if the native APIs are available and then must call the appropriate API. To start updating GotchaNative.js, I’ll add a property that tells me what native platform (if any) is recognized. For the following examples, I’m assuming that the Android app is using a WebView that declares “Android” as the local script namespace:

this.Platform = function () {
  if (Windows != 'undefined')
    return "Windows";
  else if (Android != 'undefined')
    return "Android";
  else
    return "Web";
}

This function allows my code to determine which platform it’s going to be working with so that I can tailor code and response to the platform. From here, each method within GotchaNative.js can check for the platform to know how to proceed, as shown in Figure 7.

Figure 7 GotchaNative.js Methods Checking for the Platform

this.CapturePicture = function () {
  switch (this.Platform()) {
    case "Windows":
      var captureUI = new Windows.Media.Capture.CameraCaptureUI();
      captureUI.photoSettings.format =
        Windows.Media.Capture.CameraCaptureUIPhotoFormat.png;
      return captureUI.captureFileAsync(
        Windows.Media.Capture.CameraCaptureUIMode.photo);
      break;
    case "Android":
      Android.CaptureFile(); // Calls Android code in Native app
      break;
    default:
      return null;
      break;
}

Now in the ViewModels, the code would be updated to use the platform detection to know what to do with the output of the GotchaNative methods. The following is an update to the camera button event from the HomeViewModel:

$("#btnCamera").click(function () {
  switch (gotchaNative.Platform()) {
    case "Windows":
      gotchaNative.CapturePicture().then(function (capturedItem) {
        // Do something with capturedItem;
      });
      break;
    case "Android":
      // Handle Android output
      break;
  }
}).show();

Now, as the app supports more platforms, I have a single place in my code to grow the capabilities for all platforms. If a new hot OS comes out tomorrow, the development team will be able to adapt the code to the new platform.

Wrapping Up

Enterprise developers face numerous challenges in their work. Standardized processes and tools can be seen as a barrier to implementing new technologies like UWP apps. Using UWP Bridges, enterprise developers can bring their existing intranet or external Web apps to the Windows Store (either public or Windows Store for Business). Bridges for HWAs can turn a Web app into a cross-platform UWP app, leveraging the UWP APIs to light up the user’s experience.

In this article, I explored how to take an existing Web application and convert it to an HWA while adding UWP app-specific features like accessing the camera and contacts. Using the ms-appx scheme, I showed how to jump from your hosted Web application to local content within the app package. Finally, I showed, with some planning, how HWAs can be built with many different platforms in mind, allowing the enterprise to keep up with the ever-expanding world of mobile devices. Using these techniques, HWAs can leverage the existing investments in Web applications, helping enterprises join the Windows Store ecosystem.


Tim Kulp is a senior technical architect living in Baltimore, Md. He is a Web, mobile and UWP developer, as well as author, painter, dad and “wannabe Mad Scientist Maker.” Find him on Twitter: @seccode or via LinkedIn: linkedin.com/in/timkulp.

Thanks to the following Microsoft technical expert for reviewing this article: John-David Dalton and Kiril Seksenov


Discuss this article in the MSDN Magazine forum