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

  • Prepare your Windows servers for Apple’s APNs certificate update

    Apple has announced an important change to the Certification Authority (CA) for Apple Push Notification service (APNs). The update to APNs server certificates will take effect in the sandbox environment on January 20, 2025, and in the production environment on February 24, 2025.

    To ensure uninterrupted push notification services, developers must update their application’s Trust Store to include the new SHA-2 Root: USERTrust RSA Certification Authority certificate before the respective cut-off dates.

    If You Use Firebase or Microsoft Azure Notification Service

    If your application uses Firebase Cloud Messaging (FCM) or Microsoft Azure Notification Hubs, you probably do not need to take any action. These services manage push notifications on behalf of your application, handling all necessary certificate updates internally. Google and Microsoft will ensure their backend services are updated with the new APNs root certificate, so you won’t need to manually update your Trust Store unless you have custom implementations that directly communicate with APNs.

    If you directly connect to Apple’s APNs with Windows Servers

    Then read on.
    It is essential that all Windows servers communicating with APNs trust both the old and new certificates to avoid any disruptions. Below are the steps to correctly import the new root certificate into your Windows servers.

    Steps to Update the APNs Certificate on Windows Servers

    Step 1: Download the New Root Certificate

    1. Open your web browser and navigate to the official certificate provider’s page: Sectigo Intermediate Certificates
    2. Locate and download the USERTrust RSA Certification Authority root certificate in .cer or .crt format.

    Step 2: Open Certificate Manager

    1. Press Win + R to open the Run dialog.
    2. Type certmgr.msc and press Enter.
    3. The Certificate Manager will open, allowing you to manage trusted certificates.

    Step 3: Import the New Root Certificate

    1. In Certificate Manager, expand the Trusted Root Certification Authorities folder.
    2. Right-click on the Certificates subfolder.
    3. Select All Tasks > Import.
    4. The Certificate Import Wizard will appear. Click Next.
    5. Browse to the location where you saved the downloaded certificate and select it.
    6. Click Next and follow the prompts to complete the import process.

    Step 4: Verify the Import

    1. After the import is complete, navigate to Trusted Root Certification Authorities > Certificates.
    2. Confirm that the USERTrust RSA Certification Authority certificate is listed.

    Step 5: Update Group Policy (for Domain-Joined Computers)

    If your Windows servers are part of a domain, updating the Group Policy will ensure that all connected machines receive the updated certificate.

    1. Open Group Policy Management Console.
    2. Create or edit an existing Group Policy Object (GPO).
    3. Navigate to Computer Configuration > Windows Settings > Security Settings > Public Key Policies.
    4. Right-click on Trusted Root Certification Authorities and select Import.
    5. Follow the wizard to import the new root certificate.
    6. Apply the GPO to all required machines and restart them if necessary.

    Sources

    https://developer.apple.com/news/?id=09za8wzy

    https://developer.apple.com/news/upcoming-requirements/?id=01202025a

  • Debug .NET MAUI Android apps with Android work profile

    An Android Work Profile is a feature that allows you to separate work apps and data from personal apps and data on the same device. This is particularly useful for maintaining privacy and security in a corporate environment. However when you are developing an app for your company, who’s got these configurations on their mobile devices, you might find yourself in a tricky solution, because VS Code simply installs the app on the workprofile and on the normal profile aswell, but only can run with debug on the normal profile without any configuration.

    Get the users of the Android device

    To list users on an Android device using ADB (Android Debug Bridge), you can use the following command:

    adb shell pm list users
    

    This command will display a list of users on the device, including their user IDs.

    For example, the output might look something like this:

    Users:
        UserInfo{0:Owner:13} running
        UserInfo{10:Work:30} running
    

    Configure the .csproj to launch the app on work profile

    Insert the following line within the <PropertyGroup> section of your .csproj file:

    <AndroidDeviceUserId>10</AndroidDeviceUserId>
    

    This attribute specifies the user ID for the Android Work Profile. The user ID 10 is commonly used for work profiles, but you should verify this for your specific setup.

    Last but not least: Hit F5 and Run your project 🙂

    Remark: This solution is only working in Visual Studio for Windows, and Visual Studio Code on mac.

    1. Resizing the screen when an Entry gets focused in .NET MAUI

      When an entry field gets focused, the software keyboard appears, potentially covering the entry field. To provide a better user experience, you need to adjust the screen layout so that the entry field remains visible.

      First, create a parent class for your views, deriving from ContentPage, and add a HaveKeyboardOffsetProperty.

      public class ViewBase : ContentPage
      {
          public static readonly BindableProperty HasKeyboardOffsetProperty =
              BindableProperty.Create(nameof(HasKeyboardOffset), typeof(bool), typeof(ViewBase), false);
      
          public bool HasKeyboardOffset
          {
              get => (bool)GetValue(HasKeyboardOffsetProperty);
              set => SetValue(HasKeyboardOffsetProperty, value);
          }
      }
      
      

      iOS Solution:

      Next, create the PageElementMapper class to handle the keyboard appearance and adjust the screen layout.

      public class PageElementMapper
      {
          private static double _contentOriginalHeight;
          private static Thickness _contentOriginalMargin;
      
          public static void Map(IElementHandler handler, IElement view)
          {
              if (view is ViewBase viewData)
              {
                  UIKeyboard.Notifications.ObserveWillShow((sender, args) =>
                  {
                      if (viewData.HasKeyboardOffset)
                      {
                          _contentOriginalHeight = viewData.Content.Height;
                          _contentOriginalMargin = viewData.Content.Margin;
                          viewData.Content.HeightRequest = _contentOriginalHeight - args.FrameEnd.Height;
                          viewData.Content.Margin = new Thickness(0, args.FrameEnd.Height, 0, 0);
                      }
                  });
      
                  UIKeyboard.Notifications.ObserveWillHide((sender, args) =>
                  {
                      if (viewData.HasKeyboardOffset)
                      {
                          viewData.Content.HeightRequest = _contentOriginalHeight;
                          viewData.Content.Margin = _contentOriginalMargin;
                      }
                  });
              }
          }
      }
      
      

      Finally, register the mapper in the MauiProgram.cs file.

      public static class MauiProgram
      {
          public static MauiApp CreateMauiApp()
          {
              var builder = MauiApp.CreateBuilder();
              builder
                  .UseMauiApp<App>()
                  .ConfigureMauiHandlers(handlers =>
                  {
                      Microsoft.Maui.Handlers.PageHandler.ElementMapper.AppendToMapping("KeyboardOffset", (handler, view) =>
                      {
                          if (view is ViewBase)
                          {
      #if IOS
                              PageElementMapper.Map(handler, view);
      #endif
                          }
                      });
                  });
      
              return builder.Build();
          }
      }
      
      

      Android solution:

      On Android, you can use a PropertyChanged method of the HasKeyboardOffset:

          private static void OnHasKeyboardOffsetPropertyChanged(BindableObject bindable, object oldValue, object newValue)
          {
      #if ANDROID
              if (bindable is ViewBase view)
              {
                  if (newValue is bool hasOffset)
                      if (hasOffset == true)
                          Microsoft.Maui.Controls.Application.Current.Dispatcher.Dispatch(() =>
                          {
                              Platform.CurrentActivity?.Window?.SetSoftInputMode(Android.Views.SoftInput.AdjustResize);
                          });
                      else
                          Microsoft.Maui.Controls.Application.Current.Dispatcher.Dispatch(() =>
                          {
                              Platform.CurrentActivity?.Window?.SetSoftInputMode(Android.Views.SoftInput.StateUnspecified);
                          });
              }
      #endif
          }
      

      Remarks

      The provided solution offers a way to manage this in .NET MAUI on iOS. However, always be open to improvements and share your solutions with the community for better practices. This might not be the best solution to do it.

    2. .NET MAUI Hide software keyboard when tapping out of an Entry on iOS

      To hide the software keyboard when the user taps outside the entry field, set the HideSoftInputOnTapped property to True in your ContentPage definition.

      &lt;ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                   xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                   x:Class="MyMauiApp.MainPage"
                   HideSoftInputOnTapped="True">
      
          &lt;StackLayout Padding="10">
              &lt;Entry Placeholder="Tap here to enter text" />
          &lt;/StackLayout>
      &lt;/ContentPage>
      
      

      Please note that the HideSoftInputOnTapped property might not work as expected when tapping on certain controls like ScrollView. In such cases, you might need to implement a custom behavior to handle keyboard dismissal.

    3. Resolving SQLite issues for .NET MAUI

      Recently, while working on ExampleApp, we faced two significant errors and found effective solutions for both. Here’s a detailed account of the problems and their resolutions.

      System.TypeInitializationException

      System.TypeInitializationException: The type initializer for 'SQLite.SQLiteConnection' threw an exception.
       ---> System.DllNotFoundException: e_sqlite3
      

      To resolve this error, we needed to install the latest NuGet package for SQLitePCLRaw.bundle_green. This package ensures that the necessary SQLite libraries are included in the project.

      Add the following package reference with the latest version to your project:

      &lt;PackageReference Include="SQLitePCLRaw.bundle_green" Version="2.1.10" />
      
      

      In the AppDelegate.cs file, add the following line to the CreateMauiApp method:

      protected override MauiApp CreateMauiApp()
      {
          SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_sqlite3());
          return MauiProgram.CreateMauiApp();
      }
      

      System.ExecutionEngineException in iOS Release Mode

      System.ExecutionEngineException: Attempting to JIT compile method '(wrapper delegate-invoke) void System.Action`2&lt;ExampleApp.Entites.LocalDatabase.VoucherLite, double>:invoke_callvirt_void_T1_T2 (ExampleApp.Entites.LocalDatabase.VoucherLite,double)' while running in aot-only mode. See https://docs.microsoft.com/xamarin/ios/internals/limitations for more information.
      

      This error occurs due to the JIT compilation attempt in AOT-only mode on iOS. The solution is to install this specific version of the sqlite-net-pcl.
      It will ONLY work with 1.7.355 or below.

      &lt;PackageReference Include="sqlite-net-pcl" Version="1.7.335" />
      

       This solution is also applicable to Xamarin projects.