Fifteen years ago, launching a product meant writing a Windows application. Ten years ago, it meant writing a website that worked on Internet Explorer. Today, launching a successful product means targeting Mac and Windows, and iOS and Android. And it may also mean targeting tvOS, WatchOS, Tizen, XBOX, Windows Phone, maybe more. It's mind boggling how much times have changed.

In previous articles, I've made the case for looking at Angular2 and Typescript, along with Cordova and Electron as a strategy to lower the learning curve and associated costs in targeting multiple platforms. Yes! It's true: write once, run everywhere is finally a reality. You can't target all relevant platforms with a single codebase, and the application looks good, looks consistent, and performs quite well.

But a few years ago, targeting multiple platforms effectively meant that you had to write code for each platform separately. In other words, you wrote “native” code, and didn't use Web-based technologies. The argument in favor of native is that it provides better performance and better access to leading-edge features on the respective platforms.

But writing native has two huge disadvantages: a much higher learning curve and associated costs.

What if you could have the best of both worlds? Write in C# and run everywhere as native applications. That's the value of Xamarin. Xamarin, now part of Microsoft, is an incredible alternative that lets you use one language and one code base and target multiple platforms. So why would you not just use Xamarin, always?

Always! You'll never hear a good developer use that word, although I sometimes run into naysayers. They insist that if you aren't doing 100% native, you're doing it wrong. There's an almost religious war between these two camps. The reality is that good developers take advantage of both platforms where suitable.

In this article, I intend to make the case that it is possible to build your mobile app using the best of each technology. Although Xamarin is great, it has its foibles. Although Cordova is great, it too has foibles. Sometimes mixing the two together gives you the best possible results. I intend to make this case with a sample application written in both Cordova and Xamarin. This sample application has one simple task: to send substantial amounts of data back to the server.

Strengths and Weaknesses

This is perhaps the hardest section to write in this article; I'm presenting strengths and weaknesses on a topic fraught with religiously held opinions and all without proof. Please humor me, as this section is the opinion of one person. The proof is coming shortly.

Vendor Native

By vendor native, I mean Swift or ObjectiveC for iOS and MacOS, Java for Android, and C# and XAML for Windows. The advantage here is best-of-breed performance, the smallest binaries, and the best support from the associated vendor. The disadvantage is having to learn three different platforms, maintain three code bases, and fix the same bug three times, with bonus bugs on top. This approach is expensive.

Xamarin

Using Xamarin means that you write your code in C# but it compiles down to native. The disadvantage is that you'll have a more complex project structure, a more complex dev environment - especially when you need to target iOS from Windows - and performance, though good, is not as good as pure native. Binary sizes are decent, but they're usually larger than pure native.

Also, although it's not technically a disadvantage, it's a fallacy to assume that you won't have to learn the platform intricacies just because you are using C#. The reality is that you still need to understand platform-specific details such as keychain stores, app bundle identifiers, provisioning profiles, and a lot more that comes with any associated platform. Frankly, sometimes the only difference between writing an iOS app using Xamarin and C# and using XCode and ObjectiveC feels like the language. In fact, for 90% of the time I'm stuck on a Xamarin issue, I run a search on the Internet and find an ObjectiveC solution; my workflow is a bit like Google > copy/paste > translate ObjectiveC to C#. The language, for the most part, feels like the only major difference. Mind you, that?s not a small difference! ObjectiveC is a language only a mother could love. (Swift is not so bad.)

Objective C is a language only a mother could love.

Xamarin Forms

This section will probably get me in the most trouble, but it deserves to be called out. Xamarin forms, in my opinion, have some major disadvantages. XAML (and for that matter even vendor-native controls) are okay at building a UI quickly. However, a significantly branded app is almost never easy to build using XAML.

I realize that there are some XAML experts who've already pulled out their pitchforks. But when it comes to pure developer productivity when comparing HTML5/CSS3 versus XAML, HTML wins hands down. I agree that XAML gives you more fine-tuned control, but HTML adapts better to “reflow” and multiple form factors. The whole issue I'm trying to solve here is maximum reach with minimum effort and cost. On that front, writing up an HTML-based UI is almost always a better choice than trying to do the same thing in XAML or dragging-and-dropping a button and then trying to make that button style completely not like a button. Nobody wants a boring UI, and it might take some real effort to make this button interesting.

