.NET MAUI iOS Bug – Release Mode Bindings Not Working

Software bugs can sometimes manifest in specific environments or platforms, leading to unexpected behavior. In this blog post, we will discuss a bug in .NET MAUI specifically affecting iOS platforms. The bug causes bindings between Views and ViewModels to fail in Release mode, resulting in empty Views without the expected data. We’ll explore the symptoms of this bug and present a workaround that involves utilizing the XamlCompilation attribute with the Skip option.

Symptoms

The bug we are addressing affects the binding functionality in .NET MAUI apps running on iOS platforms in Release mode. When encountering this issue, Views fail to bind with their associated ViewModels, resulting in empty Views that appear as if no BindingContext is present.

What is XamlCompilation?

XamlCompilation is an attribute provided by Xamarin.Forms that allows developers to specify how XAML files should be compiled. It offers three options: None, XamlC, and Skip.

  • None: The default option. XAML files are not compiled individually and are interpreted at runtime.
  • XamlC: XAML files are compiled ahead-of-time into IL code, improving performance by eliminating the need for runtime interpretation.
  • Skip: XAML files are skipped from the compilation process and are interpreted at runtime, similar to the None option.

Providing workaround

To mitigate this bug, we can utilize the XamlCompilation attribute with the Skip option on the affected Views. This attribute is used to control the compilation behavior of XAML files in .NET MAUI applications.

Identify the Affected View First, identify the View(s) in your .NET MAUI app that are experiencing the binding issue specifically on iOS platforms in Release mode. Add XamlCompilation Attribute Add the XamlCompilation attribute to the affected View’s code-behind file. Set the attribute value to Skip to instruct the compiler to exclude the associated XAML file from the compilation process.

[XamlCompilation(XamlCompilationOptions.Skip)]
public partial class MyAffectedView : ContentView
{
    // ...
}

Ensure that the affected View is properly updated with the XamlCompilation attribute. Test the application in Release mode on iOS to confirm that the bindings are now functioning as expected and the Views are populated with the appropriate data.

Keep in mind that while this workaround provides a solution for the bug, it’s important to regularly check for updates from the .NET MAUI team, as they may address and fix this issue in future releases. Additionally, test your app thoroughly after applying the workaround to ensure the expected functionality and behavior across different platforms.

This content has 10 months. Some of the information in this post may be out of date or no longer work. Please, read this page keeping its age in your mind.

.NET MAUI: Bug – GestureRecognizers are not working on some views

In the world of software development, bugs can occasionally arise, causing unexpected behavior in our applications. In this blog post, we will explore a bug affecting TapGestureRecognizers in .NET MAUI apps, specifically on certain Views like frames. We’ll discuss the symptoms of this bug and provide a practical workaround to ensure that TapGestureRecognizers properly fire events or execute commands.

Symptoms

The bug we are addressing is related to TapGestureRecognizers not functioning as expected on specific Views, such as frames, in .NET MAUI apps. This issue prevents TapGestureRecognizers from triggering events or executing commands, leading to a loss of interactivity for the affected Views.

Workaround

To overcome this bug, we can utilize a simple workaround that involves creating a transparent BoxView on top of the desired interaction area. By setting the InputTransparent property of the BoxView to false, we allow it to capture touch events, effectively acting as an overlay for the affected View. We can then assign the TapGestureRecognizer to the transparent BoxView to regain the desired interactivity.

First, identify the View that is experiencing the issue with TapGestureRecognizers. In this example, let’s assume we have a Frame control that should respond to tap events but is currently affected by the bug. Add a Transparent BoxView Within the same container as the affected View, add a BoxView control. Set its BackgroundColor property to Transparent to ensure it remains invisible to the user. Assign TapGestureRecognizer to the Transparent BoxView Inside the GestureRecognizers collection of the transparent BoxView, assign the TapGestureRecognizer with the desired event handling or command execution logic. You can bind the command property to a command in your view model or handle the event in code-behind. Position the transparent BoxView over the affected View, ensuring that it covers the same area where the TapGestureRecognizer should have been applied. By making the BoxView transparent and setting InputTransparent to false, it allows touch events to pass through, reaching the TapGestureRecognizer.

