Hybrid Mobile App with Umbraco, Cordova and AngularJs

Hybrid apps present the best of both worlds when it comes to mobile app development; you can write in familiar web technologies such as HTML, CSS and JavaScript and still leverage some native functionality on mobile devices.

Cordova (formerly Phone Gap) is an open source framework which allows cross platform hybrid native app development without having to delve into native languages such as Objective C or Java development.

Now Visual Studio 2015 ships with Project Templates for Cordova which makes set-up and development that much easier. Cordova requires quite a few pieces to get working and fortunately Visual Studio will take care of this for you. If the template has not already been added it will inspect your machine for all the prerequisites and fetch any that are not already on your development machine.

A Cordova app is essentially just a web page running locally on the mobile device in a web-view. This means you can work as you would normally for a website but also make use of the native functions assuming there is an API available in Cordova.

In this example we want to use Umbraco as a service provider for our mobile app content. The first task is therefore to implement a Web Service with Umbraco and WebAPI. Initially this may be useful simply to allow more client side features by consuming the API with AngularJs within the site, the added benefit being we can then re-use the service for our mobile app.

As a simple example we have a controller that uses the UmbracoApiController to fetch some data for our app.

public class ContentController : UmbracoApiController 
{
    [HttpGet]
    [AllowCors]
    public ListResultViewModel Search(string query) 
    {
        SearchService _searchService = new SearchService();
        ISearchResult result = _searchService.GetResults(query);

        return result;
    }
}

This controller action represents our API endpoint that will be available on

http://YOURDOMAIN/umbraco/api/content/search?query=somequery

Next a simple AngularJs app can connect to the end point to display the data.

amlApp.controller('search', ['$scope', 'Search', 'Item', function ($scope, Search, Item) {

    $scope.Search = new Search(); 
    $scope.Search.load();
}]);

amlApp.factory("Item", [function () {
    
    function Item(title, summary) {
        this.Title = title;
        this.Summary = summary;
    }
    
    return Item;
}]);

amlApp.factory('Search', ['$http', 'Item', function ($http, Item) {

    var Search = function () {
        this.items = [];
    };

    Search.prototype.load = function () {
        var url = 'http://YOURDOMAIN/umbraco/api/content/search?query=';

        $http.get(url).success(function (result) {
            angular.forEach(result.Items, function (item, index) {
                var listitem = new Item(item.Title, item.Summary);
                this.push(listitem);
            , this.items);
        ).bind(this)); };

return Search;

}]);

The main advantage here is that we can write the AngularJs app and it's related mark-up for our website and then reuse it with minimal modification within our app.

Now we create a new Cordova Project in Visual Studio this will generate the basic structure required for Cordova. The www folder is where most of the development work will be carried out.

Here you can just modify the HTML,CSS and JS files to create the app. The index.html file will look like a familiar bare bones web page, the main differences being the inclusion of cordova.js.

When using Umbraco as an endpoint for Cordova we need to get around problems with CORS or Cross Origin Resource Sharing. There are 3 places that you will need to configure CORS in your app; first the meta tag on the index.html page this sets up the general content security policy for the app itself.

<meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'">

Second is the config.xml file, in a corodova app this is where you will setup any plugins and any general settings. Here there is a plugin called cordova-plugin-whitelist which allows you to specify a white list of domains that your app can access. The following line indicates any domain on http can be accessed:

<plugin name="cordova-plugin-whitelist" version="1" />
<allow-intent href="http://*/*" />

Finally the endpoint that you connect to, in this case is a site you control so you need to send the correct headers in your web API response to allow access.

There is a nuget package to enable CORS for WebAPI2 available this requires MVC 5 which Umbraco 7.3.1 now supports. This allows a simple data attribute to be added to the web API methods, which will set the correct response headers to get around the issue.

using System.Web.Http.Cors;

[EnableCors]
public ListResultViewModel Search(string query)

I did find that even after upgrading and installing the package the correct headers are not being added as expected.

This is not a problem however since all we really want to do is implement a custom filter. This can be as basic or as complex as you like but it will give you some control over what methods you mark as Cross Origin.

public class AllowCorsAttribute : ActionFilterAttribute 
{
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        if (actionExecutedContext.Response != null)
        {
            actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
        }

        base.OnActionExecuted(actionExecutedContext);
    }
}

Once this is in place you should be able to call your WebAPI methods from Cordova without issue.

With all the pieces in place you can now test out the app, the easiest method is to use Ripple which comes with the project template, this allows the app to run in the browser as if it was a native application and lets you interact with it in a limited way.