Categories
.NET

Dot Net DLLs, Droid, Dependencies

Bears, Beets, Battlestar Galactica meme from The Office TV Show

Natively, Android apps are built around activities. These are distinct parts of an application which include UI and are designed to perform a particular task. Android allows you to start activities and pass data between them. A number of system dialogs are just activities which run and return a result.

Across Platforms

When using a cross-platform framework, whether it be Xamarin Forms, Uno or .NET Maui your app will generally have only a single Activity. You can create a complex application and never touch the template generated activity code. However when you want to call into an Activity, whether it be your own, a third-party library or a system feature, you need to have a reference to your current activity in order to launch another.

Each framework has its own method to help with this. On Xamarin Forms this is exposed in the Xamarin.Essentials library – Xamarin.Essentials.Platform.CurrentActivity. When migrating to .NET Maui this moved to the Microsoft.Maui.Essentials library – Microsoft.Maui.ApplicationModel.Platform.CurrentActivity. The new project templates add a line of code to the default MainActivity to initialize this and store a reference to the running activity.

On Uno the Uno base library includes Uno.UI.ContextHelper.Current which stores a reference to the activity and is initialised in the base Microsoft.UI.Xaml.ApplicationActivity class.

What’s the point of all this?

If we want to create a .NET library which works on all these different frameworks and has access to the activity we have some work to do. We can’t create a NuGet targeting different frameworks because these are all net6.0-android – you can’t specify the UI tech. We don’t want to provide multiple virtually-identical libraries tweaked for each framework, but we also don’t want to reference multiple dependencies in one library. The solution is a bit of good old-fashioned reflection. By checking for the presence of each of these types we can query the property and have our activity reference to use as required. Of course, none of these may be present. It’s entirely property our library is used from a “native” .NET Android app and the developer is working directly with the Android APIs. We can still provide a valuable API here but provide a method to pass the activity context to any API which requires it to display some UI. That allows us to cover all bases from a single dll for all “flavours” of .NET Android development. From your cross-platform code it’s entirely transparent. I’ve put my current code into a Gist here:-

public static bool TryGetCurrentActivity(out Activity activity)
{
activity = null;
#if NET6_0_OR_GREATER
// check for Uno without taking a hard dependency
var t = Type.GetType("Uno.UI.ContextHelper, Uno, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null", false, true);
if (t != null)
{
activity = (Activity)t.GetProperty("Current", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public).GetValue(null);
}
else
{
// try Maui Essentials if not
t = Type.GetType("Microsoft.Maui.ApplicationModel.Platform, Microsoft.Maui.Essentials, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", false, true);
if (t != null)
{
activity = (Activity)t.GetProperty("CurrentActivity", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public).GetValue(null);
}
}
#else
// check for Xamarin.Essentials without taking a hard dependency
var t = Type.GetType("Xamarin.Essentials.Platform, Xamarin.Essentials, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", false, true);
if (t != null)
{
activity = (Activity)t.GetProperty("CurrentActivity", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public).GetValue(null);
}
#endif
return activity != null;
}

Next Steps

The good news from this is that InTheHand.BluetoothLE (as of the next NuGet drop) no longer has Xamarin or Maui dependencies but works just the same on these platforms. I’m interested in extending this to support Avalonia too. I may also move the code into its own library as I envision using it from a few places and it will be easier to maintain.

By Peter Foot

Microsoft Windows Development MVP

One reply on “Dot Net DLLs, Droid, Dependencies”

Comments are closed.