Xamarin

[SOLVED] Firebase Performance Monitoring in Xamarin Android

Oliver Brown
— This upcoming video may not be available to view yet.

I decided to add Firebase Performance Monitoring to the latest version of Tic-tac-toe Collection.

What is it

This allows you to collect timed traces of things that happen in your app. You can set up custom traces for anything you like, but it also tracks how long HTTP requests take by default. At least it’s supposed to. On iOS it worked well, but Android had nothing.

There is an open issue on the repo with the Xamarin binding that was created in December 2018. It includes suggestions to make sure your app is set to using the native HTTP handlers (which makes sense since whatever Firebase is doing it won’t be expecting a random third party HTTP stack to be used), however it still does not work.

How does it work

So I decided to investigate how the HTTP tracing is actually implemented. How found this Stack Overflow question which lead me to this video. It turns out the implementation works by doing some byte code rewriting that changes any references in your app to the HTTP classes to instead reference Firebase provided wrappers.

Why doesn’t it work for Xamarin Android?

I kind of assumed it was doing something like that, but didn’t really think through the implications. Specifically - it does the byte code rewriting as part of a Gradle plugin that is not executed as part of a Xamarin build.

Solution

It may be possible to get the Gradle plugin to execute it’s transformer, but that seems complicated. Luckily, Firebase does provide support for adding HTTP tracing to other libraries, so I decided to work with that.

I decided to implement my own HttpMessageHandler that sets up the HttpMetric and then delegates to a normal HttpClientHandler. This can be passed into the constructor of HttpClient.

public class FirebaseHttpMessageHandler : DelegatingHandler
{
    public FirebaseHttpMessageHandler() : base(new HttpClientHandler())
    {
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var metric = StartTracking(request);
        var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
        StopTracking(metric, response);
        return response;
    }

    private HttpMetric? StartTracking(HttpRequestMessage request)
    {
        try
        {
            var url = new Java.Net.URL(request.RequestUri.AbsoluteUri);
            var metric = Firebase.Perf.FirebasePerformance.Instance.NewHttpMetric(url, request.Method.Method);
            metric.Start();
            if (request.Content?.Headers?.ContentLength is long length)
            {
                metric.SetRequestPayloadSize(length);
            }

            return metric;
        }
        catch (Exception ex)
        {
            Debug.Fail($"URL performance tracking failed: {request.RequestUri.AbsoluteUri} - {ex.Message}");
            return null;
        }
    }

    private void StopTracking(HttpMetric? metric, HttpResponseMessage response)
    {
        if (metric is null)
        {
            return;
        }
        try
        {
            metric.SetHttpResponseCode((int)response.StatusCode);
            if (response.Content?.Headers?.ContentLength is long length)
            {
                metric.SetResponsePayloadSize(length);
            }
            if (response.Content?.Headers?.ContentType?.MediaType is string mediaType)
            {
                metric.SetResponseContentType(mediaType);
            }
        }
        catch (Exception ex)
        {
            Debug.Fail($"URL performance tracking failed: {response.RequestMessage.RequestUri.AbsoluteUri} - {ex.Message}");
        }
        finally
        {
            metric.Stop();
        }
    }
}

Why does it work for Xamarin iOS?

I don’t know the exact method used on iOS, but I do know that iOS has a feature called NSURLProtocol that lets you intercept all HTTP requests by the app, as well as method swizzling which lets you replace basically any method implementation at runtime.

Either of those could be used, and they would both just work in Xamarin.

Accessing the UI in Xamarin.iOS

Oliver Brown
— This upcoming video may not be available to view yet.

An interesting discussion happened recently, triggered by a code review of (something like) the following C#:

public class ProductViewController
{
    private UIView _detailsView { get; set; }
    private ProductViewModel _viewModel { get; set; }

    private void Process()
    {
        if (_viewModel.ProcessDetails)
        {
            InvokeOnMainThread(() =>
            {
                if (_detailsView != null)
                {
                    UpdateDetailsView();
                }
            });
        }
    }
}

One of the reviewers suggested moving the second if outside the call to InvokeOnMainThread (and then combining it with the other if).

The theory was that it would more efficient to check if we need to be on the main thread before we do it, instead of doing the check on the main thread and finding out we have nothing to do.

The original author pushed back saying you can’t access _detailsView off the main thread since you would get an exception.