<BoxView BackgroundColor="Transparent" InputTransparent="False">
    <BoxView.GestureRecognizers>
        <TapGestureRecognizer Command="{Binding YourCommand}" />
    </BoxView.GestureRecognizers>
</BoxView>

Note: It’s important to keep in mind that this workaround is intended as a temporary solution until the bug is officially addressed and fixed by the .NET MAUI team. Stay up to date with the latest releases and bug fixes to ensure that you can eventually transition to the official resolution. Please remember to regularly check the official .NET MAUI documentation, release notes, and bug tracking system for any updates regarding this bug and its resolution.

https://github.com/dotnet/maui/issues/8895#issuecomment-1301620712

This content has 10 months. Some of the information in this post may be out of date or no longer work. Please, read this page keeping its age in your mind.

.NET MAUI: Implementing Light and Dark Modes

In modern application development, providing users with the ability to switch between light and dark modes has become an essential feature. This functionality not only enhances user experience but also accommodates personal preferences and improves accessibility. In this blog post, we will explore how to implement light and dark modes in .NET MAUI apps using the UserAppTheme property in the App.xaml.cs file.

Understanding the App.xaml.cs File

The App.xaml.cs file in a .NET MAUI application is responsible for defining the application’s startup and initialization logic. It acts as the entry point for the application and provides a central location to handle events and configure application-wide settings.

Setting the UserAppTheme Property

To enable light and dark modes in your .NET MAUI app, you need to access the UserAppTheme property available in the Application.Current object. This property allows you to specify the desired theme for your application.

If your application does not allow the users to change the light/dark modes, but you want to force the app to be in a specified state, you can use the App.xaml.cs constructor, and you can set the UserAppTheme property to either AppTheme.Light or AppTheme.Dark, depending on a predefined default.

Here’s an example of how to set the AppTheme to Light mode:

Application.Current.UserAppTheme = AppTheme.Light;

Similarly, you can set the AppTheme to Dark mode:

Application.Current.UserAppTheme = AppTheme.Dark;
This content has 10 months. Some of the information in this post may be out of date or no longer work. Please, read this page keeping its age in your mind.

.NET MAUI: Get unique device and installation ids for your app

Why unique device and installations identifiers are important?

First, let’s define what we mean by a unique device and installation identifiers. Essentially, these are codes that are assigned to individual devices and installations of an app. They allow developers to track usage on a specific device and identify individual installations of the app. This is important because it allows us to understand how users are interacting with our app and identify patterns in usage. For example, if we notice that a particular device is experiencing a high number of crashes, we can use the device ids to track down the specific device and troubleshoot the issue.

Another important use case for unique device and installation identifiers is providing targeted and personalized content or experiences for users. For example, we can use this information to show users personalized advertisements or to offer them special deals or promotions based on their usage patterns.

In addition to these benefits, device and install ids also play an important role in security and fraud prevention. By tracking the usage of our app on specific devices, we can identify and prevent unauthorized access to the app or service. This can help to protect user data and prevent fraud and other malicious activities.

How to get unique identifiers in .NET MAUI?

On Android, you can get a unique device id from the os with accessing Secure.AndroidId.
On iOS, UIDevice.CurrentDevice.IdentifierForVendor is the solution. It requires platform specific knowledge to access the provider APIs. I’ve extended my banditoth.MAUI.Packages library, so you do not need to worry about having this knowledge, just use the banditoth.MAUI.DeviceId NuGet package.

Once you have installed banditoth.MAUI.DeviceId, you need to initalize  the plugin within your MauiProgram.cs‘s CreateMauiApp method. Use the .ConfigureDeviceIdProvider extension method with the using banditoth.MAUI.DeviceId;

    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
            })
            .ConfigureDeviceIdProvider();
#if DEBUG
        builder.Logging.AddDebug();
#endif

        return builder.Build();
    }

Use the code with by resolving an instance of IDeviceIdProvider.

The GetDeviceId method returns an unique device identifier. On Android it serves the data from AndroidId, on iOS and MacCatalyst it uses the IdentifierForVendor. Windows returns the GetSystemIdForPublisher().Idas a string.

