Xamarin.Forms with Web Assembly

Frank A. Krueger edited this page Mar 16, 2018 · 14 revisions

This guide will show you how to use Ooui.Wasm to build a Xamarin.Forms app deployed in a web assembly.

You may also wish to read Web DOM with Web Assembly to see how to create web assembly apps that don't use Xamarin.Forms.

All of these steps are written using the command line on Mac, but you can instead use Visual Studio and Windows to accomplish the same thing!

1. Create a new app

mkdir MyFormsApp
cd MyFormsApp

dotnet new console

2. Reference Ooui.Wasm

Ooui.Wasm is a package that contains a build target to generate the web assembly build.

dotnet add package Ooui.Wasm

3. Reference Ooui.Forms

Ooui.Forms is a backend for Xamarin.Forms that uses Ooui.

dotnet add package Ooui.Forms

4. Build a UI

Edit Program.cs to be:

using System;
using Ooui;
using Xamarin.Forms;

namespace MyFormsApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // Initialize Xamarin.Forms
            Forms.Init ();

            // Create the UI
            var page = new ContentPage();
            var stack = new StackLayout();
            var button = new Xamarin.Forms.Button {
                Text = "Click me!"
            };
            stack.Children.Add(button);
            page.Content = stack;

            // Add some logic to it
            var count = 0;
            button.Clicked += (s, e) => {
                count++;
                button.Text = $"Clicked {count} times";
            };

            // Publish a root element to be displayed
            UI.Publish("/", page.GetOouiElement());
        }
    }
}

This is a little app with a button that counts its clicks.

This example builds the UI in code, but you can use XAML instead. Doing so from the command-line is tricky so I suggest using Visual Studio when working with XAML.

The last line of Main is important - all web assembly apps must Publish a root element to be displayed. The last line converts a Xamarin.Forms Page into the Ooui.Element that Publish expects.

5. Build the app

dotnet build

(The first build will be slow because it's downloading the mono wasm SDK.)

In addition to building your app, this will also generate all the files you need to run your app in a web assembly. Those files are put in the dist directory. Let's take a look:

ls -al bin/Debug/netcoreapp2.0/dist/

-rw-r--r--  1 fak  staff      960 Mar 14 11:44 index.html
drwxr-xr-x  4 fak  staff      128 Mar 14 11:44 managed
-rw-r--r--  1 fak  staff   167240 Feb 28 20:39 mono.js
-rw-r--r--  1 fak  staff  1769591 Feb 28 20:39 mono.wasm
-rw-r--r--  1 fak  staff    14304 Mar 14 11:44 ooui.js
-rw-r--r--  1 fak  staff      284 Feb 28 20:39 server.py
  • index.html is a static web page that is custom generated for your projects and lists all of its dependencies and its entry point.
  • mono.js is a bridge between the browser's javascript world and mono running in the web assembly. You can blissfully ignore its banality.
  • mono.wasm this is it - the big enchilada - mono running in a web assembly.
  • ooui.js is the standard Ooui JS library that makes working with the DOM easy.
  • server.py is a little web server to host these files (though dotnet-serve is recommended).
  • managed is a directory that contains your app's assemblies. Let's look:
ls -al bin/Debug/netcoreapp2.0/dist/managed/

-rw-r--r--   1 fak  staff   320512 Feb 28 20:39 Microsoft.CSharp.dll
-rw-r--r--   1 fak  staff   309248 Mar 14 13:22 Mono.Security.dll
-rw-r--r--   1 fak  staff     5120 Mar 14 13:22 MyFormsApp.dll
-rw-r--r--   1 fak  staff   632832 Mar 14 13:22 Newtonsoft.Json.dll
-rw-r--r--   1 fak  staff    84992 Mar 14 13:22 Ooui.Forms.dll
-rw-r--r--   1 fak  staff    94720 Mar 14 13:22 Ooui.dll
-rw-r--r--   1 fak  staff  1060864 Feb 28 20:39 System.Core.dll
-rw-r--r--   1 fak  staff   123392 Feb 28 20:39 System.Numerics.dll
-rw-r--r--   1 fak  staff   833536 Mar 14 13:22 System.Runtime.Serialization.dll
-rw-r--r--   1 fak  staff   119808 Feb 28 20:39 System.Xml.Linq.dll
-rw-r--r--   1 fak  staff  2416128 Feb 28 20:39 System.Xml.dll
-rw-r--r--   1 fak  staff  2099712 Mar 14 13:22 System.dll
-rw-r--r--   1 fak  staff   565760 Mar 14 13:22 Xamarin.Forms.Core.dll
-rw-r--r--   1 fak  staff     5120 Mar 14 13:22 Xamarin.Forms.Platform.dll
-rw-r--r--   1 fak  staff  3675136 Feb 28 20:39 mscorlib.dll

We can see that our app is only 5,120 bytes, but it depends on a plethora of .NET assemblies. Fortunately, these static files cache well. Work is progressing on linking apps more aggressively in order to decrease the size.

6. Run the web assembly app

dotnet serve -p 8000 bin/Debug/netcoreapp2.0/dist

This command requires that you install dotnet-serve - a great little web server you can run anywhere.

Alternatively, you can run this python script:

cd bin/Debug/netcoreapp2.0/dist
python server.py

Your app is now running on http://localhost:8000.

(If you're on Windows, you might have to install Python first.)

If you open that page you will briefly see "Loading..." and then a giant blue button will appear. Click away!

Hit Ctrl+C to kill the web server.

7. Deploying your Web App

Since web assembly apps run locally in the browser, serving them is a breeze.

Copy the dist directory to your favorite static web server. That server can be anything from Azure, to Amazon S3, to some Apache Thing running Linux Something.