On the surface this sounds reasonable - everyone knows you can only access UIKit objects on the main thread. But it naturally leads to the question: what does “accessing a UIKit object” actually mean?

So I wrote a quick sample that intentionally tries to do lots of UIKit manipulation on background threads in various ways:

The tests

Quick refresher. The View property of a newly constructed UIViewController is not populated until it is first accessed. Some of the tests below refer to accessing this property either before or after it is created. By default properties declared in C# will not be visible to any native iOS code. They can be made visible by adding the [Export] attribute.

  • Create a UIViewController.
  • Create a UIView.
  • Create a UIColor.
  • Check if a view controller’s View property is equal to null.
  • Check if a view controller’s View property is null using pattern matching.
  • Check if a view controller’s IsViewLoaded property is equal to true.
  • Check if a view controller’s View property is equal to null after previously creating View on the main thread.
  • Check if a view controller’s View property is null using pattern matching after previously creating View on the main thread.
  • Check if a view controller’s IsViewLoaded property is equal to true after previously creating View on the main thread.
  • Check if a new UIView property, that is not exported is equal to null.
  • Check if a new UIView property, that is not exported is null using pattern matching.
  • Check if a new UIView property, that is exported is equal to null.
  • Check if a new UIView property, that is exported is null using pattern matching.
  • Check if a view controller’s NavigationController property is equal to null.
  • Check if a view controller’s NavigationController property is null using pattern matching.
  • Set a new UIView property, that is not exported, with a view created on the main thread.
  • Set a new UIView property, that is exported, with a view created on the main thread.

Results

Test Result
Create UIViewController Exception
Create UIView Exception
Create UIColor OK
Check if View is equal to null Exception
Check if View is null pattern Exception
Check if View is loaded Exception
Check if View is equal to null after creating View Exception
Check if View is null pattern after creating View Exception
Check if View is loaded after creating View Exception
Check if non-exported view is equal to null OK
Check if non-exported view is null pattern OK
Check if exported view is equal to null OK
Check if exported view is null pattern OK
Check if NavigationController is equal to null Exception
Check if NavigationController is null pattern Exception
Set non-exported view OK
Set exported view OK

Summary

This is by no means exhaustive, but it seems in general, acessing properties declared natively in iOS will throw an exception whereas accessing properties you have declared yourself will be fine. I had a suspicion that an exported view might behave the same as a native property, but apparently not.

The code for this test is available on GitHub.

The future of Microsoft MAUI (and Xamarin Forms)

Oliver Brown
— This upcoming video may not be available to view yet.

Since Google seems to like my post about the future of Xamarin Forms so much (and I have a slight history of such posts), I’d figure I’d post an update about interesting things happening in the Xamarin Forms repo specifically related to MAUI.

Renaming

The change that actually made me write this post - a large PR with 5000+ changed files that changes the Xamarin Forms name to MAUI.

Not much of a thing for actual functionality, but a significant symbolic milestone.

Handlers and the great big architecture shift

.NET MAUI will completely change the way renderers are handled in Xamarin Forms. There are many advantages of doing it the new way, but the mechanics of how it is done are fairly complex. This video by Javier Suárez covers it well.

Interacting with this video is done so under the Terms of Service of YouTube
View this video directly on YouTube

This is all happening right now in the main-handler branch.

Update

While I was writing this, work officially moved to the dotnet/maui repo and it is accepting pull requests directly.

AppHost and Microsoft.Extensions

Originally an ASP.NET concept, that then migrated its way to Windows client development, this provides a common way to provide dependency injection, logging, and lots of other infrastructure stuff. In isolation, the pattern and implementation is good and will make it easier to override certain things in MAUI (such as handlers). It’s also useful in a wider sense since it will make configuring different styles of .NET apps more similar.

Single project

Over the past couple of years there has been a move towards producing Xamarin libraries (and .NET libraries in general) using a single multi-targeted project. The most significant is probably Xamarin Essentials. This PR adds support for creating applications following the same pattern.

Merging in Xamarin Essentials

There is a lot of functionality in Xamarin Essentials that Xamarin Forms would like to use. Likewise there is some functionality in Forms that is useful when not using Forms. This lead to some overlap in functionality (and occasionally overlap in APIs but not a perfect match in functionality).

There was an attempt to add Essentials as a dependency of Forms but it faced some problems, and there was a “change of plans”.

Now the solution is to have Forms and Essentials in the same repo. I hope Essentials remains available as its own Nuget package (and it looks like that will be the case).