The other disadvantage of Xamarin forms is bloat. This productivity abstraction layer creates larger binaries, which, in turn, can affect performance and load times. There are some solutions to this in the linking process, however.

Finally, Xamarin forms is newer than Xamarin itself, so a lot of things you want in a full UX control set are missing. This is a problem that I'm sure will get fixed in due time.

I'm not saying that Xamarin forms are never suitable. If you want a user interface that can be built nicely with drag-and-drop controls with some basic positioning, that doesn't target too many form factors, and isn't heavily branded, it might be okay! In enterprise dev scenarios, sometimes creating numerous functional apps quickly matters more than creating the best-looking apps. But for the typical mobile app that needs ooohs and aaahs, I find that Xamarin Forms are not the easiest route to success, at least not today.

Cordova and Web technologies

The biggest advantage of using Cordova is that these skills are the easiest to find and learn. Also, good-looking user interfaces built using HTML-based technologies can run everywhere, and can be built by people who aren't experts at XCode, Storyboards, or XAML. You can split the problem into smaller manageable chunks and cut your work according to your people, not the other way around. Also, with Angular and Typescript, it's possible, in a practical manner, to write code for mobile and have it run on desktop, and vice versa.

The biggest disadvantage here is performance. But let's dissect this further. Performance, although important, isn't everything. Rather, let's put it this way: your team's performance is important too. For instance, let's talk about HTML's biggest advantage: a cross-platform, responsive user interface that?s attractive and easy to build.

It's true that pressing an HTML div that's disguised as a button may take five milliseconds more than, say, a pure native button. But the important take-away here is that the user's not going to care about or even notice five milliseconds. Of course, if you did a button press 100,000 times in a loop, those five milliseconds add up to something substantial, and then the user will notice and care.

JavaScript engines have gotten pretty good. Your regular business logic, such as those that enable a textbox when the checkbox is checked, etc., run pretty much as fast as native. Where you pay a huge penalty is when you start marshalling between JavaScript to native and vice versa. Especially when you start marshalling in a loop.

That's the number one target you need to address: where you marshal across JavaScript to a native boundary repeatedly over thousands of times, a Cordova operation could amount to delays measurable in seconds, if not worse. This is something that the user will notice.

The other situation you need to consider are specific UI elements, such as scrolling list views with large amounts of data, or map applications with pan and zoom elements that have very large images; the sorts of things that could be done in HTML but are done better in native. The good news is that Cordova applications let you replace one screen with native implementation, one UI element with native implementation, or they simply ditch the whole Cordova shell and still use the same concept to write hybrid apps in either vendor native, or using Xamarin.

The Important Take-Away

The important take-away here is that every technology has its strengths and weaknesses. And the mobile application development landscape is changing rapidly, so what's true today in this article may change a year from now. I feel that crafting up your UX in HTML is a very viable approach, as long as you know when to drop HTML and JavaScript and dive into native code.

You've probably heard that dropping into Native code is expensive, and that you have to write it three times in three different platforms. It's not the case! This is where Xamarin comes into the picture. You write your code once, as a combination of C#/Xamarin, and HTML, CSS, and JavaScript.

With judicious mix-and-match, you now have the performance of native and the flexibility of HTML, all with a single code base. Simply amazing!

The App

I'm going to illustrate my argument here by building an app that posts data to a Web API written in ASP.NET. To keep things germane, I'm keeping the WebAPI extremely simple. There's no authentication and there's no complex payload. It's just a simple action that accepts a string on HTTP POST. This reflects a real-world scenario, where the app has a large payload to post. The app isn't going to post that entire payload in one request. This not only has memory implications on the mobile device, but the request itself may time out. You want to break apart that request into smaller portions. The Web API can be seen in Listing 1.

Listing 1: A very simple Web API

public class TestController : ApiController
{
    public void SubmitData(string inputData)
    {
        System.Diagnostics.Debug.WriteLine(inputData);
    }
}

This API can be called on a URL like this:

/api/test/SubmitData?inputData="sampleinput"

With the API out of the way, let's write the apps. The app does a very simple task: It calls the API 10,000 times. You'll measure the time it took to send those requests; note that you're not interested in measuring how long it actually took for the server to respond. You're only interested in the operation of firing these requests. The reason you want to measure the time it took only to send the requests is so that you can get a decent comparison of native versus JavaScript, and see if there's any merit to all the fuss some people are making regarding native performance being better. You don't want network traffic or other such extraneous factors to affect this measurement.

