Network Access Detection in .NET MAUI

Detecting network access is a fundamental requirement for many mobile applications. .NET MAUI, through its integration with platform-specific APIs and the use of the community-supported NetworkConnectivity plugin (or by implementing custom logic), allows developers to efficiently monitor and react to network status changes. This tutorial will guide you through the process of implementing network access detection in your .NET MAUI application.

Using the NetworkConnectivity Plugin

The NetworkConnectivity plugin provides a unified API for checking network status across different platforms. It simplifies the process of determining if the device is online, offline, or connected via Wi-Fi or Cellular.

Installation

First, you need to add the plugin to your .NET MAUI project. Open your project in Visual Studio or use the .NET CLI:

dotnet add package Xamarin.Essentials && dotnet add package Plugin.NetworkConnectivity

Note: While Xamarin.Essentials is often included, it's good practice to ensure it's present or add it if necessary. The primary dependency for network connectivity checks is Plugin.NetworkConnectivity.

Checking Network Status

You can check the current network status at any point in your application.

Example: Checking current connectivity

using Plugin.NetworkConnectivity;

// ...

public partial class MyPage : ContentPage
{
    public MyPage()
    {
        InitializeComponent();
        CheckNetworkStatus();
    }

    private void CheckNetworkStatus()
    {
        if (CrossConnectivity.IsConnected)
        {
            System.Diagnostics.Debug.WriteLine("Device is connected to the internet.");
            // Perform actions that require network access
        }
        else
        {
            System.Diagnostics.Debug.WriteLine("Device is offline.");
            // Show an error message, disable network-dependent features, etc.
        }
    }
}
                    

Monitoring Network Changes

For a more dynamic approach, you can subscribe to network connectivity change events. This allows your application to react in real-time as the network status changes.

Example: Subscribing to network changes

using Plugin.NetworkConnectivity;
using System;

public partial class MyPage : ContentPage
{
    public MyPage()
    {
        InitializeComponent();
        SubscribeToNetworkChanges();
    }

    private void SubscribeToNetworkChanges()
    {
        CrossConnectivity.Current.ConnectivityChanged += Current_ConnectivityChanged;
    }

    private void Current_ConnectivityChanged(object sender, ConnectivityChangedEventArgs e)
    {
        if (e.IsConnected)
        {
            System.Diagnostics.Debug.WriteLine($"Network connected. NetworkAccess: {e.NetworkAccess}");
            // Update UI, re-enable features
        }
        else
        {
            System.Diagnostics.Debug.WriteLine("Network disconnected.");
            // Show offline message, disable features
        }
    }

    protected override void OnDisappearing()
    {
        base.OnDisappearing();
        // Unsubscribe to prevent memory leaks
        CrossConnectivity.Current.ConnectivityChanged -= Current_ConnectivityChanged;
    }
}
                    

Understanding NetworkAccess Enum

The ConnectivityChangedEventArgs.NetworkAccess property provides more granular details about the type of network connection. It's an enum with the following possible values:

  • NetworkAccess.Internet: General internet access.
  • NetworkAccess.ConstrainedInternet: Limited internet access (e.g., captive portals).
  • NetworkAccess.Local: Local network access only (e.g., on a private network).
  • NetworkAccess.None: No network access.
  • NetworkAccess.Unknown: Network access cannot be determined.

You can check for specific types of access:

Example: Checking for Wi-Fi access

private void Current_ConnectivityChanged(object sender, ConnectivityChangedEventArgs e)
{
    if (e.NetworkAccess.HasFlag(NetworkAccess.Internet))
    {
        System.Diagnostics.Debug.WriteLine("Internet access is available.");
    }
    if (e.NetworkAccess.HasFlag(NetworkAccess.{highlight}Local{/highlight}))
    {
        System.Diagnostics.Debug.WriteLine("Local network access is available.");
    }
    if (e.NetworkAccess.HasFlag(NetworkAccess.{highlight}ConstrainedInternet{/highlight}))
    {
        System.Diagnostics.Debug.WriteLine("Constrained internet access is available.");
    }
}
                    

