Fiddler Debugging Http/Https Traffic for Xamarin iOS, Android and Windows (UWP) Applications

Debugging Http/Https Traffic using Fiddler for Xamarin iOS, Android and Windows (UWP) Applications

One of the most frustrating things as a frontend developer is when you are receiving incorrect data. You don’t know whether the problem lies with your application, or the backend services. The easiest way to validate this is to pretend to be a hacker. You can stage a man-in-the-middle attack on your own application. Debugging using tools like Fiddler or Charles can be used to inspect the traffic from your application. Unfortunately, the same effort that goes into protecting apps from such attacks, also means that it is harder for developers to setup Fiddler debugging.

In this post I’ll walk through setting up Fiddler debugging for a Xamarin.Forms application. The same basic approach will work for a native or Xamarin iOS/Android application as well. For this post I’ve created an application using the Blank Xamarin.Forms template that comes with Visual Studio 2019. I’ve selected to target all three platforms.

In the OnAppearing method in the MainPage of the Xamarin.Forms application, I’ve added some basic code to retrieve a string for a Https endpoint. We’ll use a Https endpoint on the assumption that if we can intercept Https then we can also intercept Http traffic.

protected override async void OnAppearing()
{
     base.OnAppearing();
     var client = new HttpClient();
     var users = await client.GetStringAsync("https://reqres.in/api/users?page=0");
     Debug.WriteLine(users);
}

Setting Up Fiddler Debugging

Before we get started with the individual platforms, it’s worth checking your configuration for Fiddler:

  • You need to make sure you have setup Https traffic decryption. I’m not going to repeat the documentation, so check out how to Configure Fiddler to Decrypt HTTPS Traffic.
  • You’ll also need to setup Fiddler debugging for remote traffic. This can be done by opening the Options window. Under the Connections tab, make sure the “Allow remote computers to connect” checkbox is checked. If you’re running Skype, or some other communication tools, it may have jumped onto the default port configured in Fiddler. In this case you can adjust the “Fiddler listens on port”.
Fiddler Debugging Options Window
Enabling remote connection in Fiddler

Windows (UWP)

I’ll start with Windows, because it’s relatively straight forward to get setup. With Fiddler running, you can run the UWP project from within Visual Studio and Fiddler debugging will work. Fiddler will capture the Https traffic without any further configuration or setup.

Fiddler Debugging
Capturing network traffic in Fiddler

In some cases, you need to make sure your application is added to the exemption list, so that traffic can be routed to the local machine. For more information see the blog post Revisiting Fiddler and Win8+ Immersive applications. To check this, click the WinConfig button in the top left corner of the Fiddler interface.

WinConfig
Click WinConfig to adjust the exemption list for Windows 10 apps

Locate your application and confirm that there is a check in the box next to your application. If it’s not checked, check the box, and then click Save Changes

Exemption Utility
Locate your UWP application and check the box to add your application to exemption list

One other issue I’ve seen but can’t reproduce reliably, is that sometimes when you run your application from Visual Studio it unchecks the box in the WinConfig in Fiddler. If for some reason you no longer see traffic in Fiddler for your application, go back and double check the exemption list in Fiddler.

Diagnosing Issues with Fiddler on Windows

When configuring Https traffic decryption, you’ll be prompted to install and trust the Fiddler root certificate. If you don’t accept all the prompts, Fiddler debugging for Windows applications will not work. Windows traffic debugging works without any further configuration because the Fiddler root certificate is trusted on the machine running Fiddler.

If you’re attempting to run the Windows application on a different machine than the one running Fiddler, you’ll need to install and trust the Fiddler root certificate. This is in addition to setting the remote machine as a proxy, which is a topic for another post. Navigate to http://[ipaddress]:[port] where [ipaddress] is the ip address of the machine running Fiddler and the [port] is the port number that Fiddler is listening on. Do NOT use https as this site is http only. You should see a screen similar to the following image – if you don’t, make sure you check that Fiddler is running!!

Fiddler Debugging Echo Service
Click on the FiddlerRoot certificate to install the root certificate

Click on the FiddlerRoot Certificate and install as a Trusted Certificate Authority on the Local Machine. This should allow your Windows application to trust Fiddler.

iOS Fiddler Debugging

Next up is iOS and in this case we’re going to use the iOS simulator. The same process should work with any iOS device that’s on the same local network as the machine running Fiddler. There are two steps to setup iOS for traffic debugging:

  1. Trust the Fiddler root certificate, and
  2. Set the http proxy to use the machine running Fiddler.

To setup the simulator, first launch the iOS application from Visual Studio. If you’re on Windows, this will launch the remote viewer for the simulator. Once the simulator is running, stop debugging and we’ll setup the simulator for traffic debugging.

Trusting the Fiddler Certificate