The Cordova App

I'm going to skip over Cordova basics here and just talk of the main steps I took to create the app.

I first created a basic Cordova project and then added jQuery into it. I cleaned up the user interface to remove that device-ready message that the starter Cordova app shows, and instead added a button and a div, as shown in this snippet:

<div id="deviceready">
    <br/>
    <button id="sendDataButton">
        Send Lots of Data</button>
    <div id="sendDataButtonLog"></div>
</div>

Also, because I intend to make HTTP calls from the application, I added the following to the “Content-Security-Policy” meta tag:

;connect-src http://*/*

Note that the above is very insecure: it allows calls to any HTTP URL. It's okay for testing purposes.

Next, let's modify the JavaScript portion of the code. The idea is that when the sendDataButton is clicked, you wish to fire off 10,000 POST requests and measure how long it took to send those requests. You don't care about how long it takes for those requests to return.

The first thing to do here is to add an event handler for the sendDataButton click event. You can do this in the initialize function, as shown in this next snippet:

$("#sendDataButton").bind('click', app.sendData);

As you can see, clicking the button calls a function called sendData on the app object. This function can be seen in Listing 2.

Listing 2: The sendData function

sendData:function() {
    var now = window.performance.now();
    var deferreds = [];
    var i = 1;
    for (i = 1; i <= 10000; i++) {
        deferreds.push(sendDataChunk());
    }
    var then = window.performance.now();
    document.getElementById(
        "sendDataButtonLog").innerHTML =
        "Total time (ms): " + (then - now);

    $.when.apply($, deferreds).done(function() {
        // you can check for total time
        // for request to complete here.
    });
    function sendDataChunk() {
        var deferred = new $.Deferred();
            var postUrl = "..removed..";
            $.ajax({
                type: "POST",
                url: postUrl,
                success: function() {
                    deferred.resolve();
                }
            });
        return deferred;
    }
}

As Listing 2 shows, you're firing off 10,000 requests, but you don't wait for them to finish. You're simply interested in measuring the time it took to fire off the requests. In doing so, you're going from JavaScript to native, although all of this is implemented in the WebBrowser itself. You can imagine that going to the Cordova shell would probably be an even more expensive operation. An example of going to the Cordova shell might be calling the Camera API, or perhaps some offline data store API other than window.localStorage.

Now, go ahead and run the application. It shows you a user interface with a button that says “Send Lots of Data.” Press that button, and the application informs you of how long it took to send 10,000 requests.

Figure 1: The Cordova app took some time to send the data
Figure 1: The Cordova app took some time to send the data

10,000 requests are quite a bit, so, as can be seen from Figure 1, it took nearly 14 seconds to send these requests. Now let's repeat this example using native code written in Xamarin.

The Xamarin Hybrid App

Instead of writing a full Xamarin forms-based app, I instead choose to write a hybrid app. A hybrid app, in this case, is a Xamarin app that uses Web-based technologies for its user interface and basic business logic. It has the ability to ask Xamarin native code to do heavy lifting wherever necessary. For instance, here I ask the native code to make the POST requests for us. This is a very good approach because now I can move back and forth between Cordova apps and custom Xamarin Hybrid apps.

What about plug-ins? Aren't plug-ins how you're supposed to target native capabilities in Cordova? Indeed, plug-ins are one way to the goal, but plug-ins usually still mean that you have to write the plug-in in multiple platform-specific languages. This brings me back to my original problem of avoiding multiple code-bases. I could write a plug-in using Xamarin, but in its current incarnation, Xamarin likes to own the entire project. The project structure is not the most conducive to writing a Cordova plug-in. Or I could rely on the community to provide a plug-in for me. But those plug-ins are written for the most generic circumstances.

Aren't plug-ins how you're supposed to target native capabilities in Cordova?

For instance, imagine that my requirement was to search an offline store using a key. I could use a plug-in to read the entire offline store, and then run it in a loop, going over the JavaScript/native firewall over and over again, and paying a big performance penalty. Although this is a contrived example, and for such common scenarios, plug-ins exist that let you pass in the Search key once. Because the iteration is done purely in native code, it's quite conceivable that a plug-in matching your specific business requirement doesn't exist.