Resizetizer.NT

Resizertizer.NT, like its predecessor Resizetizer, is a package for generating platform specific images in all the right sizes at build time.

Managing image assets across iOS and Android (and using Visual Studio) has always been an unpleasant process. This tool makes it much easier and will be included in MAUI by default.

Mobile apps, ads and consent

Oliver Brown
— This upcoming video may not be available to view yet.

I’ve recently spent some time adding the Google User Messaging Platform (UMP) to Tic-tac-toe Collection. The motivating factor was needing to support App Tracking Transparency in iOS 14 when using AdMob, but more generally, due to the GDPR, apps have significant requirements around consent and data management (especially with ads) and my haphazard custom implementation was a pain and probably not entirely compliant.

My effort to do this led me to learning quite a bit about the current state of this in apps and on the web.

Aside - Technical implementation

UMP is provided as a native library for both Android and iOS. There are official Xamarin bindings available for each (they are very new, and for a while I had to bind the iOS implementation myself).

I created a cross-platform wrapper to make using it easier in a Xamarin Forms app.

Google UMP is an implementation of a Consent Management Platform (CMP) as defined by the IAB (I tried to find a link to a neutral definition, but if you search Google for “Consent Management Platform”, you get a whole load of ads for companies wanting to help you).

This will look very familiar to most European users (and probably others) since most websites display a popup with a similar setup. What I did not realize until investigating this is that the information and settings it contains (down to the exact wording in some cases) is very proscribed and there it not much leeway about how the information is presented (possibly explaining why they all feel so universally unpleasant to use).

More surprising, at least initially, is that the way this information is stored is actually really well defined as part of shared API. The popup which you provide consent through makes the information available to the hosting site (as well as advertising components on the page) in a predictable way.

A lot of the information is contained in this GitHub repo, with the API defined here.

The web API is really well specified and provides a JavaScript object available for anything on the page to query to get current consent status. The mobile API is a bit less so. Basically the data is stored in the shared preferences for the app (SharedPreferences on Android and NSUserDefaults on iOS) with well known keys you have to query yourself.

(Mainly just for fun, I created a package for querying this data with Xamarin.)

There a few things about the spec that I found interesting:

  • The “purposes” for which data can be used are very specifically defined, and numbered. Many things refer to them by number.
  • The list of vendors is also centrally determined and numbered.
  • There is what appears to be a typo in the spec: property names include VendorConsents, PurposeConsents and then PublisherConsent. This last one is structured the same as the others, but named in the singular. And since, like HTTP referer, it wasn’t caught before publication, it is now set in stone.

Some problems

There are some problems with this system. Some are general and some are specific to Google’s implementation.

The biggest is the language presented to the user is still very verbose. The whole point of the GDPR was to give users more insight and control about how their data is used. I seriously doubt many people will actually make an effort to understand all the purposes and the consequences of them.

One weird limitation of Google’s implementation is that it is impossible for the user to see their previous consent status and to tweak it slightly. When you first display the form, everything is turned off. The user can select to accept everything or dig through and accept individual permissions. If the form is presented again, everything is turned off again. If the user wanted to revoke or grant a specific permission, they’d have to remember themselves what they chose last time.

Even worse, there is no way to exit the form without making changes. If you launch them form, and select “Manage options”, your only way out saves the “everything off” state.

Purpose one

The first numbered purpose is “Store and/or access information on a device”. This is essentially a technology agnostic way of referring to a cookie. It doesn’t actually allow an app or website to do anything itself, it has to be combined with another purpose. And interesting things happen if the user does not grant it.

Most significantly, Google Mobile Ads (whether using AdMob or Google Ad Manager) will refuse to display any ads at all. In theory any app using Google Ads should be using a system that checks if the user is subject to the GDPR, request consent for purpose one and then respect it in this way.

The new update to Tic-tac-toe Collection does that. Which means European users who refuse consent will disables ads completely, for free. Since my ad revenue is low, and I’m already not a big fan of how mobile advertising tends to work… I’m kind of okay with it.

Interestingly, there is some debate about whether the GDPR actually requires this. If an app requires ads to be financially viable, and storing cookies is required to technically deliver ads (say for basic stats tracking or fraud prevention - not personalisation) that sounds very much like a legitimate interest, which means it can be done without consent. Google does address this here with the following quote

