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

Tag: android

  • Install Android SDK automatically when running MAUI app.

    When attempting to deploy a MAUI app, the build process failed with the following error:

    /usr/local/share/dotnet/packs/Microsoft.Android.Sdk.Darwin/35.0.50/tools/Xamarin.Android.Tooling.targets(92,5): error XA5207: 
    Could not find android.jar for API level 35. This means the Android SDK platform for API level 35 is not installed; it was expected to be in `/Users/banditoth/Library/Android/sdk/platforms/android-35/android.jar`.
    You can install the missing API level by running `dotnet build -t:InstallAndroidDependencies -f net9.0-android "-p:AndroidSdkDirectory=/Users/banditoth/Library/Android/sdk"`, or change the project to target an API version that is installed.
    See https://aka.ms/xa5207 for more details.
    
    

    This error indicates that the Android SDK platform for API level 35 is missing. The suggested solution is to install the missing API level by running the following command:

    dotnet build -t:InstallAndroidDependencies -f net9.0-android "-p:AndroidSdkDirectory=/Users/banditoth/Library/Android/sdk"
    
    

    However, running the above command led to another error:

    /usr/local/share/dotnet/packs/Microsoft.Android.Sdk.Darwin/35.0.50/tools/Xamarin.Installer.Common.targets(19,3): error : The Android SDK license agreements were not accepted, please set `$(AcceptAndroidSDKLicenses)` to accept.
    
    

    This error occurs because the Android SDK license agreements have not been accepted.

    The Solution

    To resolve this issue, you need to accept the Android SDK license agreements. This can be done by modifying your project’s .csproj file. Add the following line within a <PropertyGroup>:

    <AcceptAndroidSDKLicenses>true</AcceptAndroidSDKLicenses>
    
    

    Here’s an example of how your .csproj file might look after the modification:

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFrameworks>net9.0-android;net9.0-ios;net9.0-maccatalyst</TargetFrameworks>
        <RootNamespace>YourAppNamespace</RootNamespace>
        <AcceptAndroidSDKLicenses>true</AcceptAndroidSDKLicenses>
      </PropertyGroup>
    </Project>
    

  • Debug .NET MAUI Android apps with Android work profile

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

    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. Disabling Map Zoom Controls and Other Buttons in .NET MAUI Android

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

      In this post, we’ll guide you through the process of disabling these UI elements (zoom controls, compass, and location buttons) in your Android map implementation using a custom map handler. This approach gives you more control over the user experience and map functionality in your mobile app.

      Creating a Custom Map Handler

      To disable these controls, we need to customize how the map is rendered on Android. This involves creating a custom map handler that intercepts the way the map is displayed and adjusts its settings.

      A detailed tutorial for creating custom map handlers can be found in this great guide by Vladislav Antonyuk. We will extend that concept here.

      First, we need to implement a MapCallbackHandler that disables specific controls when the map is ready. This is done in the OnMapReady method, which is triggered when the map is fully loaded and ready for interaction.

      using Android.Gms.Maps;
      using Android.Gms.Maps.Model;
      using Microsoft.Maui.Handlers;
      using Microsoft.Maui.Controls.Compatibility.Maps.Android;
      
      class MapCallbackHandler : Java.Lang.Object, IOnMapReadyCallback
      {
          private readonly IMapHandler mapHandler;
      
          public MapCallbackHandler(IMapHandler mapHandler)
          {
              this.mapHandler = mapHandler;
          }
      
          public void OnMapReady(GoogleMap googleMap)
          {
              // Update map with any pins or map state changes
              mapHandler.UpdateValue(nameof(IMap.Pins));
              
              // Disable zoom controls
              googleMap.UiSettings.ZoomControlsEnabled = false;
              
              // Disable the "My Location" button
              googleMap.UiSettings.MyLocationButtonEnabled = false;
              
              // Disable the compass
              googleMap.UiSettings.CompassEnabled = false;
      
              // Additional settings can be adjusted here, such as disabling tilt or gestures.
          }
      }
      
      

      In the OnMapReady method, we access the googleMap.UiSettings property, which contains several settings that control the map’s UI. In our example, we set the following to false:

      • ZoomControlsEnabled: Disables the zoom buttons.
      • MyLocationButtonEnabled: Removes the My Location button that appears when location services are enabled.
      • CompassEnabled: Hides the compass that appears when the user rotates the map.

      You can also adjust other settings here, such as disabling tilt gestures or zoom gestures if needed.

    2. .NET MAUI Android: OverrideBackButtonPress not being hit.

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

      You might encounter a scenario where the OverrideBackButtonPress method in your Page is not being triggered on Android devices. This can be a frustrating issue, but there’s a straightforward solution that involves modifying your AndroidManifest.xml file.

      The predictive back gesture feature in Android can indeed affect how back button presses are handled in your application. Learn more at: https://developer.android.com/guide/navigation/custom-back/predictive-back-gesture

      Predictive Back Gesture

      Android’s predictive back gesture allows users to preview the destination or action that will occur when they complete a back gesture. In .NET MAUI, the OverrideBackButtonPress method allows you to handle the back button press event in your application. However, if this method is not being called, it could be due to a specific setting in your AndroidManifest.xml file.

      Disabling Predictive Back Gesture

      To ensure your custom back button handling works as expected, you need to disable the predictive back gesture by setting the android:enableOnBackInvokedCallback attribute to false in your AndroidManifest.xml file. This prevents the system from intercepting the back button press and allows your application to handle it.

      <application
          android:label="YourAppName"
          android:icon="@mipmap/ic_launcher"
          android:enableOnBackInvokedCallback="false">
          <!-- Other settings -->
      </application>
      
      

    3. .NET MAUI Android Auto : Launching Navigation Apps from your app

      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.

      Android Auto is a popular platform that allows users to seamlessly integrate their Android devices with their car’s infotainment system. This integration extends to navigation, allowing users to launch navigation apps like Google Maps or Waze directly from Android Auto. In this blog post, we’ll explore how to achieve this functionality from within your Android application using .NET MAUI.

      The key to launching navigation apps on Android Auto is to construct a URI with the desired latitude and longitude and use an Intent to open the navigation app. Let’s break down the code snippet you provided to understand how it works:

      public class NavigationOnClickListener : Java.Lang.Object, IOnClickListener
      {
          private readonly CarContext _context;
          private readonly double _latitude;
          private readonly double _longitude;
      
          public NavigationOnClickListener(CarContext context, double latitude, double longitude)
          {
              _context = context;
              _latitude = latitude;
              _longitude = longitude;
          }
      
          public void OnClick()
          {
              string uri = $"geo:{_latitude.ToString(CultureInfo.InvariantCulture)},{_longitude.ToString(CultureInfo.InvariantCulture)}";
              Intent intent = new Intent(CarContext.ActionNavigate)
                  .SetData(AndroidUri.Parse(uri));
              _context.StartCarApp(intent);
          }
      }
      
      

      AndroidUri is the Android.Net.Uri class alias achieved by:

      using AndroidUri = Android.Net.Uri;
      

      Let’s dissect this code step by step:

      1. NavigationOnClickListener is a custom class that implements the IOnClickListener interface. This class is responsible for handling the click event that launches the navigation app.
      2. In the constructor, we receive three parameters: context, latitude, and longitude. context is the CarContext instance, and latitude and longitude are the destination coordinates (double).
      3. Inside the OnClick method, we construct a URI in the following format: "geo:latitude,longitude". The CultureInfo.InvariantCulture is used to ensure that the decimal separator is a period (.) rather than a comma (,) to make the URI universally compatible. This is crucial because different regions may use different formats for numbers.
      4. We create an Intent with the action CarContext.ActionNavigate. This action specifies that we want to launch a navigation app.
      5. We set the data of the intent by parsing the constructed URI using AndroidUri.Parse(uri).
      6. Finally, we start the navigation app by invoking _context.StartCarApp(intent).