Navigate to http:[ipaddress]:[port] (eg http://192.168.1.109:8888) to load the Fiddler echo page. Then click on the Fiddler Certificate link. Follow the prompts to download and install the certificate.

Fiddler Echo Service iPhone Download Certificate iPhone Download Profile iPhone

In addition to downloading the certificate you also need to install it. Go to Settings / General / Profile and click through on the FiddlerRoot profile in order to Install it.

image image image image image image image

The Fiddler root certificate needs to be trusted as a root certificate. Go to Settings / About / Certificate Trust Settings and toggle the switch next to the FiddlerRoot certificate. Fiddler generates a certificate for each site you go to that is derived from the root certificate, so the root certificate needs to be installed as a trusted certificate.

image image image image

The only difference between a real iOS device and the simulator is that on a real iOS device you can set a network proxy. There are online tutorials, such as this one, for instructions on setting a proxy. Unfortunately, setting up a proxy this isn’t configurable on the simulator. If you want to use a proxy in the simulator, you can set the proxy on the mac running the simulator but this would affect all traffic on the mac. Alternatively, when running on the simulator, we can adjust the HttpClient to use a WebProxy using the following code:

var handler = new HttpClientHandler();
handler.Proxy = new WebProxy("192.168.1.109", 8888);
var client = new HttpClient(handler);

Running the iOS application should show network traffic in Fiddler debugging window. You should still see the returned data printed out in the Output window (ie from the Debug.WriteLine statement).

Android Fiddler Debugging

For Android I’m going to use the Android Simulator. Real devices should behave similarly, assuming they’re connected to the same local network as the machine running Fiddler.

Unlike iOS, that will use any proxy configured for the device, for Android you need to explicitly opt in to use a proxy in your code. You’ll need to use code similar to the following on both emulator and real devices:

var handler = new HttpClientHandler();
handler.Proxy = new WebProxy("192.168.1.109", 8888);
var client = new HttpClient(handler);

What’s a little scary about this code is that it “just works”. You might be thinking that this is a good thing. However, it does raise the question of how much of the system security model does the Microsoft built HttpClientHandler respect. What I would have expected is an SSL fail exception because the Fiddler root certificate isn’t trusted by the emulator. Furthermore, the application is not configured to use any user certificates.

The other thing to point out here is that you should not be using the HttpClientHandler. I’ve discussed this in my previous post on working with the HttpClient. Let’s change our code by moving it into the OnCreate method of the Android head project. We’ll also change over to using the AndroidClientHandler.

protected override async void OnCreate(Bundle savedInstanceState)
{
     ...
     var handler = new AndroidClientHandler();
     handler.Proxy = new WebProxy("192.168.1.109", 8888);
     var client = new HttpClient(handler);
     var users = await client.GetStringAsync("https://reqres.in/api/users?page=0");
     System.Diagnostics.Debug.WriteLine(users);
}

When we run the application we see the very familiar SSL handshake exception being raised, which is what we should expect. To get things to work, we now need to install the Fiddler certificate and configure the application to use user certificates.

Install the Fiddler Root Certificate

To install the Fiddler root certificate, navigate to http:[ipaddress]:[port] (eg http://192.168.1.109:8888) to load the Fiddler echo page. Click on the Fiddler Certificate link in order to download the certificate. Follow the prompts to download and install the certificate

image image image image image  image

After installing the certificate go to Setting / Security and Location / Encryption & credentials / User credentials to inspect the certificate

image  image

With the certificate installed into the user store, you need to configure the Android project to allow the use of certificates from the user store. In my post Working with Self Signed Certificates (Certificate Pinning) in Android Applications with Xamarin.Forms, I covered this in detail. The quick summary is that you need to create a network_security_config.xml file which sets the trust-anchors property (set using the debug-overrides element) to include certificates from the user store. You then need to reference this xml file from the networkSecurityConfig attribute on the application element in the AndroidManifest.xml file.

After installing the certificate and adding the network security configuration to the Android application you should now see network requests from the application appear within Fiddler debugging window.

Side Note: Links on how to setup your iOS, Android or Windows device for remote debugging

Side Note: Links on how to setup your iOS, Android or Windows device for remote debugging

Whether it be for convenience, or out of necessity, being about to set up remote debugging to your device makes for a better debugging experience. Particularly if you’re working on a Windows machine, it’s really useful to not have to sit within a meter of the machine running the build agent. 

iOS on WiFi

On iOS, you need to connect your device to Xcode this first time. Thereafter you can debug across a WiFi network. Note that there are some limitations, specifically older devices won’t support network debugging.

Configure Remote Debugging for iOS

Android ADB Configuration

For Android, you need to configure ADB to connect to your device. Note that this configuration only lasts whilst the IP address of the device is retained. If a new IP address is leased, you’ll need to reconfigure ADB to allow for remote debugging.

Windows Remote Machine Setup for Remote Debugging

With a Windows application, use the debugging tools to connect to your device and then debug using the remote machine option in Visual Studio.

Remote Machine settings

The ability to do remote debugging is particularly useful when developing an Xbox application. With the Xbox running in Dev Mode it’s possible to use the Find option to locate the address of the Xbox. Debugging an Xbox application is then the same as debugging any other Windows 10 application.

If you need to diagnose the network traffic from your application, check out the post on using Fiddler for debugging


Nick Randolph @thenickrandolph

If you need help debugging your application, contact Built to Roam

 


Self Signed Android Certificates and Certificate Pinning in Xamarin.Forms

Working with Self Signed Certificates (Certificate Pinning) in Android Applications with Xamarin.Forms

Next up is looking at working with self-signed certificates in an Android application. Previous posts in this sequence are:

In this post we’re going to briefly talk about non-secure services. Next, we’ll look at how to trust self signed certificates by adding them to the Android bundle. Then lastly we’ll look at intercepting the certificate validation process when making service calls.

One resource that is particularly useful is the network security documentation provided for Android developers. This lists the various elements of the network security configuration file that this post will reference.

Non-Secure (i.e. Http) Services

By default, Android, like iOS, doesn’t allow applications to connect to non-secure services. This means that connecting to http://192.168.1.107 or http://192.168.1.107.xip.io will not work out of the box. You’ll see an error similar to the following, if you attempt to connect to a non-secure service:

Java.IO.IOException: Cleartext HTTP traffic to 192.168.1.107 not permitted occurred

It’s important to note that this behaviour has changed between Android 8.1 and Android 9. Prior to Android 9 there were no default restrictions on calling non-secure, or plain text, services.

Adding Network Security Configuration

You can enable accessing Http/Plain text services by adjusting the network security configuration for the application. To do this we need to add an xml file to the Resources/xml folder which we’ve called network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
     <base-config cleartextTrafficPermitted="true" />
</network-security-config>

This adjusts the network security for the application both in debug and in production. If you want to access plain text services only during debugging, you should change the base-config open and close tags to debug-overrides (everything else remaining the same). The “Application (Debuggable = true/false)” assembly attribute controls whether or not the application runs in debugging mode.

#if DEBUG
[assembly: Application(Debuggable = true)]
#else
[assembly: Application(Debuggable = false)]
#endif

We also need to add a reference to the network_security_config.xml file. In the application manifest file (AndroidManifest.xml) add the networkSecurityConfig attribute.

<?xml version="1.0" encoding="utf-8"?>
< manifest http://schemas.android.com/apk/res/android%22">http://schemas.android.com/apk/res/android"
           android_versionCode="1"
           android_versionName="1.0"
           package="com.refitmvvmcross"
           android_installLocation="auto">
     <uses-sdk android_minSdkVersion="19"
               android_targetSdkVersion="28" />
     <application
         android_allowBackup="true"
         android_theme="@style/AppTheme"
         android_label="@string/app_name"
         android_icon="@mipmap/ic_launcher"
         android_roundIcon="@mipmap/ic_launcher_round"
         android:networkSecurityConfig="@xml/network_security_config"
         android_resizeableActivity="true">
         <meta-data
             android_name="android.max_aspect"
             android_value="2.1" />
     </application>
< /manifest>

You can change the filename of the network_security_config.xml file, so long as it matches the networkSecurityConfig attribute value in the AndroidManifest.xml file.

If you run the application it will connect to the Http/Plain text endpoint.

Plain-text on iOS

In addition to enabling/disabling Http/Plain text services across the entire application, it can also be controlled on a per-endpoint basis. See the documentation on the Network Security Configuration for more information.

Self Signed Certificate Endpoints

Switching the endpoint to a Https endpoint with a self signed certificate (eg https://192.168.1.107:5001) will raise the following error:

Javax.Net.Ssl.SSLHandshakeException: <Timeout exceeded getting exception details> occurred

Which of course is completely meaningless, except that we do know it’s related to establishing the SSL connection.

If we look to the Output window, we can find more information about the exception. Unfortunately when an Android app crashes it will spew a lot of mostly irrelevant data into the output window. I’m sure all that debug information is useful in a lot of cases. However, in this case it is a lot of irrelevant information that makes it hard to find the important information. The best way to find more information is to search for the error from the debug session (i.e. Javax.Net.Ssl.SSLHandshakeException). Once found, look at the next 10-15 lines of information. In this case we see

05-04 08:31:21.756 I/MonoDroid( 5948): UNHANDLED EXCEPTION:
05-04 08:31:21.768 I/MonoDroid( 5948): Javax.Net.Ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found. ---> Java.Security.Cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found. ---> Java.Security.Cert.CertPathValidatorException: Trust anchor for certification path not found.

This points to the fact that the application hasn’t been able to verify the certificate path for the certificate returned by the service. This result is not surprising because the service is using a self signed certificate and neither the Android device or the application trust the certificate.

Trusting Self Signed Android Certificates

In this section we’re going to use the public key from the self signed certificate. This will allow the application to connect to the secure endpoint, without having to write code to intercept the certificate validation. We’ll cover two different ways but they amount to the same thing. In both cases it’s necessary to have the public key of the certificate authority available to the application. The application will use the public key to verify the certificate path of the certificate returned by the service.

Installing to the Android Certificate Store

The first option is to install the public key of the certificate authority onto the Android device. Android maintains two different certificate stores: system and user. We’re going to be adding the certificate to the user store. Aadding to the System store requires root access and can be done using ADB as shown in various posts, such as this one.

The public key that we need to use is the public key of the certificate authority. As discussed in previous posts, we’ve used mkcert to generate our self signed certificate. The public key of the certificate authority used by mkcert is available at C:\Users\[username]\AppData\Local\mkcertrootCA.pem

The first challenge is to get the certificate onto the device, which I typically find easiest via a download link. I add the public key to dropbox and then open the link in Chrome on the Android device:

image image

Installing the Public Key

After downloading the pem file, clicking on the file in the Downloads list does nothing. You actually need to go to Settings / Security & location / Encryption & credentials / Install from SD card

image

The name of the items under settings may vary from device to device. For example Install from SD card might be Install from storage. The quickest way is to search for certificate and go to the item that says something like Install from SD card.

image

Clicking on the Install from SD card/storage settings item will display a file picker. From the burger menu you can select Downloads which will reveal the pem file you’ve just downloaded. However, this item will be disabled, presumably because of some security related to downloaded items. I initially thought that I’d downloaded the wrong certificate format. In actual fact, if you go back to the burger menu and browse the contents of the device (see third image above) and click on Download, you’ll see the same rootCA.pem file but this time it’s not dimmed out and you can click on it.

image

Saving the Root Certificate

If you have a PIN setup on the device, when you click on the rootCA.pem, you’ll need to enter your pin. After entering your PIN you’ll be asked to enter a Name for the certificate and what the certificate is to be used for.

The Name isn’t particularly useful since it doesn’t show up anywhere. It doesn’t appear in either the Trusted credentials screen (second image, showing the added certificate), nor the Security certificate popup that appears if you click on the certificate for more information.

Since we want the certificate to be used by the app we leave the default use, “VPN and apps”. At this point if you open the service endpoint in the browser you should see that the certificate is trusted.

image

Accessing the Android Certificate Store

Now that we’ve installed the certificate, there’s just one change we need to make to the Android application itself. By default Android applications will only use certificates in the system store. However, you can adjust the application to make use of the user certificate store. To do this we need to add a trust-anchors and certificates elements to the network_security_config.xml with the following contents:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
     <debug-overrides>
         <trust-anchors>
            <certificates src="user" />
         </trust-anchors>
     </debug-overrides>
</network-security-config>

In this case, the certificates element will only be used when the application is running in debug mode (ie by using the debug-overrides element). Running the application now will return data from the Https endpoint.

image

The issue with this approach is that the public key for the certificate authority has to be installed on the device. Since the public key appears in the user store, it means that at any point the user could remove it. Whilst it is unlikely that the user will delete the individual item, they may decides to clear all cached credentials.

Clearing cached credentials has the unfortunate side effect of clearing out the user store, thus preventing the application from running. If you’re only connecting to endpoints for the purpose of development or debugging, this option may be sufficient and would minimise the changes required to the application.

Adding to Application Package

The second option is to add the public key of the certificate authority to the application package itself. We’ll use the DER format for the public key which we generated from the mkcert public key file in the previous post. Add the kestrel.der file to the Resources / raw folder, with Build Action set to AndroidResource, and the Custom Tool to MSBuild:UpdateGeneratedFiles.

image

You need to link the public key to the network security configuration file. Add the trust-anchors and certificates elements to the network_security_config.xml file as follows:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
     <base-config>
         <trust-anchors>
             <certificates src="@raw/kestrel" />
         </trust-anchors>
    </base-config>
</network-security-config>

If you only want to use the certificates in debugging, exchange the base-config with debug-overrides.

That’s all you need to do to be able to access a service that uses a self-signed certificate.

Validating Server Certificates (i.e. Android Certificate Pinning)

The other alternative to working with self signed certificates is to override the certificate validation that is done as part of each service request. On Android you can override the ConfigureCustomSSLSocketFactory and GetSSLHostnameVerifier methods on the AndroidClientHandler. For example, here’s a CustomerAndroidClientHandler that inherits from the AndroidClientHandler and overrides these methods:

public class CustomAndroidClientHandler : AndroidClientHandler
{
     protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
     {
         request.Version = new System.Version(2, 0);
         return await base.SendAsync(request, cancellationToken);
     }

    protected override SSLSocketFactory ConfigureCustomSSLSocketFactory(HttpsURLConnection connection)
     {
         return SSLCertificateSocketFactory.GetInsecure(0, null);
     }

    protected override IHostnameVerifier GetSSLHostnameVerifier(HttpsURLConnection connection)
     {
         return new BypassHostnameVerifier();
     }
}

internal class BypassHostnameVerifier : Java.Lang.Object, IHostnameVerifier
{
     public bool Verify(string hostname, ISSLSession session)
     {
         return true;
    }
}

We’ve also included the class BypassHostnameVerifier, which is a basic implementation of the IHostnameVerifier that needs to be returned from the GetSSLHostnameVerifier method. In the ConfigureCustomSSLSocketFactory method we’re returning a factory generated by the GetInsecure method. According to the method documentation the GetInsecure method “Returns a new instance of a socket factory with all SSL security checks disabled”. The documentation goes on to provide a warning “Warning: Sockets created using this factory are vulnerable to man-in-the-middle attacks!”.

I would like at this point to reiterate this warning. By providing your own handling of the SSL checks, you are effectively taking ownership and responsibility of making sure your application isn’t being hacked. As such, I would recommend only overriding these methods when you need to connect to a service that uses a self signed certificate. Make sure that in the Verify method you validate the service response to ensure only responses with self signed certificates that you trust are processed (ie check for man-in-the-middle attacks).

If you’re just interested in certificate pinning (i.e. ensuring that your application is connecting to a server that is returning a known certificate) you can simply override the GetSSLHostnameVerifier method. This will leave the default SSL verification/security in place but give you the opportunity to validate that the certificate being returned is what you expect.

Http2 Handling on Android

The bad news is that Http2 combined with self signed certificates doesn’t currently play nicely with the out of the box AndroidClientHandler. The AndroidClientHandler is the default and preferred handler on Android. When you attempt to connect to a service that is Http2 only and it uses a self signed certificate, you’ll probably see an error similar to the following:

Javax.Net.Ssl.SSLHandshakeException: Connection closed by peer occurred

Unfortunately there’s no simple solution without importing another library. Luckily, the ModerHttpClient library has the code necessary to do this and is updated slightly in the modernhttpclient-updated nuget package.

Please do not include the nuget package in your application as neither the original or the updated package are being actively maintained. Instead, copy the source code that you need (in this case the NativeClientHandler) and take ownership of maintaining it within your application logic.

To round this out, here’s an example that overrides the NativeMessageHandler to set the Http version to 2.

public class CustomNativeClientHandler : NativeMessageHandler
{
     protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
     {
         request.Version = new System.Version(2, 0);
         return await base.SendAsync(request, cancellationToken);
     }
}

And when an instance of the CustomNativeClientHandler is created, the EnableUntrustedCertificates property is set to true. This effectively disables any of the SSL checking, so again opens up the risk of man-in-the-middle attacks.

Mvx.IoCProvider.LazyConstructAndRegisterSingleton<HttpMessageHandler, IServiceOptions>(options =>
{
     return new CustomNativeClientHandler
     {
         AutomaticDecompression = options.Compression,
         EnableUntrustedCertificates = true
     };
});

And when we run this, we can see that the Http protocol used is Http/2.

image

In this post we’ve touched on using both self signed certificates, as well as certificate pinning. This is not an easy topic but important for application developers to be across. If you come across issues with your application security, feel free to reach out on twitter or via Built to Roam’s contact page.


Nick Randolph @thenickrandolph

Built to Roam on building cross-platform applications


Accessing ASP.NET Core API hosted on Kestrel over Https from iOS Simulator, Android Emulator and UWP Applications.

Accessing ASP.NET Core API hosted on Kestrel over Https from iOS Simulator, Android Emulator and UWP Applications.

This post is a stepping stone to get local debugging working for a Http/2 service over Https from a Xamarin.Forms application. In my post on publishing to Azure I covered the fact that the underlying service receives a Http/1.1 connection, despite applications establishing a http/2 connection. This made it difficult to build out applications that use technology such as GRPC which rely on the http/2 protocol. To make it possible to develop both the mobile app and the services locally, we need to setup the ASP.NET Core debugging to allow the applications (ie each of the supported platforms) to connect.

This post assumes that the ASP.NET Core application is being hosted locally using Kestrel, mainly because of the limitations around http/2 (here and here). By default, when you create an ASP.NET Core application it is setup with multiple launch configurations, allowing you to switch between IIS Express, Kestrel and if you select the Docker option when creating your project, you’ll see an option to launch using Docker (as shown in the following image showing the launchSettings.json for the HeaderHelper project).

image

To switch between the different launch configurations you just need to select the right configuration from the run dropdown in Visual Studio – in this case I’ve selected the HeaderHelper option, which as you can see from the above launch configurations uses the “Project” command name that correlates to hosting using Kestrel (I know, not super obvious, right!).

image

When we run the ASP.NET Core application using the default launch configuration on Kestrel, what we see is that a command window is shown (since Kestrel is basically a console application) and then a browser window is subsequently launched. As you’d expect the out of the box experience is all good – we can see it’s launched the https endpoint and there’s the lock icon to indicate it’s trusted.

image

It’s also interesting to note that the service is returning Http/2 when according to this document (see screenshot below) the default is Http/1.1.

image

Well, it looks like the documentation hasn’t been updated in line with the latest code. If you take a look at GitHub for AspNetCore repository you can see that between the stable v2.2.4 and the v3.0.0-preview4 release there has been a change to the default value.

image

Coming back to our Kestrel hosted ASP.NET Core application, we can see that the endpoint host is localhost, which aligns with what’s in the applicationUrl property in the configuration in the launchSettings.json file. Unfortunately, localhost isn’t great when it comes to working with mobile applications as localhost doesn’t always resolve to the development machine. For example if you’re working with a real iOS or Android device, they’re most likely going to be on the same WiFi network but localhost won’t resolve to machine running the ASP.NET Core application. Similarly if you’re developing on a Windows PC and using a remote Mac to do the build and run the simulator, localhost again won’t resolve to the correct machine.

To solve this, we need to change the Kestrel configuration to expose the service in such a way that it can be accessed via the IP address of the machine where Kestrel will be running. Note that there are plenty of services such as ngrok, portmap.io and Forward which are great and easy to setup for non-secure services. However, once you get into trying to extend the configuration to support Https or Http/2 you end up needing to pay to use their premium service. These services are great if you want to extend beyond the bounds of your firewall but are overkill if all you want to do is expose your service for development purposes.

A much similar alternative is to:

– Change Kestrel to bind to all IP addresses for the host machine

– Add a firewall rule to allow in-bound connections on the posts required for the application

I’ll elaborate on these in more detail – and I’m going to do them in reverse order because the firewall rule is required in order to verify the Kestrel configuration is working when binding to the IP address.

Adding a Firewall Rule for Ports 5001 and 5000 (on Windows)

On Windows, it’s relatively straight forward to add a firewall rule that will allow inbound connections on specific ports. In this case we’re interested in adding a rule that works for ports 5000 and 5001, which are the two ports used in the applicationUrl property of launchSettings.json. Here’s the step-by-step

– Press Start key, type “Windows Defender” and click on the “Windows Defender Firewall with Advanced Security” option

– Click on “Inbound rules” in the left panel

– Click on “New rule” in the right (Actions) panel to launch the New Inbound Rule Wizard

– When prompted for the type of rule, select “Port” and click Next

– Make sure the “Specific local ports” option is selected and enter “5000-5001” (or “5000,5001”) in the text box.

– Click Next, accepting the defaults on the remaining pages of the New Inbound Rule Wizard, through to the final page where you’ll need to give the rule a name before hitting Finish.

Once you’ve created the Inbound rule, any requests made on these ports will be allowed through to whatever service is bound to those ports on your computer. You should disable this rule when you’re not making use of these ports for debugging.

Binding Kestrel to All IP Addresses

This can be done simply by changing the launchSettings.json file to replace localhost with 0.0.0.0:

image

When you rebuild (you may need to force a rebuild as sometimes the change to launchSettings.json isn’t picked up by Visual Studio) and attempt to run the application you’ll see an error page – this is because 0.0.0.0 isn’t actually a real IP address, it’s just the address used in the launchSettings to configure Kestrel to bind to all addresses.

image

If you change the address to use localhost instead of 0.0.0.0 you’ll again see that the api result is returned successfully. However, if you now use the actual IP address of the computer (in this case 192.168.1.107) you’ll see a certificate warning. Clicking the Advanced you can proceed to the site and see the result but the “Not secure” in the address bar will remain.

image

The fact that there’s a security error is going to cause a lot of issues if we don’t resolve it because none of the application platforms (ie iOS, Android, UWP) work well with Https when the certificate can’t be verified. Even if you use certificate pinning (to be covered in a future post) you’ll find it hard to configure the different platforms to work with certificates that don’t match the domain of the service.

If we take a look at the certificate being used, we can see that the Subject Alternative Name only matches with localhost.

image

Luckily this problem can be fixed by changing the certificate that is used by your ASP.NET Core application. If you’re planning on exposing your ASP.NET Core endpoint directly to the internet I would recommend getting a certificate from a well known CA. The following process can be used for setting up your service for development purposes:

If you know what you’re doing you can download the latest openssl and proceed to create your own certificates. However, this is fairly involved and a much similar way is to leverage the mkcert tool that is available at https://github.com/FiloSottile/mkcert. The steps are as follows:

– Download the latest binaries for mkcert (you might want to rename the executable from say mkcert-v1.3.0-windows-amd64.exe to mkcert.exe for convenience)

– Launch a command prompt running as Administrator

– Run “mkcert -install”. If you get an error such as “failed to execute keytool…..”  you probably didn’t read the previous step and opened a regular command prompt. You need to be running as Administrator

image

A successful install should look like:

image

The install process creates a certificate and trusts it on the local computer as a trusted certificate authority, meaning it can be used to generate other certificates.

– Run mkcert to create a certificate that you can use in your ASP.NET Core application

mkcert -pkcs12 -p12-file kestrel.pfx 192.168.1.107 localhost 127.0.0.1 ::1

image

– Copy the newly created kestrel.pfx into the ASP.NET Core project and set the Build Action to Content to make sure it gets deployed with your application.

image

– Remove the applicationUrl property from the Kestrel configuration in launchSettings.json

image

– Update the CreateHostBuilder method in program.cs to setup the Kestrel configuration. Specifically setting up both ports 5001 and 5000 to listen on Https and Http respectively. For port 5001 the kestrel.pfx certificate is used (note despite the advice we haven’t changed the password here but would recommend doing so if you’re going to use this in production)

public static IHostBuilder CreateHostBuilder(string[] args) =>
     Host.CreateDefaultBuilder(args)
         .ConfigureWebHostDefaults(webBuilder =>
         {
             webBuilder
                 .ConfigureKestrel(options =>
                 {
                     options.ListenAnyIP(5001, listenOptions =>
                     {
                         listenOptions.UseHttps(“kestrel.pfx”, “changeit”);
                     });
                     options.ListenAnyIP(5000);
                 })
                 .UseStartup<Startup>();
         });

Now when we run the ASP.NET Core application on the Kestrel hosting we can successfully navigate to the endpoint using the machines IP address.

image

Inspecting the https certificate you can see that the Subject Alternative Names include 192.168.1.107 (ie the machines IP address) and that the Certification path ends in the mkcert certificate that has been added to the trusted certificate authorities on this computer.

imageimage

Now that we’ve configured Kestrel and ASP.NET Core to play nice, what we need to do is to configure our mobile applications to connect to this service, which we’ll do in the next post.

Xamarin and the HttpClient For iOS, Android and Windows

Xamarin and the HttpClient For iOS, Android and Windows

In an earlier post that talked about using dependency injection and registering interfaces for working with Refit across both Prism and MvvmCross I had code that registered an instance of the CustomHttpMessageHandler class which internally used a HttpClientHandler for its InnerHandler. For developers who have spent a bit of time optimising their iOS, Android or Windows application, you’ll have noted that using the HttpClientHandler is generally not deemed to be best practice.  As I’m a big fan of trying to demonstrate best practices, I figured I’d expand on this a little into a post talking about the HttpClient and some of the options you have.

Firstly, a couple of bits of side reading:

– Docs on the HttpClient stack

– Mono blog post talking about the HttpWebRequest / HttpClient

– Jon’s post on Http Performance

What you should gather from these articles is that Microsoft is doing their best to set you up for success but not wanting to take any documentation for granted, let’s see what happens when we create a brand new Xamarin.Forms project and spin up an instance of the HttpClient. When creating the project I just picked the Blank Xamarin.Forms template and made sure that all three platforms were included. The code for creating the HttpClient just uses the zero-parameter constructor:

var client = new HttpClient();

Let’s run each platform and see what the HttpClient gives us (and at this point I haven’t updated any NuGet packages, framework versions or anything. This is just what VS2019 gives me when I create a new XF project).

UWP

image

Here we get the managed HttpClientHandler, rather than the newer (and arguably better) WinHttpHandler. Actually I didn’t find a definitive guide on which is better for UWP, although this stackoverflow post does seem to imply the WinHttpHandler would be the preferred choice, particularly if you want to leverage Http/2.

Android

image

Android is using the AndroidClientHandler which is what should give us the most up to date http experience.

iOS

image

iOS is using the NSUrlSessionHandler which is what should give us the most up to date http experience.

This all seems good (albeit that you might want to use the WinHttpHandler on UWP) so for a lot of developers they might never run into any issues. If you did want to adjust which handler is used on iOS and Android (again assuming you’re just using the HttpClient with the default constructor) you can do so via the properties dialog for the corresponding platform:

image

However, where things come unstuck is if you want to customise some of the http behaviour. In my previous post I demonstrated setting the compression flag but it could have equally been adding an additional header or changing the credentials that are sent as part of each request. In this case, it’s easy enough to use the overload of the HttpClient constructor that takes a HttpMessageHandler and use the managed HttpClientHandler implementation (as I demonstrated). As you’d have seen from the linked articles above, this isn’t ideal as the managed implementation doesn’t leverage the platform specific optimisations.

The better approach is for my application to register the platform specific handler, which in MvvmCross can be done via the Setup class (which is created by default when using MvxScaffolding):

UWP

public class Setup : MvxFormsWindowsSetup<Core.App, UI.App>
{
     protected override void InitializeIoC()
     {
         base.InitializeIoC();
        Mvx.IoCProvider.LazyConstructAndRegisterSingleton<HttpMessageHandler, IServiceOptions>(options =>
         {
             return new WinHttpHandler()
             {
                AutomaticDecompression = options.Compression
             };

         });
     }
}

Android

public class Setup : MvxFormsAndroidSetup<Core.App, UI.App>
{
     protected override void InitializeIoC()
     {
         base.InitializeIoC();


        Mvx.IoCProvider.LazyConstructAndRegisterSingleton<HttpMessageHandler, IServiceOptions>(options =>
         {
            return new AndroidClientHandler
             {
                 AutomaticDecompression = options.Compression
             };

         });
     }
}

iOS

public class Setup : MvxFormsIosSetup<Core.App, UI.App>
{
     protected override void InitializeIoC()
     {
         base.InitializeIoC();


        Mvx.IoCProvider.LazyConstructAndRegisterSingleton<HttpMessageHandler, IServiceOptions>(options =>
         {
             var nsoptions = NSUrlSessionConfiguration.DefaultSessionConfiguration;
             if (options.Compression == System.Net.DecompressionMethods.None)
             {
                 nsoptions.HttpAdditionalHeaders = new NSDictionary(“Accept-Encoding”, “identity”, new object[] { });
             }
             var handler = new NSUrlSessionHandler(nsoptions);
             return handler;

         });
     }
}

Note: for iOS the NSUrlSessionHandler enabled compression by default, so the code here illustrates how you could disable compression if you wanted by sending the identity Accept-Encoding header.

In this post I’ve shown you how you can register each of the native platform handlers to optimise the requests made when using the HttpClient. This post should be read in conjunction with my earlier post that registered the other classes necessary to create the HttpClient based on the registered handler. The only other change is that the HttpService constructor should accept an HttpMessageHandler instead of an ICustomHttpMessageHandler.

public class HttpService : IHttpService
{
     public HttpService(HttpMessageHandler httpMessageHandler, IServiceOptions options)
     {
         HttpClient = new HttpClient(httpMessageHandler as HttpMessageHandler)
         {
             BaseAddress = new Uri(options.BaseUrl)
         };
     }


    public HttpClient HttpClient { get; }
}

Update: It’s worth noting that the WinHttpHandler used in the UWP example isn’t part of the core framework. Instead it is accessible via the System.Net.Http.WinHttpHandler NuGet package. Visual Studio provides a handy way to find and install this package – selecting the WinHttpHandler reference (where there is a build error) and looking at the intellisense options, there is an option to Install the System.Net.Http.WinHttpHandler package.

image

Blend Still Lives

Blend Still Lives

I was surprised when editing the XAML of a UWP project that I saw a prompt to open the page in Blend – I’d all but forgotten that Blend exists.

image

On launching Blend I noticed the fancy new splash screen but is the only thing that’s been worked on? Well I currently don’t use Blend, even for UWP development, so I’m not sure why this product even exists, considering most of its features are covered by the new tool windows in Visual Studio.

I did notice that when editing the UWP page, there was at least support for Visual States. Back in its prime, Blend led the way with developer-designer engagement. Now with hot reload support in most major frameworks, the reliance on a design time experience as all but gone away. I think it’s time to say RIP to Blend and move forward with a different approach to XAML developers.

Getting Started with Platform Uno

Getting Started with Platform Uno

A while ago I posted on Building a TipCalc using Platform Uno and at the time there was quite a few steps to jump through to get a basic application running from scratch. In this post I’m going to cover off how incredibly easy it now is to get started with the Uno Platform. Before I get into the steps, I want to give some background on why after almost a year am I coming back to looking at Uno. For those who have been reading my blog or have worked with Built to Roam you’ll know that we specialise in building cross-platform applications, whether it be a mobile app spanning iOS and Android, a Windows app targeting desktop and Xbox, or an enterprise solution that’s available across web, mobile and desktop. With a deep heritage in the Microsoft ecosystem we have seen the emergence of technologies such as Xamarin.Forms – historically this was rudimentary framework for rapidly developing forms based applications, primarily for line of business solutions. We’ve also seen other frameworks emerge such as React Native, Flutter and of course PWAs. Each framework has its advantaged and disadvantages; each framework uses a unique set of tools, workflow and languages. The question we continually ask ourselves is which framework is going to provide the best value for our customers and that will allow us to build user interfaces that include high fidelity controls and rich animation.

We also evaluate frameworks based on the target platforms that they support, which is what has led me to this post. One of the amazing things about Xamarin.Forms is that it has provided support for the three main platforms, iOS, Android and Windows, as part of the core platform. In fact the tag line is currently “Native UIs for iOS, Android and Windows from a single, shared codebase”.

image

What’s mind blowing is if you look at the Other Platforms page you’ll see that there is also support for GTK, Mac, Tizen and WPF. Unfortunately, these other platforms do not get the same love as the core platforms, so don’t expect them to be kept up to date with the latest releases.

At this point you might be thinking, why stray from Xamarin.Forms? Well in recent times there has been a shift away from supporting UWP as a core component of Xamarin.Forms. When asked on Twitter about UWP support for Shell, David Ortinau’s response was just another nail in the coffin for UWP app developers who are already struggling an up hill battle to convince customers of the value proposition of building for Windows.

image

So this leads me to again revisit other frameworks but we find the situation isn’t much better:

  • React Native – iOS and Android only – There is a React Native for Windows but again, it’s not part of the core offering, so it will trail (perhaps not by much but the commit history indicates a difference between 1 day ago for the main Reach Native repo and 26 days ago on the Windows repo, for the most recent commit).
  • Flutter – iOS and Android only – There is work on desktop embedding and having Flutter work on the web, so perhaps we’ll see more support beyond Google I/O
  • PWAs – varying level of support on different platforms – Clearly Microsoft sees this as the path forward for some of their Office suite of apps but the lack of native UI I think is still a limitation of PWAs.

At this point I remembered that Uno provided an interesting take on cross platform development. I also remembered that they’ve been doing a lot of work to support WebAssembly, so perhaps this could be the perfect solution. In the simplest form, the Uno Platform is #uwpeverywhere (an initiative that I’ve long believed Microsoft should have championed, after all it’s called Universal for a reason, right?) but beyond that Uno is about being able to “Build native apps for Mobile and Web using XAML and C#”.

image

Let’s get cracking with building a Uno application and see how it pans out. If you’re on the Uno Platform homepage and wondering how to get started, don’t worry, you’re not alone – I was looking for a big “Get Started” button but instead I see links to sample apps and to the source code. If you find yourself across at the source code, you’re about to embark down the wrong path – you don’t need to grab their source code as everything is distributed via nuget! So where do you go? Well you need to find the Uno Documentation and then click the link to Getting Started – now we’re cooking with gas! Unfortunately most of this page is pretty useless until you come to want to debug your application on WebAssembly. Instead what you really want to do i install the Uno Visual Studio Extension and use that to create your application.

Getting Started

  • Install the Uno Visual Studio Extension
  • Open Visual Studio and select File, New, Project
  • Search for “cross platform” and select the Cross-Platform App (Uno Platform) template

image

  • Important: Update nuget package references – if you don’t do this, it’s unlikely that your application will run as a WebAssembly (check the “Include prerelease” to get the latest update for Wasm support)

image

  • For WebAssembly in the csproj file:
    • Add <DotNetCliToolReference Include=”Uno.Wasm.Bootstrap.Cli” Version=”1.0.0-dev.214″ /> into the same ItemGroup as the PackageReference for Uno.Wasm.Bootstrap
    • Add <MonoRuntimeDebuggerEnabled>true</MonoRuntimeDebuggerEnabled> to the initial PropertyGroup
    • Change the Project element to <Project Sdk=”Microsoft.NET.Sdk.Web”>
  • Build and run each platform – I’m showing UWP, Android and WebAssembly here but iOS works straight from the template too

image

So, now that we have a UWP application that runs on iOS, Android, Windows and Web, are we satisfied with this as a cross platform solution? I think I’m enjoying working in UWP again but it’ll take a bit more investigation to see if this is a viable solution or not.

———-

Contact Built to Roam for more information on building cross-platform applications

———-

Android Emulator Exception after updating to Visual Studio 15.9 preview 3

Android Emulator Exception after updating to Visual Studio 15.9 preview 3

I noticed earlier this evening that there was an update available for Visual Studio 15.9. Normally I wait a few days to update as I’m not in any particular hurry but I noticed in the blog post and release notes that work had been done on the Android build and execution. I also remembered that I hadn’t updated Visual Studio or my emulator images since updating my Surface Book 2 to the latest Windows update – it contains a fix for the awful performance of the Android emulator running on Windows hypervisor. Anyhow, the upshot is that I updated Visual Studio to the latest preview….

I decided to drop my existing emulator images and create new ones. Unfortunately this was a bad idea as I was then unable to start the new emulator images. When I attempted to start the emulator I would get an error stating “The requested operation requires elevation. (Exception from HRESULT: 0x800702E4)”.

image

Turns out I’m not the only person seeing this, as someone had already reported this issue.

It also turns out that there’s a simple solution…. close the Android Device Manager and just hit Run from within Visual Studio. Turns out that this causes the emulator image to boot, deploy and run the application. And all the updates seem to do the trick, debugging is back to an acceptable speed.

Intercepting the Android Software Back Button in Xamarin.Forms

Intercepting the Android Software Back Button in Xamarin.Forms

Recently an issue was raised on MvvmCross that claimed there was an issue intercepting the back button in a Xamarin.Forms + MvvmCross application running on Android. I spent a bit of time investigating the issue as I didn’t believe MvvmCross was doing anything that would prevent an application from intercepting the back button. In this post I’ll walk through my investigation and demonstrate a solution that I came up with. Just for clarity, the issue was referring to intercepting the software back button that appears in the navigation bar.

In the comments someone had referenced a solution proposed by Udara Alwis (https://theconfuzedsourcecode.wordpress.com/2017/03/12/lets-override-navigation-bar-back-button-click-in-xamarin-forms/) which states that the OnOptionsItemSelected method can be overridden in the Activity that hosts the Xamarin.Forms application. Further comments indicated that this solution didn’t work for a Xamarin.Forms application that was using MvvmCross. My starting point was to of course validate this assertion. Using the Playground sample in the MvvmCross source code I attempted to override the OnOptionsItemSelected method in the MainActivity of the Android application. I ran the application and sure enough, the OnOptionsItemSelected method does not get invoked when tapping the software back button.

Having validated that the MvvmCross Playground was indeed broken, I next wanted to test to see if it was an issue with Xamarin.Forms itself. To do this, I started by creating a new Xamarin.Forms application (I’m just going to build for Android, since this is just a sample).

image

The Blank application template comes with a single page, MainPage. I added a second page to the application:

image

Onto the MainPage I added a Button and in the Clicked event handler added code to navigate to the page I just added:

private async void Button_Clicked(object sender, EventArgs e)
{
     await Navigation.PushAsync(new Page1());
}

In order to get the navigation bar to appear, I changed the App constructor to make use of a NavigationPage:

public App()
{
     InitializeComponent();


    MainPage = new NavigationPage(new MainPage());
}

Lastly, I needed to add the OnOptionsItemSelected override to the MainActivity.

public override bool OnOptionsItemSelected(IMenuItem item)
{
     return base.OnOptionsItemSelected(item);
}

Unfortunately, after doing all this, the OnOptionsItemSelected method was still not called. Looks like the issue sits with Xamarin.Forms, so it’s time to start trawling through the source code.

After an initial inspection it appears that the FormsAppCompatActivity does override the OnOptionsItemSelected method, but that doesn’t explain why overriding it in my application wouldn’t work. However, further inspection revealed that the NavigationPageRenderer (the renderer for the NavigationPage) implements the IOnClickListener interface and registers itself with the ActionBar (which corresponds to the navigation bar). Doing this prevents the call to the OnOptionsItemSelected method, which is why we were not seeing it called.

I figured that I would try extending the default renderer and provide my own implementation of the IOnClickListener interface:

[assembly: ExportRenderer(typeof(NavigationPage), typeof(HackBackButton.CustomNavigationPageRenderer))]
namespace HackBackButton
{
     public class CustomNavigationPageRenderer : NavigationPageRenderer, IOnClickListener
     {
         public CustomNavigationPageRenderer()
         {
         }


        public CustomNavigationPageRenderer(Context context) : base(context)
         {
         }


        public new void OnClick(Android.Views.View v)
         {
             Element?.PopAsync();
         }
    }
}

This works and the OnClick method is invoked when the software back button is tapped. Of course, we then need to route this to the current page so that it can decide if it should allow the back navigation.

Turns out that it’s nothing to do with MvvmCross and that the issue lie entirely with Xamarin.Forms. There needs to be a better way to intercept the back navigation. Someone has already listed a issue with Xamarin.Forms, so add a comment and make sure this issue gets some attention.

Getting Started with Xamarin.Forms and Device Customization using OnIdiom

Getting Started with Xamarin.Forms and Device Customization using OnIdiom

Previous posts in this sequence on Getting Started with Xamarin.Forms:
Multi-Targeting in Visual Studio, SDK Versions, MvvmCross, Authenticating with ADAL
Refactoring MvvmCross and Services, Effects, Navigation with MvvmCross
Presentation Attributes in MvvmCross, Resources and Styles, Resource Dictionaries
Platform Specific Resources with OnPlatform

Last post I covered how to use OnPlatform to tailor resources and styles based on the target platform. However, there is an alternative dimension you can tailor the layout of your application and that’s using OnIdiom. If you look at the definition of the OnIdiom class you can see that it allows you to define different values for Phone, Tablet, Desktop, TV and Watch.

image

To use this in XAML is very similar to using OnPlatform:

<Label>
     <Label.Text>
         <OnIdiom x_TypeArguments=”x:String”>
             <OnIdiom.Phone>Hello from a phone app</OnIdiom.Phone>
             <OnIdiom.Desktop>Hello from a desktop app</OnIdiom.Desktop>
         </OnIdiom>
     </Label.Text>
</Label>

As you can see from the code snippet this provides different string values for when the application is run on a phone vs being run on a desktop.

Note: Tablet only works well for iOS and Android. Xamarin.Forms running on UWP currently doesn’t distinguish between Windows running in desktop or tablet mode, and as such will always use the Desktop idiom values.

Getting Started with Xamarin.Forms, Refactoring MvvmCross and Services

Getting Started with Xamarin.Forms, Refactoring MvvmCross and Services

Previous posts in this sequence:
Getting Started with Xamarin.Forms and Multi-Targeting in Visual Studio
Getting Started with Xamarin.Forms and SDK Versions
Getting Started with Xamarin.Forms with MvvmCross
Getting Started with Xamarin.Forms and Authenticating with ADAL

In this post I’m going to do a bit of a refactor based on the work completed in the previous post where we added code directly into the MainViewModel to use the Azure Active Directory Authentication Library. This would be fine if the MainViewModel was the only view model in the application that needed access to the Authenticate method. As I will probably want to make use of it elsewhere, I’ve decided to refactor that code into a class called CredentialService.

When I wired up MvvmCross a couple of posts ago, I did so without going into much detail on how the relationship between view models and their corresponding page is setup. I’m not going to delve into the inner workings of MvvmCross but suffice to say that there is some reflection magic that goes on based on the names of the classes. A view model with the name MainViewModel will be paired with a page called MainPage.

In addition to the magic that glues the view model and pages together (and thus the navigation model) MvvmCross also has a quite powerful dependency injection framework. The CredentialService that I’ll be creating will be registered with the DI framework as a singleton that can be easily accessed.

Let’s start by creating the CredentialService and it’s corresponding interface ICredentialService in a folder called Services in the Core library.

public partial class CredentialService:ICredentialService
{
     private const string AuthEndpoint = “
https://login.microsoftonline.com/{0}/oauth2/token”;


    private const string ResourceId = “https://graph.windows.net/”;
     private const string TenantId = “[your tenantId]”;
     private const string ClientId = “[your clientId]”;
     private const string RedirectURI = “[your redirectURI]”;


    public string AccessToken { get; set; }


    public async Task<string> Authenticate()
     {
         string authority = string.Format(CultureInfo.InvariantCulture, AuthEndpoint, TenantId);
         var authContext = new AuthenticationContext(authority);


        var result = await authContext.AcquireTokenAsync(ResourceId, ClientId, new Uri(RedirectURI), this.PlatformParameters);
         AccessToken = result.AccessToken;
         return AccessToken;
     }
}

public interface ICredentialService
{
     Task<string> Authenticate();
}

The platform specific code will need to be extracted out of the MainViewModel.Platform.cs into the corresponding CredentialService.Platform.cs. For example the UWP class would be:

public partial class CredentialService
{
     private IPlatformParameters PlatformParameters => new PlatformParameters(PromptBehavior.Always, false);
}

In order to register the CredentialService with the DI framework, we just need to add a small bit of code to the Initialize method of the App class in the Core library

public override void Initialize()
{
     CreatableTypes()
         .EndingWith(“Service”)
         .AsInterfaces()
         .RegisterAsLazySingleton();


    RegisterAppStart<MainViewModel>();
}

The last step is to make use of the service in the MainViewModel. We do this by adding a parameter of type ICredentialService to the MainViewModel constructor.

private ICredentialService CredentialService { get; }
public MainViewModel(ICredentialService credentialService)
{
     CredentialService = credentialService;
}


private async Task Authenticate()
{
     Debug.WriteLine(await CredentialService.Authenticate());
}

And that’s it – we haven’t changed any functionality but the solution is better organised and structured in a way that services can easily be added without cluttering up view models.

image

Where’s the Latest Android Emulator?

Where’s the Latest Android Emulator?

I’ve been struggling to get the Android emulator to perform at a level where debugging was possible. After upgrading to VS15.8 I was able to switch over to use the new Windows Hypervisor support (note that “Windows Hypervisor Platform” is different from the Hyper-V feature in the Windows Features dialog). However, I found that the performance of the emulator was so bad that debugging was barely possible – infinitely worse than when I was using the HAXM support.

After spending a bit of time searching online I came across references to versions of the Android emulator that were higher than what I was using. I double-checked the Android SDK Manager just in case there were updates available but there were none.

Eventually I realised that by selecting the cog in the lower right corner of the SDK Manager I was able to switch from the Microsoft repository across to the Google repository.

image

After switching to the Google repository there was indeed an update to the tools, which included the new emulator version.

Did this fix the performance issue? Not entirely. Performance was better in the Android P emulator but still nowhere near as good as a real device (even an old one).

If all else fails, go to the source. I reached out to Miguel and asked if this was a known issue.

image

Looks like we need to wait for a Windows update in order to get this performance fix.

Getting Started with Xamarin.Forms and Authenticating with ADAL

Getting Started with Xamarin.Forms and Authenticating with ADAL

Previous posts in this sequence:
Getting Started with Xamarin.Forms and Multi-Targeting in Visual Studio
Getting Started with Xamarin.Forms and SDK Versions
Getting Started with Xamarin.Forms with MvvmCross

Now that we’ve got the basics of an application, we’re going to add some authentication using the Azure Active Directory Authentication Library. We’re going to start with registering an application with Azure Active Directory (AAD) (the docs do cover this here but I figured I’d cover it again anyway). Start by heading over to the Azure portal and selecting Azure Active Directory from the set of tabs on the left.

image

In the list of tabs for the AAD, find the App Registrations tab

image

Click “New application registration” and fill in the details for the new app

image

Note that the Sign-on URL doesn’t have to be a real URL, just one that both the portal and the app know about – we’ll use this later! After you’re done creating the app registration you should be able to retrieve the Application ID. Save this information for later as we’ll need it when we’re authenticating the user within our application.

image

The pieces of information you’ll need in order to use ADAL within your application are:

clientId – This is the Application ID that was displayed after you created the app registration in the Azure portal. This is a GUID

redirectUri – This is the Redirect URI that you specified when creating the app registration. If you didn’t write this down, or you want to double check, or change it, you can do so by clicking the Redirect URIs tab under Settings for the app registration. This is a URL (e.g. https://stratapark)

resourceId – This is the identifier of the resource you want to access. In this case we just want to authenticate the user, so we’re going to use the default resource, which is the AAD directory itself, https://graph.windows.net/. This can be a URL or a GUID depending on the type of resource you’re referencing

tenantId – This is the identifier of the tenant that you’re authenticating against. This can be the URL or GUID of your tenant.

To retrieve the tenantId you need to select the Properties tab of the Azure Active Directory and copy the Directory ID

imagehttps://www.nuget.org/packages/Microsoft.IdentityModel.Clients.ActiveDirectory/

Now that we’ve setup the app registration, we’re good to start writing some code. Firstly, we need to add a reference to the ADAL library from NuGet – search for Microsoft.IdentityModel.Clients.ActiveDirectory

image

Add the ADAL library to all projects.

Let’s start with the UI and add a button to the MainPage.

<Button Text=”Authenticate” Command=”{Binding AuthenticateCommand}” />

And of course we need a command within the MainViewModel. In fact we’ll add the bulk of the authentication code to the MainViewModel too:

private IMvxCommand authenticateCommand;
public IMvxCommand AuthenticateCommand => authenticateCommand ?? (authenticateCommand = new MvxAsyncCommand(Authenticate));


private const string AuthEndpoint = “https://login.microsoftonline.com/{0}/oauth2/token”;


private const string ResourceId= “https://graph.windows.net/”;

private const string TenantId = “[your tenantId]”;
private const string ClientId = “[your clientId]”;
private const string RedirectURI = “[your redirectUri]”;


public async Task Authenticate()
{
     string authority = string.Format(CultureInfo.InvariantCulture, AuthEndpoint, TenantId);
     var authContext = new AuthenticationContext(authority);


    var result = await authContext.AcquireTokenAsync(ResourceId, ClientId, new Uri(RedirectURI), PlatformParameters);
     Debug.WriteLine( result.AccessToken);
}

The only thing missing is the PlatformParameters (bolded in the code above). As the name suggests, these are platform specific parameters required by the ADAL library. For each platform we need to expose a property that returns an IPlatformParameters within the MainViewModel.Platform.cs for each platform.

Android

private IPlatformParameters PlatformParameters => new PlatformParameters(CurrentActivity, true, PromptBehavior.Auto);
public Activity CurrentActivity
{
     get
     {
         var top = Mvx.IoCProvider.Resolve<IMvxAndroidCurrentTopActivity>();
         return top.Activity;
     }
}

iOS

private IPlatformParameters PlatformParameters => new PlatformParameters(GetTopViewController(),true, PromptBehavior.Auto);
public static UIViewController GetTopViewController()
{
     var window = UIApplication.SharedApplication.KeyWindow;
     var vc = window.RootViewController;
     while (vc.PresentedViewController != null)
         vc = vc.PresentedViewController;


    if (vc is UINavigationController navController)
         vc = navController.ViewControllers.Last();


    return vc;
}

UAP

private IPlatformParameters PlatformParameters => new PlatformParameters(PromptBehavior.Always, false);

NetStandard

private IPlatformParameters PlatformParameters => null;

Note: you need to provide the NetStandard implementation otherwise the NetStandard target won’t build.

There is one more thing we need to add. Android requires an additional piece of code within the Activity that hosts the Xamarin.Forms application

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
     base.OnActivityResult(requestCode, resultCode, data);
     AuthenticationAgentContinuationHelper.SetAuthenticationAgentContinuationEventArgs(requestCode, resultCode, data);
}

If your Android application authenticates but doesn’t ever return the access token, chances are that your OnActivityResult override is either missing, or on the wrong Activity – I spent a bit of time trying to work out why iOS and UWP worked but Android would just hang; turns out I was missing this override.

There you have it – you’re good to go with using ADAL to authenticate your users within your Xamarin.Forms application

Getting Started with Xamarin.Forms with MvvmCross

Getting Started with Xamarin.Forms with MvvmCross

Previous posts in this sequence:

Getting Started with Xamarin.Forms and Multi-Targeting in Visual Studio

Getting Started with Xamarin.Forms and SDK Versions

Next up is adding in MvvmCross – no surprises here: Add the MvvmCross package to all projects in the solution

image

We need to make a few adjustments to the Core library. First up, we need to add an App class to Core that inherits from MvxApplication. For the moment the only thing this class is going to do is to set the initial view model of the application. One of the core ideas behind MvvmCross is that navigation is driven from view models, rather than at the view level. By setting the initial view model, we’re effectively defining which view will be shown when our application launches.

public class App : MvxApplication
{
     public override void Initialize()
     {
         RegisterAppStart<MainViewModel>();
     }
}

We’ll do a bit of tidying up whilst we’re making changes to the Core project. We’ll create a ViewModels folder and move MainViewModel into folder

We’ll update MainViewModel and MainViewModel.Platform.cs (all four) to add ViewModels to namespace. We’ll also update MainViewModel to inherit from MvxViewModel.

Now that we’ve updated the Core library, we’ll turn our attention to the UI library and the head projects. We’ll add the MvvmCross.Forms NuGet reference to all projects, except Core.

image

The only other change we need to make to the UI library for the moment is to update MainPage to inherit from MvxContentPage instead of ContentPage. You’ll need to do this in both the xaml and xaml.cs files. However, I would recommend dropping the inheritance from the xaml.cs file as it is not required in multiple places.

Next up we need to adjust each of the head projects (UWP, iOS and Android) so that they use MvvmCross to launch the Xamarin.Forms views.

UWP

Rename MainPage to HostPage (in both MainPage.xaml and MainPage.xaml.cs, and the filenames themselves) in the UWP head project – we do this to avoid any confusion between the name of the page and any views that are automatically associated with MainViewModel. Also update HostPage to inherit from MvxFormsWindowsPage.

For UWP we need an additional step due to some limitation around the support for generics. Add a help class ProxyMvxApplication, defined as follows:

public abstract class ProxyMvxApplication : MvxWindowsApplication<MvxFormsWindowsSetup<Core.App, UI.App>, Core.App, UI.App> { }

Change App.xaml and App.xaml.cs to inherit from ProxyMvxApplication, and remove all code in App.xaml.cs other than the constructor which should contain a single call to InitializeComponent. Override the HostWindowsPageType method in the App class

protected override Type HostWindowsPageType()
{
     return typeof(HostPage);
}

Build and run the UWP application

iOS

Update the AppDelegate as follows

public partial class AppDelegate : MvxFormsApplicationDelegate<MvxFormsIosSetup<Core.App, UI.App>, Core.App, UI.App>
{ }

Build and run the iOS application.

Android

Rename and update the MainActivity as follows. Again, we rename the activity to avoid confusion with any activity or view that would be automatically associated with MainViewModel.

public class HostActivity
         : MvxFormsAppCompatActivity<MvxFormsAndroidSetup<Core.App, UI.App>, Core.App, UI.App>
{ }

Build and run the Android application.

You may experience a build error when you attempt to build and run the Android application, relating to referencing the Mono.Android.Export library. In this case, use the Add Reference dialog to manually add the missing reference.

image

There you have it – all three platforms running Xamarin.Forms application powered by MvvmCross.

Getting Started with Xamarin.Forms and SDK Versions

Getting Started with Xamarin.Forms and SDK Versions

In my previous post I did a walk through of creating a new Xamarin.Forms application and setting up the Core and UI projects for multi-targeting. Whilst I covered updating the various NuGet packages, I didn’t look at the SDK versions for the three platforms. In this post I’m going to look at the options for setting the SDK version, as it’s important that you update this to target the latest SDK version, even if your application is going to support older platform versions.

Android

If you right-click on the Android head project and select Properties you’ll see the Project Properties pane.

Start by increasing the Target Framework by selecting the highest Android version that you have installed

image

Next, on the Android Manifest tab, select “Use Compile using SDK version” under the Target Android version. On this tab you can also set the Minimum Android version if you don’t want to accept the defaults – this may be relevant if you don’t want a massive support matrix for your application as it will prevent installation on devices running a version of Android older than the minimum.

image

Build and run the Android application to make sure you haven’t broken anything and then commit your changes – in this case the first change would have made changes to the Android csproj file, whereas the second change would have changed the AndroidManifest.xml file.

iOS

Setting the SDK Version for iOS is straight forward and the recommendation is to leave the “Default” (which should be the default value) in the SDK Version dropdown on the iOS Build tab on the Properties pane for the iOS application.

image

If you want to adjust the minimum supported version of iOS, you can do this by double-clicking the Info.plist file for your iOS application and then adjusting the Deployment Target.

image

UWP

Both the Target and Min version of the UWP application can be set from the Application tab of the Project Properties pane. Setting the Target version defines the SDK version that will be used to compile the application and thus the APIs that are available.

image


Core and UI

Now that the Core and UI libraries are set to be multi-targeted it is also necessary to define what the target framework/version should be for each platform. If you don’t do this, you may be limited as to what platform APIs are available. Rather than setting these values in each of the libraries, we can create a file, Directory.build.targets, in the solution folder and include the appropriate elements there – this will get included in all projects that support the new csproj format. In this case the contents of our Directory.build.targets file will look like

<Project>
   <PropertyGroup Condition=”$(TargetFramework.StartsWith(‘netstandard’))”>
     <DefineConstants>$(DefineConstants);NETSTANDARD;PORTABLE</DefineConstants>
   </PropertyGroup>
   <PropertyGroup Condition=”$(TargetFramework.StartsWith(‘uap’))”>
     <DefineConstants>$(DefineConstants);NETFX_CORE;XAML;WINDOWS;WINDOWS_UWP</DefineConstants>
     <TargetPlatformVersion>10.0.17134.0</TargetPlatformVersion>
     <TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
   </PropertyGroup>
   <PropertyGroup Condition=”$(TargetFramework.StartsWith(‘Xamarin.iOS’))”>
     <DefineConstants>$(DefineConstants);MONO;UIKIT;COCOA;IOS</DefineConstants>
   </PropertyGroup>
   <PropertyGroup Condition=”$(TargetFramework.StartsWith(‘MonoAndroid’))”>
     <DefineConstants>$(DefineConstants);MONO;ANDROID</DefineConstants>
   </PropertyGroup>
</Project>

The csproj for both Core and UI projects also needs to be updated to replace the target framework MonoAndroid81 with MonoAndroid90.

All your projects should now be targeting the latest framework/sdk versions. If you find that some, or all, of these changes don’t take effect, you may need to either reload specific projects, or restart Visual Studio.

Building a TipCalc using Platform Uno

Building a TipCalc using Platform Uno

Recently I’ve been playing around with Platform.Uno – I’ve long held the view that Microsoft’s Xamarin.Forms was a stop-gap in delivering a true cross-platform solution. Whilst Xamarin.Forms is a highly productive platform, it has some severe limitations, specifically around overriding the look and feel of the native controls. This is where Flutter has stolen a lot of mindshare, mainly because customers and companies looking to build apps, no longer look for apps that match the platform style. They’re much more focussed on strong brand presence and great user experience, meaning that a great Material app on iOS will get better reviews and usage than a mediocre app that uses the default iOS style. Platform Uno attempts to deliver on what I believe the Universal Windows Platform (UWP) should have been – taking UWP XAML across iOS, Android and Web Assembly.

Anyhow, here goes with building a TipCalc. I’ll start with the basic UWP application:

I’ll create a separate project for our ViewModel:

Running the UWP app at this point gives an operational tip calculator

image

So now, let’s add some Uno goodness. We’ll start by moving the MainPage.xaml into its own class library:

  • Add a new project based on the Class Library (.NET Standard) project template, TipCalc.UI
  • Remove class1.cs
  • Add reference to project TipCalc.Core
  • Move MainPage.xaml and MainPage.xaml.cs to the TipCalc.UI project
  • Change namespace from TipCalc.UWP to TipCalc.UI for both MainPage.xaml and MainPage.xaml.cs
  • Edit TipCalc.UI.csproj to allow it to multi-target (ie generate multiple dlls that target UWP, Droid, iOS etc) and make sure correct build action is set for MainPage.xaml
  • Add reference to Uno.UI nuget package (currently in prerelease).
  • Final TipCalc.UI.csproj should look similar to
  • <Project Sdk=”MSBuild.Sdk.Extras/1.5.4″>
       <PropertyGroup>
         <TargetFrameworks>xamarinios10;MonoAndroid80;uap10.0</TargetFrameworks>
       </PropertyGroup>


      <PropertyGroup Condition=” ‘$(TargetFramework)’ == ‘uap10.0’ “>
         <GenerateLibraryLayout>true</GenerateLibraryLayout>
       </PropertyGroup>


      <ItemGroup Condition=” ‘$(TargetFramework)’ == ‘uap10.0’ “>
         <PackageReference Include=”Microsoft.NETCore.UniversalWindowsPlatform” Version=”6.1.5″ />
       </ItemGroup>


      <ItemGroup>
         <PackageReference Include=”Uno.UI” Version=”1.31.0-dev.52″ />
       </ItemGroup>


      <ItemGroup>
         <Page Include=”MainPage.xaml”>
           <SubType>Designer</SubType>
           <Generator>MSBuild:Compile</Generator>
         </Page>
       </ItemGroup>


      <ItemGroup>
         <ProjectReference Include=”..TipCalc.CoreTipCalc.Core.csproj” />
       </ItemGroup>
    </Project>

  • Add Uno.UI nuget reference to TipCalc.Core. Resulting csproj should look similar to
  • <Project Sdk=”MSBuild.Sdk.Extras/1.5.4″>
       <PropertyGroup>
         <TargetFrameworks>xamarinios10;MonoAndroid80;uap10.0</TargetFrameworks>
       </PropertyGroup>


      <ItemGroup>
         <PackageReference Include=”Uno.UI” Version=”1.31.0-dev.52″ />
       </ItemGroup>
    </Project>

  • Add reference to TipCalc.UI to TipCalc.UWP

By all accounts at this point you’ve done a fair bit of lifting with out much to show for it. In fact, because of some absolute genius coding by Microsoft, if you run the UWP application at this point you’ll most likely see a System.AccessViolationException when attempting to navigate to MainPage

image

This seems to be an issue where you’re attempting to navigate to a page that’s defined in a separate assembly and there are no other XAML pages defined in the head (ie UWP) project. Simple solution is just to add a dummy page to the UWP project that you’ll never use…. but seriously Microsoft??? Oh, and this isn’t the first time this has been pointed out (see https://social.msdn.microsoft.com/Forums/windowsserver/en-US/4efa91ad-fa8f-45f0-9864-c2fd2b24477c/uwpc-accessviolationexception-when-navigating-froma-another-assembly?forum=wpdevelop which links to an old post http://danielvaughan.org/posts/uwp/2015/08/15/UWP-AccessViolationException-when-Navigating-to-a-Page-in-Another-Assembly/)

Right, so the question is – after all this effort, how are we any closer to having a cross platform application. Well, let’s spit out the Android build:

  • Add a new project based on the Android App (Xamarin) project template, TipCalc.Droid
    image
  • Use the Blank App template
  • Uninstall any of the Xamarin.Android.Support nuget packages that are installed by default
  • Add reference to Uno.UI nuget package
  • Add reference to both TipCalc.UI and TipCalc.Core
  • Add a reference to Mono.Android.Export
    image
  • Add App.xaml and App.xaml.cs from the TipCalc.UWP project to the TipCalc.Droid project As Link
    image
  • Alter MainActivity to the following
  • [Activity(
         MainLauncher = true,
         ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize,
         WindowSoftInputMode = SoftInput.AdjustNothing | SoftInput.StateHidden
    )]
    public class MainActivity : Windows.UI.Xaml.ApplicationActivity
    {
    }

  • Add an Application class as follows
  • [global::Android.App.ApplicationAttribute(
         Label = “@string/app_name”,
         LargeHeap = true,
         HardwareAccelerated = true,
         Theme = “@style/AppTheme”
    )]
    public class Application : Windows.UI.Xaml.NativeApplication
    {
         public Application(IntPtr javaReference, JniHandleOwnership transfer)
             : base(new App(), javaReference, transfer)
         {
         }
    }

Now we’re good to go. Set the TipCalc.Droid to be the start up project and off we go. The app looks basically the same as it did on UWP

image

This took quite a bit of effort to get going but now that it’s there, you can imagine that productivity is going to be quite good. Next up I’ll add in the iOS project but I don’t envisage that, nor Web Assembly, being that hard from the samples I’ve seen to date.

Source code available at https://github.com/nickrandolph/UnoSamples

MvvmCross: Initialize method on the first view model

MvvmCross: Initialize method on the first view model

An issue was raised on MvvmCross following the release of v6 where applications were breaking because they have async code in the Initialize method of the first view model. Changes in v6 mean that the first view model is effectively loaded synchronously. This change was made because applications should not do heavy lifting before displaying the first view of their application as there are platform requirements that will cause the application to terminate if it doesn’t display the first view within the appropriate time window. This change means that any code that attempts to jump to a different thread (even something like Task.Delay) will cause the fist view of the application to break.

In some scenarios this doesn’t make sense – for example if you have a splash screen Activity on Android, the first navigation can be done asynchronously because you already have a view being displayed on the screen. Here I’m going to use a simple example to demonstrate how to resolve this issue – you should only use this if you are using a splash screen for the first view of your application.

Let’s start by breaking our application by adding the following to our first view model:

public override async Task Initialize()
{
     await Task.Delay(2000);
     await base.Initialize();
}

If you make this change and attempt to run your application you’ll see a black screen (on Android – and I’m using Android because we typically have a splash Activity such as in my earlier post).

Next we’re going to fix this by overriding the MvxAppStart class to make the first navigation asynchronous:

public class CustomMvxAppStart<TViewModel> : MvxAppStart<TViewModel>
     where TViewModel : IMvxViewModel
{
     public CustomMvxAppStart(IMvxApplication application, IMvxNavigationService navigationService) : base(application, navigationService)
     {
     }


    protected override void NavigateToFirstViewModel(object hint)
     {
         NavigationService.Navigate<TViewModel>();
     }
}

Note that it’s the bold line that we’ve changed from the built in MvxAppStart class where we call NavigationService.Navigate<TViewModel>().GetAwaiter().GetResult(); which forces the navigation to be done synchronously.

We now need to make sure that our CustomMvxAppStart is used. To do this we just need to change a single line in the App.cs to use RegisterCustomAppStart instead of RegisterAppStart

RegisterCustomAppStart<CustomMvxAppStart<FirstViewModel>>();

And we’re done – running the application now will allow the application to load successfully.

MVX=1: TipCalc – a second example – adding IoC and the Xamarin Android Designer (MVX+1 days of MvvmCross)

MVX=1: TipCalc – a second example – adding IoC and the Xamarin Android Designer (MVX+1 days of MvvmCross)

Following on from the first post in the MVX+1 series, in this post we’ll create a basic Tip Calculator (mirroring the original post from the N+1 series). However, in this case the first section is a more detailed set of instructions on how to get the basics of all three platforms setup with MvvmCross. Going forward we’ll use this as a starting point so that we don’t need to cover over this in each subsequent post.

Source code: https://github.com/nickrandolph/MvxPlus1DaysOfMvvmCross/tree/master/Mvx-01-TipCalc

Getting Started Instructions (Native Apps)

Note: In this case the name of the application is TipCalc but these instructions can be followed to get any new project started by simply replacing TipCalc with the name of your project.

  1. Create a the new solution by creating a new Class Library (.NET Standard) with the project name set to TipCalc.Core and the solution name to just TipCalc.
  2. Add a new project based on the Blank App (Universal Windows) project template called TipCalc.Uwp (make sure that the Minimum and Target versions are set to at least the Fall Creators Update)
  3. Add a new project based on the Android App (Xamarin) project template called TipCalc.Droid (use the Blank app template)
  4. Add a new project based on the iOS App (Xamarin) project template called TipCalc.iOS (use the Blank app template)
  5. Add a reference to MvvmCross NuGet package (v6.0.0 at time of writing to all four projects)
  6. TipCalc.Uwp: Update NuGet package Microsoft.NETCore.UniversalWindowsPlatform to the latest stable version (6.0.8 at time of writing)
  7. TipCalc.Droid: Update the Android version to Use Latest Platform (Project Properties –> Application –> Target Framework)
  8. TipCalc.Droid: Update Xamarin.Android.Support.Design to latest stable version (27.0.2 at time of writing)
  9. TipCalc.Droid: Add a reference to MvvmCross.Droid.Support.V7.AppCompat package
  10. TipCalc.iOS: Unload project; delete packages.config; edit TipCalc.iOS.csproj and add the following ItemGroup
    <ItemGroup>
       <PackageReference Include=”MvvmCross” Version=”6.0.0″ />
    </ItemGroup>

  11. Add a reference to TipCalc.Core to each of the three head projects (ie TipCalc.Uwp, TipCalc.Droid and TipCalc.iOS)
  12. TipCalc.Core: Rename the default Class1.cs to App.cs, and allow Visual Studio to rename class to App
  13. TipCalc.Core: Change the App class to inherit from MvxApplication
  14. TipCalc.Core: Add a folder, ViewModels, and add a class called FirstViewModel.
  15. TipCalc.Core: Change FirstViewModel to inherit from MvxViewModel
  16. TipCalc.Core: Override Initialize method in App to register services and set startup view model to FirstViewModel
    public override void Initialize()
    {
         CreatableTypes()
                 .EndingWith(“Service”)
                 .AsInterfaces()
                 .RegisterAsLazySingleton();
         RegisterAppStart<FirstViewModel>();
    }

  17. TipCalc.Uwp: Add a help class ProxyMvxApplication

    public abstract class ProxyMvxApplication: MvxApplication<MvxWindowsSetup<Core.App>, Core.App> { }
  18. TipCalc.Uwp: Change App.xaml and App.xaml.cs to inherit from ProxyMvxApplication
  19. TipCalc.Uwp: Remove all code in App.xaml.cs other than the constructor which should contain a single call to InitializeComponent
  20. TipCalc.Uwp: Delete MainPage.xaml and MainPage.xaml.cs
  21. TipCalc.Uwp: Add a Views folder, and  add a FirstView based on the Blank Page template
  22. TipCalc.Uwp: Change FirstView.xaml and FirstView.xaml.cs to inherit from MvxWindowsPage
  23. TipCalc.Droid: Add a new class, MainApplication, that inherits from MvxAppCompatApplication
  24. [Application]
    public class MainApplication : MvxAppCompatApplication<MvxAppCompatSetup<App>, App>
    {
         public MainApplication(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
         {
         }
    }

  25. TipCalc.Droid: Rename MainActivity.cs to SplashScreen.cs and let Visual Studio rename the class
  26. TipCalc.Droid: Rename activity_main.axml to SplashScreen.axml, and adjust layout to indicate application loading
  27. TipCalc.Droid: Adjust SplashScreen class to inherit from MvxSplashScreenAppCompatActivity and set NoHistory to true (since we don’t want the user to be able to press the back button and go back to the splash screen)

    [Activity(Label = “@string/app_name”, Theme = “@style/AppTheme”, MainLauncher = true, NoHistory = true)]
    public class SplashScreen : MvxSplashScreenAppCompatActivity

  28. TipCalc.Droid: Add a folder, Views, and add a new Activity, FirstView.c
  29. [Activity(Label = “FirstView”)]
    public class FirstView : MvxAppCompatActivity<FirstViewModel>
    {
         protected override void OnCreate(Bundle bundle)
         {
             base.OnCreate(bundle);


            SetContentView(Resource.Layout.FirstView);
         }
    }

  30. TipCalc.Droid: Add a new Android Layout to the Resources/Layout folder, FirstView.axml
  31. TipCalc.Droid: You may run into an error: “error XA4210: You need to add a reference to Mono.Android.Export.dll when you use ExportAttribute or ExportFieldAttribute.” If you do, you just need to Add Reference to Mono.Android.Export (search in the Add Reference dialog).
  32. TipCalc.iOS: Update AppDelegate class to inherit from MvxApplicationDelegate, and remove the default code.
    [Register(“AppDelegate”)]
    public class AppDelegate : MvxApplicationDelegate<MvxIosSetup<App>, App>
    {
    }
  33. TipCalc.iOS: Add an Empty Storyboard, called Main.storyboard, to the root of the project
  34. TipCalc.iOS: Add a ViewController to the Main.storyboard using the designer and set the Class and Storyboard ID to FirstView (also make sure the “User Storyboard ID” checkbox is set to true)
  35. TipCalc.iOS: Move the generated FirstView.cs and FirstView.designer.cs files (from the previous step) into a new folder called Views, and adjust the namespace of the FirstView class to FirstView.iOS.Views
  36. TipCalc.iOS: Update the FirstView class to inherit from MvxViewController
    [MvxFromStoryboard(“Main”)]
    public partial class FirstView : MvxViewController<FirstViewModel>

Now to actually build out the Tip Calculator. Rather than embed the calculation logic into our view model, we’re going to abstract it out into a service. To do this we’ll make use of the IoC container made available by MvvmCross. We’ll register a CalculationService which will be injected into our view model constructor.

Let’s continue our development of the Tip Calculator in TipCalc.Core:

  1. Add a folder called Services
  2. Add an interface ICalculationService into the Services folder
    public interface ICalculationService
    {
         double Tip(double subTotal, double generosity);
    }
  3. Add a class, CalculationService, which implements ICalculationService, again into the Services folder
    public class CalculationService : ICalculationService
    {
         public double Tip(double subTotal, double generosity)
         {
             return subTotal * generosity / 100.0;
         }
    }
  4. Add a constructor to the FirstViewModel which accepts an ICalculationService parameter
  5. private readonly ICalculationService _calculationService;
    public FirstViewModel(ICalculationService calculationService)
    {
         _calculationService = calculationService;
    }

  6. Add properties for SubTotal, Generosity, Tip and Total. Each property should take the following form where SetProperty is called within the setter
    private double _subTotal;
    public double SubTotal
    {
         get { return _subTotal; }
         set { SetProperty(ref _subTotal, value); }
    }
  7. Add a Recalc method which will invoke the Tip method on the ICalculationService
    private void Recalc()
    {
         Tip = _calculationService.Tip(SubTotal, Generosity);
         Total = SubTotal + Tip;
    }
  8. Add a call to Recalc into the setter for both SubTotal and Generosity
  9. Set some initial values for the SubTotal and Generosity (if you use the property setters, rather than setting the fields, the Recalc method will be invoked)

That’s it for the core logic for the application. Now we just need to wire up the UI for each platform.

One thing that’s worth noting is that in step 16 of the original setup where the Initialize method is overridden, there is logic in the Initialize method to interrogate the current assembly looking for all classes that end in Service and register them, based on their interface, with the MvvmCross IoC container – this is how MvvmCross knows about the implementation of the ICalculationService which is used when instantiating the FirstViewModel.

Let’s built out the UWP interface in TipCalc.Uwp:

  1. Add the following XAML inside the existing Grid element:
    <StackPanel>
         <TextBlock Text=”SubTotal”/>
         <TextBox Text=”{Binding SubTotal, Mode=TwoWay}”/>
         <TextBlock Text=”How generous?”/>
         <Slider Value=”{Binding Generosity, Mode=TwoWay}”
                 Minimum=”0″
                 Maximum=”100″/>
         <TextBlock Text=”Tip:”/>
         <TextBlock Text=”{Binding Tip}”/>
         <TextBlock Text=”SubTotal:”/>
         <TextBlock Text=”{Binding Total}”/>
    </StackPanel>

That’s the UWP interface done – four elements (with TextBlock headings): TextBox and Slider for inputting SubTotal and Generosity using two-way data binding, and two TextBlock for outputting the Tip and Total amounts.

Now let’s do Android:

  1. Add the following namespace declaration to FirstView.axml
  2. Add the following xml to FirstView.axml
    <TextView
         android_text=”SubTotal”
         android_textAppearance=”?android:attr/textAppearanceMedium”
         android_layout_width=”fill_parent”
         android_layout_height=”wrap_content”
         android_id=”@+id/textView1″ />
    <EditText
         android_layout_width=”fill_parent”
         android_layout_height=”wrap_content”
         android_id=”@+id/editText1″
         local:MvxBind=”Text SubTotal” />
    <TextView
         android_text=”Generosity”
         android_textAppearance=”?android:attr/textAppearanceMedium”
         android_layout_width=”fill_parent”
         android_layout_height=”wrap_content”
         android_id=”@+id/textView2″ />
    <SeekBar
         android_layout_width=”fill_parent”
         android_layout_height=”wrap_content”
         local:MvxBind=”Progress Generosity”
         android_id=”@+id/seekBar1″ />
    <TextView
         android_text=”Tip”
         android_textAppearance=”?android:attr/textAppearanceMedium”
         android_layout_width=”fill_parent”
         android_layout_height=”wrap_content”
         android_id=”@+id/textView3″ />
    <TextView
         android_textAppearance=”?android:attr/textAppearanceMedium”
         android_layout_width=”fill_parent”
         android_layout_height=”wrap_content”
         local:MvxBind=”Text Tip”
         android_id=”@+id/textView4″ />
    <TextView
         android_text=”Total”
         android_textAppearance=”?android:attr/textAppearanceMedium”
         android_layout_width=”fill_parent”
         android_layout_height=”wrap_content”
         android_id=”@+id/textView5″ />
    <TextView
         android_textAppearance=”?android:attr/textAppearanceMedium”
         android_layout_width=”fill_parent”
         android_layout_height=”wrap_content”
         local:MvxBind=”Text Total”
         android_id=”@+id/textView6″ />

In this case we’re leveraging the xml extensions offered by MvvmCross in order to do the data binding using the MvxBind syntax.

Finally, let’s do iOS:

  1. Add the following code to the FirstView.cs
    public override void ViewDidLoad()
    {
         base.ViewDidLoad();

  2.     // Perform any additional setup after loading the view
         var label = new UILabel(new RectangleF(10, 0, 300, 40));
         label.Text = “SubTotal”;
         Add(label);


        var subTotalTextField = new UITextField(new RectangleF(10, 40, 300, 40));
         Add(subTotalTextField);


        var label2 = new UILabel(new RectangleF(10, 80, 300, 40));
         label2.Text = “Generosity?”;
         Add(label2);


        var slider = new UISlider(new RectangleF(10, 120, 300, 40));
         slider.MinValue = 0;
         slider.MaxValue = 100;
         Add(slider);


        var label3 = new UILabel(new RectangleF(10, 160, 300, 40));
         label3.Text = “Tip”;
         Add(label3);


        var tipLabel = new UILabel(new RectangleF(10, 200, 300, 40));
         Add(tipLabel);


        var label4 = new UILabel(new RectangleF(10, 240, 300, 40));
         label4.Text = “Total”;
         Add(label4);


        var totalLabel = new UILabel(new RectangleF(10, 280, 300, 40));
         Add(totalLabel);


       var set = this.CreateBindingSet<FirstView, FirstViewModel>();
         set.Bind(subTotalTextField).To(vm => vm.SubTotal);
         set.Bind(slider).To(vm => vm.Generosity);
         set.Bind(tipLabel).To(vm => vm.Tip);
         set.Bind(totalLabel).To(vm => vm.Total);
         set.Apply();

    }

In this case for iOS we again make use of the data binding support provided by MvvmCross by using the CreateBindingSet method, followed by a call to Bind for each element property we want to bind, and then finally a call to Apply to complete the setup of data binding.

And that’s it – a Tip Calculator for all three platforms.

MVX=0F Side Note: Adding a Splash Screen

MVX=0F Side Note: Adding a Splash Screen

I received some feedback on my previous post on setting up MvvmCross for Xamarin.Forms, asking how to add a splash screen to the Android Forms application. In the post MVX=0 I converted the MainActivity that comes as part of the standard Xamarin Android project into a SplashScreen but when it came to the Android project for Xamarin.Forms I left it without a splash screen.

Luckily adding a splash screen is really easy, so let’s add one to the Forms.Droid project:

  1. Copy the SplashScreen.axml from the /Resources/layout folder in the FirstDemo.Droid project into the /Resources/layout folder in the Forms.Droid project
  2. Remove “MainLauncher = true” from the Activity attribute on the MainActivity
  3. Change the MainActivity inheritance:
    public class MainActivity : MvxFormsAppCompatActivity<MainViewModel>

  4. Add a new class, SplashScreen.cs:
    [Activity(Label = “FirstDemo.Forms.Splash”, Theme = “@style/MainTheme”, MainLauncher = true, NoHistory = true)]
    public class SplashScreen : MvxFormsSplashScreenAppCompatActivity<MvxFormsAndroidSetup<Core.App, App>, Core.App, App>
    {
         public SplashScreen() : base(Resource.Layout.SplashScreen)
         {
         }

  5.     protected override void RunAppStart(Bundle bundle)
         {
             StartActivity(typeof(MainActivity));
             base.RunAppStart(bundle);
         }
    }

And there you have it – the Android Xamarin.Forms project will launch with a splash screen before redirecting to the MainActivity which will host the Xamarin.Forms content.

MVX=0F: A first MvvmCross Application (MVX+1 days of MvvmCross)

MVX=0F: A first MvvmCross Application (MVX+1 days of MvvmCross)

Updated 16/4/2018: Reference to MvvmCross have been updated to v6.0.0

One of the awesome things about MvvmCross is that you can take the exact same set of ViewModels that you used for your UWP, iOS, Android applications and use them in a Xamarin Forms application. As we go through the MVX+1 series, I’ll make some space for talking about Xamarin Forms as well.

In this post we’re going to extent what we started in the previous post by adding a Xamarin Forms interface – this means creating new head projects for iOS, Android and UWP too. All up we’re adding four new projects but fear not, most of the heavy lifting is done by Visual Studio:

Into our existing solution we’re going to add a new Xamarin Forms project:

  1. Add a new Mobile App (Xamarin.Forms) project called FirstDemo.Forms
    image_thumb1_thumb
  2. When prompted, select Blank App, make sure all three Platforms are checked and make sure you select the .NET Standard option (Do NOT use the Share Project option).
    image_thumb3_thumb
  3. Upgrade the Xamarin.Forms NuGet to latest for all four Forms projects (at time of writing is 2.5.1.444934)
  4. Add MvvmCross NuGet Package to all Forms projects (Forms, Forms.iOS, Forms.Android and Forms.UWP)
  5. Add MvvmCross.Forms NuGet Package to all Forms projects (Forms, Forms.iOS, Forms.Android and Forms.UWP)

Note: You may need to upgrade to latest NuGet packages for all Forms projects before you can add references to the MvvmCross packages.

Update the FirstDemo.Forms project

  1. Remove all code in App class except for constructor with a call to InitializeComponent
  2. Create Views folder
  3. Move MainPage into Views folder and rename to FirstView
  4. Adjust FirstView.xaml and FirstView.xaml.cs to change class name to FirstView and to make it inherit from MvxContentPage
  5. Add two Entry and a Label with data binding to FirstView.xaml

Update the FirstDemo.Forms.Uwp project

  1. Update Microsoft.NETCore.UniversalWindowsPlatform (v6.0.8 at time of writing)
  2. Add reference to FirstDemo.Core
  3. Change MainPage to inherit from MvxFormsWindowsPage
  4. Remove all code other than the InitializeComponent method call in the constructor of MainPage
  5. Add ProxyMvxApplication
    public abstract class ProxyMvxApplication : MvxWindowsApplication<MvxFormsWindowsSetup<Core.App, FirstDemo.Forms.App>, Core.App, FirstDemo.Forms.App, MainPage>
  6. Change App.xaml and App.xaml.cs to inherit from ProxyMvxApplication
  7. Remove all code other than the constructor, with a single call to InitializeComponent, in App.xaml.cs

Update the FirstDemo.Forms.Android project

Note (1): If you run into the following error, you may need to rename your project. In this case we renamed it to Forms.Droid (as well as the folder the project resides in)
1>C:Program Files (x86)Microsoft Visual StudioPreviewEnterpriseMSBuildXamarinAndroidXamarin.Android.Common.targets(2088,3): error MSB4018: System.IO.PathTooLongException: The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.

Note (2): If you’re using the preview build of Visual Studio, you may run into an error: “error XA4210: You need to add a reference to Mono.Android.Export.dll when you use ExportAttribute or ExportFieldAttribute.” If you do, you just need to Add Reference to Mono.Android.Export (search in the Add Reference dialog).

  1. Change Forms.Android project to target latest Android SDK (v8.1 at time of writing)
  2. Upgrade Xamarin.Android.Support.* to latest for the Forms.Android project
  3. Add reference to FirstDemo.Core
  4. Change MainActivity inheritance, remove code except for a constructor:
    public class MainActivity : MvxFormsAppCompatActivity<MvxFormsAndroidSetup<Core.App, App>, Core.App, App>
    {
    }

Update the FirstDemo.Forms.iOS project

  1. Add reference to FirstDemo.Core
  2. Changed inheritance of AppDelegate
    public partial class AppDelegate : MvxFormsApplicationDelegate<MvxFormsIosSetup<Core.App, FirstDemo.Forms.App>, Core.App, FirstDemo.Forms.App>

And there you have it – you should be able to build and run all three Forms projects utilising the same view models that the non-Forms projects used