CW
Navigation

Language

πŸ‡§πŸ‡· PT πŸ‡ΊπŸ‡Έ EN

Navigation

Home About Stack Companies Blog
CONTACT
Back to Blog
25 May 2026 13 Views
Don't Let Android 15 Break Your MAUI App: The 3-Step Edge-to-Edge Fix

Don't Let Android 15 Break Your MAUI App: The 3-Step Edge-to-Edge Fix

"Stop wrestling with compatibility mode. Learn why your app looks like a tiny box on Android 15 and how a single XAML style fixes it forever."

Don't Let Android 15 Break Your MAUI App: The 3-Step Edge-to-Edge Fix

You updated your .NET MAUI app to net10.0-android, shipped a new release, and suddenly the app opens as a tiny box in the center of the screen with a black background all around it. It looks like an Android bug β€” but the root cause is well understood, and the fix is permanent.

In this post you'll learn exactly what happened, why it happened, and how to fix it in a way that's compatible with Android 15 and Android 16.


What Changed in Android 15 and .NET 10

When Google released Android 15 (API 35), it started enforcing edge-to-edge mode for all apps. This means app content is expected to extend behind the system bars (status bar and navigation bar).

At the same time, .NET 10 introduced a silent breaking change in the default behavior of MAUI pages:

In .NET 9, ContentPage respected system bars by default (Container behavior). In .NET 10, ContentPage defaults to edge-to-edge (None).

The combination of both changes causes apps without the correct configuration to fall into Android's compatibility mode β€” which renders the layout at a fixed small size and centers it on screen with a black background. That's the "small box" you're seeing.

⚠️ Breaking Change in .NET 10

If you migrated from net9.0-android to net10.0-android, your pages' default behavior changed without you touching a single line of XAML.


Symptoms

You're likely hitting this issue if:

  • The app opens as a small centered window with a black background around it
  • After the splash screen, there's a black screen before the app loads
  • Content is partially hidden behind the status bar or navigation bar
  • The problem appeared after a version bump or package update to .NET 10

Diagnosis: The Three Root Causes

1. android:resizeableActivity Not Declared

Android 15 treats apps without this declaration as "not optimized" and forces them into compatibility mode. The result is the small box.

2. EdgeToEdge.Enable(this) Without Inset Handling

This API correctly activates edge-to-edge, but it requires the app to handle Window Insets β€” otherwise content ends up behind the system bars and the window background becomes transparent (black).

3. SafeAreaEdges Not Configured for .NET 10

Due to the .NET 10 breaking change, all ContentPage instances now default to None. Without explicitly setting SafeAreaEdges, layouts no longer respect safe areas.


The Complete Fix

Step 1 β€” AndroidManifest.xml: Declare Screen Support and Resizable Activity

Add android:resizeableActivity="true" to the <application> tag and the <supports-screens> element right below it:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  <application
    android:allowBackup="true"
    android:icon="@mipmap/appicon"
    android:label="${applicationLabel}"
    android:usesCleartextTraffic="true"
    android:windowOptOutEdgeToEdgeEnforcement="true"
    android:resizeableActivity="true">
  </application>

  <supports-screens
    android:smallScreens="true"
    android:normalScreens="true"
    android:largeScreens="true"
    android:xlargeScreens="true"
    android:anyDensity="true" />

  <!-- your permissions here -->
</manifest>

ℹ️ About windowOptOutEdgeToEdgeEnforcement

This attribute disables Android 15's forced edge-to-edge enforcement. It's a temporary escape hatch β€” in Android 16 it will be ignored entirely. That's why Step 3 is critical for long-term compatibility.


Step 2 β€” MainActivity.cs: Remove EdgeToEdge.Enable

If you added EdgeToEdge.Enable(this) to OnCreate, remove it. Without proper inset handling, it makes the window transparent and causes the black screen between splash and first render:

// BEFORE β€” causes black screen without inset handling
protected override void OnCreate(Bundle? savedInstanceState)
{
    EdgeToEdge.Enable(this); // ← remove this
    base.OnCreate(savedInstanceState);
}
// AFTER β€” clean and correct
protected override void OnCreate(Bundle? savedInstanceState)
{
    base.OnCreate(savedInstanceState);
}

Step 3 β€” App.xaml: Configure SafeAreaEdges Globally

This is the definitive fix β€” compatible with Android 16. Add a global implicit style to App.xaml to restore .NET 9 behavior across all pages at once:

<Application.Resources>
    <ResourceDictionary>

        <Style TargetType="ContentPage" ApplyToDerivedTypes="True">
            <Setter Property="SafeAreaEdges" Value="Container" />
        </Style>

        <!-- rest of your resources -->

    </ResourceDictionary>
</Application.Resources>

βœ… One Style, All Pages