The GetInstallationId method generates an unique identifier for the application, which will be stored until the application is being reinstalled, or the application’s data being erased.

This content has 1 year. Some of the information in this post may be out of date or no longer work. Please, read this page keeping its age in your mind.

.NET MAUI Jailbreak and root detection

banditoth.MAUI packages just got a new package: banditoth.MAUI.JailbreakDetector. 2022 was a great year for me in a software development perspective, my MAUI packages got downloaded over more than 1500 times, which is a great achievement for me. I’m keeping up the work, and having a new package on my palette: A lightweight root and jailbreak detection algorithm for Android and iOS with .NET MAUI.

What is jailbreaking?

Jailbreaking is the process of removing the limitations imposed on iOS devices by Apple. It allows users to install apps and tweaks that are not available on the App Store, customise the appearance of the operating system, and access features that are otherwise restricted. Jailbreaking an iOS device is considered to be a violation of Apple’s terms of service, and it can also make the device more vulnerable to security risks.

What is rooting?

Rooting is the process of allowing users of smartphones, tablets and other devices running the Android mobile operating system to attain privileged control (known as root access) over various Android subsystems. Rooting is often performed with the goal of removing limitations that hardware manufacturers or carriers place on some devices, thereby providing the latest versions of Android to devices that no longer receive official updates, or unlocking features which are otherwise unavailable to the user. Rooting is also often used to remove pre-installed apps, known as bloatware, that the manufacturer or carrier included on the device and which the user may not have wanted.

Why jailbreak and root protection is important?

When a device is jailbroken or rooted, it can become more vulnerable to security risks because the jailbreak process involves disabling certain security measures and exposing the device to potentially malicious software. This can compromise the security and stability of the operating system, and it can also make the device more susceptible to being hacked or compromised in other ways. By implementing jailbreak protection, software developers can help to ensure that their apps and systems are running on a secure and stable platform, which can help to protect the device and its users from various types of attacks and vulnerabilities.

Use jailbreak and root protection in .NET MAUI

Install the banditoth.MAUI.JailbreakDetector NuGet in order to protect your apps against vulnerabilities.

Initalize the library in the MauiApp.cs file within the CreateMauiApp method, like this:

public static MauiApp CreateMauiApp()
		{
			var builder = MauiApp.CreateBuilder()
				.UseMauiApp<App>()
				...
				.ConfigureJailbreakProtection(configuration =>
				{
					configuration.MaximumPossibilityPercentage = 20;
					configuration.MaximumWarningCount = 1;
					configuration.CanThrowException = true;
				});
			return builder.Build();
		}

You can dependency inject the jailbreak detector instance, by resolving an instance of IJailbreakDetector. Store the instance in a private readonly field in your class, or use it directly.

    public async Task CheckJailbreakOrRoot()
    {
        if(_jbDetector.IsSupported())
        {
            if(await _jbDetector.IsRootedOrJailbrokenAsync())
            {
                // Code when jailbroken or rooted
            }
            else
            {
                // Code when clear
            }
        }
    }

By calling ScanExploitsAsync you can process the discovered exploits and warnings during the scan – It returns a ScanResultScanResult has a property named PossibilityPercentage. This percentage tells you how confidently you can tell whether a device has been jailbroken or rooted. Different types of tests contribute different weights to the final result.

    public async Task CheckJailbreakOrRoot()
    {
        ScanResult scan = await _jbDetector.ScanExploitsAsync();
        
        if(scan == null)
            return;
            
        foreach(var exploit in scan.Exploits)
        {
            // Get detailed information about the exploits here
        }
        
        if(scan.PossibilityPercentage < 5)
        {
            // Custom code when only 5% possible that the device is rooted or jailbroken
        }
    }

Remarks

Please note that there are many different kinds of jailbreaks and roots. It is possible that this package does not properly support the detection of these different techniques. If you find that filtering does not work on your device, please help by expanding the code repository.

This content has 1 year. Some of the information in this post may be out of date or no longer work. Please, read this page keeping its age in your mind.