András Tóth‘s professional blog
banditoth.net

Hey there 👋, I’m banditoth a .NET MAUI developer from Hungary.
I write about software development with .NET technologies.

You can find me on:
LinkedIn | Github | StackOverflow | X / Twitter | Threads

Category: MAUI

  • .NET MAUI Jailbreak and root detection

    This content has 2 years. 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.

    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 &lt; 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.

  • .NET MAUI : Get current activity on Android

    This content has 2 years. 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.

    If you want to access the current activity on Android you will need to use the code below:

    Microsoft.Maui.ApplicationModel.Platform.CurrentActivity
    

    They made it very easy to access it. Appreciate it!

  • .NET MAUI : Write multilingual apps easily

    This content has 3 years. 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.

    If you need a solution to create multilingual applications without the hassle of implementing all kinds of code, I have good news for you. I’ve migrated my Xamarin.Forms package to .NET MAUI, and you can easily build multilingual applications with MAUI. No need to restart the application, the language takes effect immediately and works on all platforms. You can also use it from XAML, and C# code. It can handle multiple resource files at the same time. It can store the last language set by the user, and the next time you restart it, it will use the same language as the last time the user set it. But instead of letters, watch this video to see what exactly it can do:

    Let’s get started

    This project is available on GitHub: https://github.com/banditoth/MAUI.Packages

    To start with, I’ve put together a demo app for you for the sake of demonstration. There is no extra functionality, just 4 buttons. Three of them are to change the language of the application, and one of them is to give us a pop-up window. There is no logic to it yet, but together we will build on the article.

    The easiest demo app in the world

    Create translation files

    The first thing you will need are files containing multilingual translations. If you are familiar with Xamarin Forms, I will not surprise you: we will use files with RESX extension. By default, all MAUI applications include a directory called Resources. In this directory, I create a directory called Translations next to the Fonts, Images, and Raw directories, where I put the translations used by the application.

    Decide what the default language of your application should be. This is important because the default language is not indicated by a language code at the end of the filename. This language (and file) will be the one that the application will use as fallback, so that if, say, the application can’t find the text in the Hungarian or German translations, it can print it out in that language. In my case, the default language of the application will be English, so I didn’t specify it in the filename.

    I’ve created translations for each language with this data:

    	<data name="WelcomeMessage" xml:space="preserve">
    		<value>The quick brown fox jumps over the lazy dog</value>
    	</data>
    	<data name="AlertTitle" xml:space="preserve">
    		<value>Important notice</value>
    	</data>
    	<data name="AlertContent" xml:space="preserve">
    		<value>.NET Bot is cute!</value>
    	</data>
    	<data name="AlertConfirm" xml:space="preserve">
    		<value>Agree</value>
    	</data>
    

    Since ResX files are set by default to generate a code-behind file from their data, this automatic generation should be disabled for all ResX files other than the default language.

    This can be easily done on windows, just click on the file (in this case the German translation) and in the properties window, under Custom tool, clear the ResxFileCodeGenerator value. If you are using Visual Studio on a Mac, you cannot delete this from the interface, so you have to manually remove the option in the project file.

    For Visual Studio for mac, find the name of the files containing the translation in the project and delete the following lines:

            <Generator>ResXFileCodeGenerator</Generator>
            <LastGenOutput>AppTranslations.de.Designer.cs</LastGenOutput>
    

    If you did everything right, you will only have these files. If there are any ‘.Designer’ files left in the Solution, feel free to delete them. The important thing is that when you compile the application, they are not recreated by Visual Studio

    Install banditoth.MAUI.Multilanguage

    Click on your project with right, then select ‘Manage NuGet Packages’. Search for banditoth.MAUI.Multilanguage in the search bar, and install the result with the exact same name of your search text 🙂 This project is available on GitHub by the way, so if you are experiencing issues with it, you can report over here: https://github.com/banditoth/MAUI.Packages

    Initialise the component

    Let’s navigate to your MauiProgram.cs file, and add some init logic in it!

    	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");
    			})
                .ConfigureMultilanguage(config =>
                {
                    // Set the source of the translations
                    // You can use multiple resource managers by calling UseResource multiple times.
                    config.UseResource(AppTranslations.ResourceManager);
    
                    // If the app is not storing last used culture, this culture will be used by default
                    config.UseDefaultCulture(new System.Globalization.CultureInfo("en-US"));
    
                    // Determines whether the app should store the last used culture
                    config.StoreLastUsedCulture(true);
    
                    // Determines whether the app should throw an exception if a translation is not found.
                    config.ThrowExceptionIfTranslationNotFound(false);
    
                    // You can set custom translation not found text by calling this method 
                    config.SetTranslationNotFoundText("Transl_Not_Found:", appendTranslationKey: true);
                });
    
            return builder.Build();
    	}
    

    Use it in code

    Usage in XAML

    In order to use our translations in XAML files, we need to declare the tool’s namespace in XAML. Go to the top of your XAML file, and make the following declaration:

    xmlns:multilanguage="clr-namespace:banditoth.MAUI.Multilanguage;assembly=banditoth.MAUI.Multilanguage"
    

    After this declaration you can access the translation tool, so let change this code:

                <Label 
                    Text="This text should be multilingual"
                    FontSize="18"
                    HorizontalOptions="Center" />
    
    

    to this:

                <Label 
                    Text="{multilanguage:Translation Key=WelcomeMessage}"
                    FontSize="18"
                    HorizontalOptions="Center" />
    

    Usage in C# code

    Wherever we need to pass multilingual texts to or from another method, the ITranslator interface comes in handy. This interface is registered in the MAUI ‘s dependency container, so it can be retrieved from the container by constructor injection for example.

        private readonly ITranslator translator;
    
    	public MainPage(ITranslator translator)
    	{
    		InitializeComponent();
            this.translator = translator;
        }
    

    Unfortunately currently .NET MAUI is not supporting Constructor injection for Shell, but you can request any service from anywhere by adding this little work around to App.xaml.cs (but its definitely not nice):

    	public App(IServiceProvider serviceProvider)
    	{
    		InitializeComponent();
            ServiceProvider = serviceProvider;
    		MainPage = new AppShell();
        }
    
        public static IServiceProvider ServiceProvider { get; private set; }
    

    The localized string can be retreived like this (This example shows an Alert dialog for the user in the correct language)

        void DisplayAlertButton_Clicked(System.Object sender, System.EventArgs e)
        {
            _ = DisplayAlert(translator.GetTranslation("AlertTitle"),
                translator.GetTranslation("AlertContent"),
                translator.GetTranslation("AlertConfirm"));
        }
    

    Change language runtime

    To change language, you need to call the SetCurrentCulture method with the desired CultureInfo, like this:

        void ChangeToEnglishButton_Clicked(System.Object sender, System.EventArgs e)
        {
            translator.SetCurrentCulture(new CultureInfo("en"));
        }
    
        void ChangeToGermanButton_Clicked(System.Object sender, System.EventArgs e)
        {
            translator.SetCurrentCulture(new CultureInfo("de"));
        }
    
        void ChangeToHungarianButton_Clicked(System.Object sender, System.EventArgs e)
        {
            translator.SetCurrentCulture(new CultureInfo("hu"));
        }
    

  • Configure CI pipeline with .NET MAUI Release candidate (for NuGets)

    This content has 3 years. 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.

    In order to do automated builds in Azure DevOps with the .NET MAUI Release Candidate release, we need a few extra steps in the pipeline configuration. I used these steps to ensure that the NuGet packages I develop are automatically compiled and uploaded to NuGet.org. In this article I won’t go into detail about how to create a CI pipeline, I just want to show you the difference from a normal CI pipeline. I haven’t tried building and deploying applications in the cloud at the moment, but it can probably be done. Also, I don’t go into how to make the package automatically go to NuGet.org, for that I recommend an earlier article (and also how to create a CI/CD pipeline): https://www.banditoth.net/2021/11/09/azure-devops-setup-private-nuget-feed-with-ci/

    Since a final version of .NET MAUI has not been released as of today, in order to build our applications in the cloud, we need to install the MAUI Workload on the Agent.
    If we do not do this, we may encounter the following error:

    Error NETSDK1147: To build this project, the following workloads must be installed: maui-windows
    

    Adjust your pipeline

    In order to install the workload on our build agent, create a new task at the very beginning in the pipeline file, which is executes a command in the command line:

    This will result the following task in the yaml file:

    - task: CmdLine@2
      inputs:
        script: 'dotnet workload install maui'
    

    The installation of the workload will take about 5 minutes.

    From now on, you will be able to use .NET Maui references on the pipelines too. This will let you build your packages in the cloud.
    Once MAUI will be officially available, probably you don’t need these steps.

  • .NET MAUI RC1 is available with VS for Mac support

    This content has 3 years. 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.

    Good news for .NET MAUI fans. We’ll soon have a stable version from the wonderful developers at Microsoft, but in the meantime, here we have the first RC version of .NET MAUI.
    There’s a lot of new features in this version, including integration with the Essentials package, much more customizable styles, etc.
    But today I want to talk about the most important thing for me, which is the support for Visual Studio for Mac. Well, it’s not so official yet, and it’s not so usable, but we can see progress. VS for Mac 2022 is no longer a stranger to MAUI projects. Unfortunately, I couldn’t get the debugging to work, but you can now start the project on almost any platform.

    Let’s use MAUI in Visual Studio 2022 for Mac

    First and most importantly, and I experienced it first hand.
    If the IDE you want to use throws the following errors:

    /usr/local/share/dotnet/sdk/6.0.202/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.targets(5,5): Error NETSDK1147: To build this project, the following workloads must be installed: maui-maccatalyst
    To install these workloads, run the following command: dotnet workload install maui-maccatalyst (NETSDK1147) (ResxEditorMaui)
    
    /usr/local/share/dotnet/sdk/6.0.202/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.targets(5,5): Error NETSDK1147: To build this project, the following workloads must be installed: maui-ios
    To install these workloads, run the following command: dotnet workload install maui-ios (NETSDK1147) (ResxEditorMaui)
    
    /usr/local/share/dotnet/sdk/6.0.202/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.targets(5,5): Error NETSDK1147: To build this project, the following workloads must be installed: maui-android
    To install these workloads, run the following command: dotnet workload install maui-android (NETSDK1147) (ResxEditorMaui)
    

    And you can’t install the recommended packages because the following error is displayed:

    Workload ID android-aot is not recognized.
    

    Then be sure to install .NET version 6.0.3XX. You can do this from this url and select the appropriate processor architecture. https://github.com/dotnet/installer

    To check which version is installed, you can check in the terminal with the following paranncs:

    dotnet --info
    

    If you have installed the required version of .NET 6.0, issue the following command:

    sudo dotnet workload install maui
    

    You can then use MAUI in Visual Studio for Mac.