Because ApplyToDerivedTypes="True" is set, this style applies to every page in your app β€” including Shell pages and custom page subclasses β€” without touching individual XAML files.


Why SafeAreaEdges="Container" Is the Right Fix

SafeAreaEdges was introduced in .NET MAUI 10 as the official API for safe area control. It operates at the MAUI layer using Window Insets β€” the modern Android API β€” and automatically adapts to any OS version.

Value Behavior
None Full edge-to-edge β€” content can extend behind system bars
Container Respects system bars and notches (same as .NET 9 default)
SoftInput Respects only the soft keyboard inset
All Respects everything, including the keyboard

The key advantage over manifest-level workarounds: it works at runtime via Window Insets, so it adapts correctly regardless of Android version β€” including Android 16, which will remove the windowOptOutEdgeToEdgeEnforcement opt-out entirely.


Solution Comparison

Approach Android 15 Android 16 Complexity
windowOptOutEdgeToEdgeEnforcement only βœ… Works ❌ Removed Low
EdgeToEdge.Enable without insets βœ… Works βœ… Works High β€” needs per-page inset handling
SafeAreaEdges="Container" global style βœ… Works βœ… Works Low β€” one line

Special Cases: Overriding Per Page

The global Container style covers the vast majority of screens. For specific pages that need different behavior, simply override the property inline:

Immersive Page (photo viewer, custom splash)

<ContentPage SafeAreaEdges="None">
    <!-- content extends behind system bars -->
</ContentPage>

Page With Input at the Bottom (chat, forms)

<ContentPage SafeAreaEdges="All">
    <!-- keyboard won't cover content -->
</ContentPage>

Hybrid Layout (edge-to-edge header + safe content area)

<ContentPage SafeAreaEdges="None">
    <Grid RowDefinitions="Auto,*">

        <!-- Header bleeds behind the status bar -->
        <Grid BackgroundColor="{StaticResource PrimaryColor}"
              SafeAreaEdges="None" />

        <!-- Content respects safe areas -->
        <ScrollView Grid.Row="1"
                    SafeAreaEdges="Container" />

    </Grid>
</ContentPage>

ℹ️ ScrollView and SafeAreaEdges

Setting SafeAreaEdges directly on a ScrollView has no effect for keyboard avoidance. Wrap the ScrollView inside a layout and set SafeAreaEdges on the container instead.


Migration Checklist: .NET 9 β†’ .NET 10 (Android)

  • Add android:resizeableActivity="true" to the <application> tag in the manifest
  • Add <supports-screens> with all screen sizes enabled
  • Remove EdgeToEdge.Enable(this) from MainActivity.cs
  • Add global SafeAreaEdges="Container" implicit style in App.xaml
  • Test on a physical device running Android 14 or higher
  • Test on a device with a notch or punch-hole camera
  • Verify that keyboard does not overlap input fields on entry-heavy pages

Frequently Asked Questions

Will this break older Android versions?

No. SafeAreaEdges uses Window Insets, which is available and safe across all Android versions supported by .NET MAUI (minSdk 23+). On older devices the behavior is identical to before.

Do I need to update every XAML file?

No. The implicit global style in App.xaml applies to every ContentPage automatically. You only need to add per-page overrides for screens that intentionally need different behavior.

Can I keep windowOptOutEdgeToEdgeEnforcement="true" in the manifest?

Yes, for now. It doesn't hurt and provides an extra safety net on Android 15. Just be aware it will be removed in Android 16, which is why SafeAreaEdges="Container" is the long-term solution.

What about iOS?

SafeAreaEdges works on iOS too, replacing the legacy ios:Page.UseSafeArea="True" attribute. If you were using that, you can safely migrate to SafeAreaEdges="Container" as well.


Conclusion

The migration to net10.0-android introduced a silent breaking change that affects every MAUI app: the default behavior of ContentPage shifted from Container to None. Combined with Android 15's new edge-to-edge enforcement rules, the result is the small box layout or a black screen on startup.

The fix takes three lines of XAML in App.xaml β€” but it's important to apply it now, before Android 16 reaches your users' devices and the manifest opt-out stops working altogether.

If you maintain multiple MAUI apps, apply all three steps to each one. The effort is minimal, and you'll be covered for the next wave of Android releases.

Cezar Wagenheimer
Written By

Cezar Wagenheimer

Full Stack Developer & Game Creator. Specialized in building immersive digital experiences and advanced systems.

Connect:
Share this article

Related reads

Explore by topic

FAQ

What Changed in Android 15 and .NET 10

When Google released Android 15 (API 35), it started enforcing edge-to-edge mode for all apps. This means app content is expected to extend behind the system bars (status bar and navigation bar).

Comments

Be the first to comment!

Leave a comment