You could write it using ObjectiveC, Java, WinJS, and God knows what else! Or, you could avoid that complexity all together and use Xamarin for native, and HTML and JavaScript for UI and basic business logic. At least, that's what I like to do, because it seems to be the path to success that requires the least effort.

Let's get started.

The first thing to do is to create a Xamarin project. Start Visual Studio for Mac (if you have a Mac), or just Visual Studio with Xamarin tools installed, and choose to create a Forms App project using C#. Ensure that the shared code project is a portable class library, and choose to use XAML for user interface files. Call this project HybridView.

Once the project is created, you should see a project structure like that shown in Figure 2.

Figure 2: The Xamarin app project structure
Figure 2: The Xamarin app project structure

Next, in the HybridView project, add a new class called HybridWebView, and put the code shown in Listing 3 into it.

Listing 3: The HybridWebView view.

using System;
using Xamarin.Forms;

namespace HybridView
{
    public class HybridWebView : View
    {
        Action<string> action;
        public static readonly BindableProperty UriProperty =
        BindableProperty.Create(
            propertyName: "Uri",
            returnType: typeof(string),
            declaringType: typeof(HybridWebView),
            defaultValue: default(string));

        public string Uri
        {
            get { return (string)GetValue(UriProperty);}
            set { SetValue(UriProperty, value) ;}
        }

        public void RegisterAction(Action<string> callback)
        {
            action = callback;
        }

        public void Cleanup()
        {
            action = null;
        }

        public void InvokeAction(string data)
        {
            if (action == null || data == null)
            {
                return;
            }
            action.Invoke(data);
        }
    }
}

As you can see from Listing 3, you're creating a simple view that accepts a URI as a bindable property. Also, it allows you to invoke an action. The idea is that you can specify what page to load using the bindable property, and that page can invoke native code functionality using the action.

Next, use this view in the HybridViewPage ContentPage. Go ahead and edit its XAML portion, as shown in Listing 4.

Listing 4: The HybridViewPage.xaml file

<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml";
             xmlns:local="clr-namespace:HybridView"
             x:Class="HybridView.HybridViewPage">
    <ContentPage.Content>
        <local:HybridWebView x:Name="hybridWebView" Uri="index.html"
                         HorizontalOptions="FillAndExpand"
                         VerticalOptions="FillAndExpand" />
    </ContentPage.Content>
</ContentPage>

As can be seen from Listing 4, I'm using the View I created and I'm pointing it to a file called index.html. I'll create this file in the HybridView.iOS/Droid projects and embed it as content. You can also load a file over HTTP, but I doubt that Apple would be too pleased with such an app and you run a high risk of app rejection.

Next, you need to handle the action that can be invoked by the JavaScript code, and in native code, fire off 10,000 POST requests and measure the time it took to send those requests. As before, you won't wait for the results to return. This code goes in the HybridViewPage.xaml.cs file, and can be seen in Listing 5.

Listing 5: HybridViewPage.xaml.cs

using System.Net;
using Xamarin.Forms;

namespace HybridView
{
    public partial class HybridViewPage : ContentPage
    {
        public HybridViewPage()
        {
            InitializeComponent();
            hybridWebView.RegisterAction(data => sendData());
        }

        private void sendData()
        {
            var now = System.DateTime.Now;
            string url = "..removed..";
            for (int i = 0; i < 10000; i++)
            {
                HttpWebRequest request = (
                    HttpWebRequest)WebRequest.Create(url);
                request.Method = "POST";
                request.BeginGetResponse((ar) =>
                    System.Diagnostics.Debug.WriteLine(
                        "end:" + ar.AsyncState.ToString()), i);
            }
            var then = System.DateTime.Now;
            DisplayAlert("Alert",
            "Total time (ms):" +
            (then - now).TotalMilliseconds,
            "OK");
        }
    }
}

Great! All that's left to be done is to create a simple index.html file that can call this action, and a view renderer that can load this HybridWebView view. Let's first create the view renderer as a class in the HybridView.iOS project, which can be seen in Listing 6.

Listing 6: The HybridWebViewRender

using System.IO;
using HybridView;
using HybridView.iOS;
using Foundation;
using WebKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(HybridWebView),
    typeof(HybridWebViewRenderer))]