Implementing Custom Network Detection (Advanced)

While the plugin is highly recommended, you might need to implement custom logic for specific scenarios or if you prefer not to use external plugins. This typically involves using platform-specific APIs.

Android

On Android, you can use ConnectivityManager. You'll need to declare appropriate permissions in your AndroidManifest.xml.

AndroidManifest.xml (Android)

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
                    

And then use the following C# code within your Android-specific implementation.

Example (Android specific)

// In your Android platform-specific code
using Android.Net;
using Android.Content;

public class AndroidNetworkHelper
{
    public static bool IsInternetAvailable()
    {
        var connectivityManager = (ConnectivityManager)Android.App.Application.Context.GetSystemService(Context.ConnectivityService);
        if (connectivityManager == null) return false;

        if (global::Android.OS.Build.VERSION.SdkInt >= global::Android.OS.BuildVersionCodes.M)
        {
            var capabilities = connectivityManager.GetNetworkCapabilities(connectivityManager.ActiveNetwork);
            if (capabilities != null)
            {
                return capabilities.HasCapability(NetCapability.Internet) &&
                       capabilities.HasCapability(NetCapability.ValidatedInternet);
            }
        }
        else
        {
            var info = connectivityManager.ActiveNetworkInfo;
            return info != null && info.IsConnected;
        }
        return false;
    }
}
                    

iOS

On iOS, you can use the Network framework or reachability classes. You'll need to add the SystemConfiguration.framework.

Example (iOS specific)

// In your iOS platform-specific code
using System.Net;
using System.Net.NetworkInformation;
using SystemConfiguration;

public class IosNetworkHelper
{
    public static bool IsInternetAvailable()
    {
        SCNetworkReachabilityFlags flags;
        var defaultRouteReachability = new IPAddress(0).GetReachability();
        if (defaultRouteReachability.TryGetFlags(out flags))
        {
            return IsNetworkReachable(flags);
        }

        var remoteHostReachability = "www.google.com".GetReachability(); // Or any reliable host
        if (remoteHostReachability.TryGetFlags(out flags))
        {
            return IsNetworkReachable(flags);
        }

        return false;
    }

    private static bool IsNetworkReachable(SCNetworkReachabilityFlags flags)
    {
        // Check if the online flag is set.
        if (!flags.HasFlag(SCNetworkReachabilityFlags.ConnectionRequired))
        {
            return true;
        }
        return false;
    }
}

// Helper extension methods for iOS reachability
public static class ReachabilityExtensions
{
    public static SCNetworkReachability GetReachability(this IPAddress hostAddress)
    {
        return new SCNetworkReachability(hostAddress);
    }

    public static SCNetworkReachability GetReachability(this string host)
    {
        return new SCNetworkReachability(host);
    }

    public static bool TryGetFlags(this SCNetworkReachability reachability, out SCNetworkReachabilityFlags flags)
    {
        return reachability.TryGetFlags(out flags);
    }
}
                    

Manually implementing platform-specific network detection can be complex due to variations in APIs and background execution restrictions. The Plugin.NetworkConnectivity is generally the preferred and more robust solution.

Best Practices

  • Always check before making network requests: Prevent unnecessary errors and improve user experience by ensuring a connection exists before attempting to fetch data.
  • Handle offline states gracefully: Provide clear feedback to the user when they are offline. Offer options to retry or save data for later.
  • Use event handlers: Subscribe to ConnectivityChanged events to react immediately to network status updates.
  • Unsubscribe from events: Always unsubscribe from event handlers when a page or component is disposed to prevent memory leaks.
  • Consider different network types: Differentiate between Wi-Fi, Cellular, and no connection, as some operations might be restricted or more costly on cellular data.
  • Handle captive portals: For constrained networks, inform the user they might need to log in through a portal.
For critical operations, consider implementing a retry mechanism with exponential backoff for network requests that fail due to temporary network issues.