Google uses cookies or mobile ad identifiers to support ads measurement. Existing ePrivacy laws require consent for such uses, for users in countries where local law requires such consent. Accordingly, our policy requires consent for ads personalisation and ads measurement where applicable, even if ads measurement can, for GDPR purposes, be supported under a controller’s legitimate interests.

The future of Xamarin Forms

Oliver Brown
— This upcoming video may not be available to view yet.

Microsoft have just announced the future of Xamarin and Xamarin forms - the .NET Multi-platform App UI (or MAUI for short). As a name, it’s not great. The highlights are as follows:

  • It’s an evolution of Xamarin Forms. It basically is Xamarin Forms, but finally accepting some breaking changes. To be honest, I’m hoping for a lot since there is a lot of weirdness in Xamarin Forms that has been holding it back.
  • Single project, multi-targeted. It took a long time to get to the point where this was possible. From shared projects, to PCL projects, through .NET Standard. This should make things a lot easier.
  • Still based on platform renderers using native controls. This is a mixed bag. Using native controls has long been a selling point of Xamarin (with or without Forms). With the rise of Flutter this has been shown to be less important. Many people have been asking for consistent platform agnostic renderers instead.
  • The end of “Xamarin” as a name. Some time in the .NET 6 timeline (end of 2021) Xamarin.iOS will become .NET for iOS and Xamarin.Android will be .NET for Android. I have mixed feeling about this since this was a fairly succinct way to describe by top skillset.

I also already have my own enhancement issue submitted.

My second through fifth contributions to Xamarin Forms

Oliver Brown
— This upcoming video may not be available to view yet.

Xamarin Forms took part in Hacktoberfest, an effort to increase contributions to open source.

Like my previous contributions, three quarters of my PRs were targeting macOS. The main reason is the changes were straightforward (which makes it more disappointing how long some of the issues have been around).

I would like to say I wasn’t doing it for the t-shirt, but that wouldn’t really be true. I wouldn’t do it just for stickers though.

ListView improvements in Xamarin Forms

Oliver Brown
— This upcoming video may not be available to view yet.

Since becoming open source, it has become possible to find out potential upcoming features in Xamarin Forms by just poking around the active branches in the repository (macOS support was visible in the repo before any announcement). One of them is lv2spike. From just reading the commit messages, it seems this is a new CollectionView, based on UICollectionView for iOS and RecyclerView for Android. This is something that has been needed for a while, but is a big enough undertaking that I understand why it has taken a while. After all the branch suggests this is still just a spike. There are quite a lot of feature requests for the Xamarin Forms ListView that are just not possible (like this one for horizontal layout) mainly because the iOS implementation is based on UITableView. This will open lots of possibilities. My biggest concern is that despite the push forward with features, Xamarin Forms is accruing bugs even faster, and with the expanded platform support this could just get worse…

This is an imported post and may not be formatted correctly. View the original here.

Tic-tac-toe Collection open beta

Oliver Brown
— This upcoming video may not be available to view yet.

For various reasons I decided to write a Tic Tac Toe game in Xamarin Forms. At the moment it supports variable board sizes, variable win line size (so it implicitly supports Gomoku) and a few custom rules like misère, a pie rule and disallowed overlines.

It currently functions on Android, iOS and Windows, but is only released on Android for now.

Apart from experimenting with various features of Xamarin Forms (as well as managing Nuget packages), my goal is to try and add all the options. Features I’m planning:

  • Ultimate Tic-tac-toe
  • Quantum Tic-tac-toe
  • 3D (and 4D) Tic-tac-toe
  • Online multiplayer
  • Order and chaos
  • Wild Tic-tac-toe

Download Tic-tac-toe Collection from the Google Play Store.

[SOLVED] Unable to cast object of type 'Xamarin. Forms. Xaml. ElementNode' to type 'Xamarin. Forms. Xaml. ValueNode'.

Oliver Brown
— This upcoming video may not be available to view yet.

When writing XAML for Xamarin Forms, you may across the error: Unable to cast object of type 'Xamarin.Forms.Xaml.ElementNode' to type 'Xamarin.Forms.Xaml.ValueNode' This is nearly always caused by assigning a value to an event in XAML, instead of specifying a method name. A common example is: <Switch Toggled="{Binding IsToggled}" /> Toggled is the name of an event. The property that was probably intended is called IsToggled. <Switch IsToggled="{Binding IsToggled}" />