namespace HybridView.iOS
{
    public class HybridWebViewRenderer :
        ViewRenderer<HybridWebView, WKWebView>, 
            IWKScriptMessageHandler
    {
        const string JavaScriptFunction =
        "function invokeNativeCode(data){
        window.webkit.messageHandlers
        .invokeAction.postMessage(data);}";
        WKUserContentController userController;

        protected override void OnElementChanged(
            ElementChangedEventArgs<HybridWebView> e)
        {
            base.OnElementChanged(e);

           if (Control == null)
           {
               userController = new WKUserContentController();
               var script = new WKUserScript(
                   new NSString(JavaScriptFunction),
                       WKUserScriptInjectionTime.AtDocumentEnd, false);
                       userController.AddUserScript(script);
                   userController.AddScriptMessageHandler(this,
                       "invokeAction");

                   var config = new WKWebViewConfiguration {
                       UserContentController = userController };
                   var webView = new WKWebView(Frame, config);
                   SetNativeControl(webView);
            }
            if (e.OldElement != null)
            {
                userController.RemoveAllUserScripts();
                userController.RemoveScriptMessageHandler("invokeAction");
                var hybridWebView = e.OldElement as HybridWebView;
                hybridWebView.Cleanup();
            }
            if (e.NewElement != null)
            {
                string fileName =
                    Path.Combine(NSBundle.MainBundle.BundlePath,
                        string.Format("Content/{0}", Element.Uri));
                        Control.LoadRequest(
                          new NSUrlRequest(new NSUrl(fileName, false)));
            }
        }

        public void DidReceiveScriptMessage(
            WKUserContentController userContentController,
            WKScriptMessage message)
        {
            Element.InvokeAction(message.Body.ToString());
        }
    }
}

For the index.html, create a folder called Content in the HybridView.iOS project and drop an index.html in that folder. Make sure that its build action is set to Content, as can be seen in Figure 3.

Figure 3: Build action for the index.html file
Figure 3: Build action for the index.html file

All that's left now is to put some simple code in the html file that calls the native function, which can be seen in the next snippet:

<button type="button" onclick="invokeNativeCode('hello');">
    Invoke Native Code
</button>

Go ahead and build this app and run it in the same simulator or device that you ran the Cordova project in. The user interface shows you a button that you can click on. Go ahead and click on it. Clicking on the button fires off 10,000 POST requests, and shows you the time taken for those requests to be sent. This can be seen in Figure 4.

Figure 4: The Xamarin app doing the same job as the Cordova app
Figure 4: The Xamarin app doing the same job as the Cordova app

As is quite clear, the Xamarin app, being native, is orders of magnitude faster than the Cordova app. Subsequent executions show that the Xamarin app for this specific task is four to 15 times faster. That is quite a bit - it's performance that the user will notice.

But let me qualify that; you're still using an HTML-based user interface. I'm sure you're paying a slight performance penalty for it, but, the user doesn't notice the extra five milliseconds it took to click an HTML button versus a native button. In fact, in many instances, an HTML UI may perform better than a native UI.

Being able to mix and match when creating a UI in Web technologies gives you a lot of flexibility in crafting a responsive, reflowable UI using a single portable skillset.

But the main point here is that being able to mix and match when creating a user interface in Web technologies gives you a lot of flexibility in crafting up a responsive, reflowable user interface using a single portable skillset. Where you need to dive into native, you do so using Xamarin. This gives you the best of all the worlds.

Although I'm sure that going vendor native will perform even better, the effort to do so would be three times, if not more, and the improvement with vendor native, frankly, isn't that much beyond what Xamarin native already gives you. That isn't to say that I never find myself opening XCode.

Summary

In a land far, far away, there's a battle brewing between developers. Some insist that native is the only way you should write apps. Others insist that writing apps using native offers very little benefit and delivering Cordova apps is the right way to serve your user's needs.

Thankfully, I live far, far away from that land of battles. I feel that the mobile dev landscape is changing very rapidly, and it beckons you to stay on top of the changes so you know what's the best way to build an app today. From my point of view, right now, writing user interfaces in HTML is the easiest. That native code offers better performance seems to hold true, but those situations where you must confine your efforts to native code are rare. I also know that Xamarin offers 90% of the performance benefit of vendor native, while also giving me a portable codebase that I can share across platforms.

Thankfully, it's possible for me to pick the right tool for the right job. Sometimes it's Xamarin, sometimes it's Cordova, and sometimes it's vendor native.

I hope you found this article useful. Until next time, happy coding!