Não deixe o Android 15 quebrar seu app MAUI: A correção de 3 etapas para o Edge-to-Edge
"Pare de lutar com o modo de compatibilidade. Saiba por que seu aplicativo parece uma caixa minúscula no Android 15 e como um único estilo XAML resolve isso para sempre."
Não deixe o Android 15 quebrar seu app MAUI: A correção de 3 passos para o Edge-to-Edge
Você atualizou seu app .NET MAUI para net10.0-android, enviou uma nova versão e, de repente, o app abre como uma pequena caixa no centro da tela com um fundo preto ao redor. Parece um bug do Android — mas a causa raiz é bem conhecida e a correção é permanente.
Neste post, você aprenderá exatamente o que aconteceu, por que aconteceu e como corrigir de uma forma compatível com o Android 15 e Android 16.
O que mudou no Android 15 e .NET 10
Quando o Google lançou o Android 15 (API 35), começou a impor o modo edge-to-edge para todos os apps. Isso significa que o conteúdo do app deve se estender por trás das barras do sistema (barra de status e barra de navegação).
Ao mesmo tempo, o .NET 10 introduziu uma mudança de comportamento (breaking change) silenciosa no padrão das páginas MAUI:
No .NET 9, o
ContentPagerespeitava as barras do sistema por padrão (comportamentoContainer). No .NET 10, oContentPageassume o padrão edge-to-edge (None).
A combinação de ambas as mudanças faz com que apps sem a configuração correta caiam no modo de compatibilidade do Android — que renderiza o layout em um tamanho pequeno fixo e o centraliza na tela com um fundo preto. Essa é a "caixa pequena" que você está vendo.
⚠️ Mudança de Comportamento no .NET 10
Se você migrou de net9.0-android para net10.0-android, o comportamento padrão das suas páginas mudou sem que você tocasse em uma única linha de XAML.
Sintomas
Você provavelmente está enfrentando este problema se:
- O app abre como uma pequena janela centralizada com um fundo preto ao redor
- Após a splash screen, há uma tela preta antes do app carregar
- O conteúdo está parcialmente oculto atrás da barra de status ou da barra de navegação
- O problema apareceu após um aumento de versão ou atualização de pacote para o .NET 10
Diagnóstico: As Três Causas Raiz
1. android:resizeableActivity não declarado
O Android 15 trata apps sem essa declaração como "não otimizados" e os força para o modo de compatibilidade. O resultado é a caixa pequena.
2. EdgeToEdge.Enable(this) sem tratamento de Insets
Esta API ativa corretamente o edge-to-edge, mas exige que o app trate os Window Insets — caso contrário, o conteúdo acaba atrás das barras do sistema e o fundo da janela torna-se transparente (preto).
3. SafeAreaEdges não configurado para .NET 10
Devido à mudança no .NET 10, todas as instâncias de ContentPage agora têm o padrão None. Sem definir explicitamente SafeAreaEdges, os layouts não respeitam mais as áreas seguras.
A Correção Completa
Passo 1 — AndroidManifest.xml: Declare suporte de tela e atividade redimensionável
Adicione android:resizeableActivity="true" à tag <application> e o elemento <supports-screens> logo abaixo:
<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" />
<!-- suas permissões aqui -->
</manifest>
ℹ️ Sobre windowOptOutEdgeToEdgeEnforcement
Este atributo desativa a imposição forçada de edge-to-edge do Android 15. É uma saída temporária — no Android 16 ele será totalmente ignorado. Por isso o Passo 3 é crítico para compatibilidade a longo prazo.
Passo 2 — MainActivity.cs: Remova EdgeToEdge.Enable
Se você adicionou EdgeToEdge.Enable(this) ao OnCreate, remova-o. Sem o tratamento adequado de insets, ele torna a janela transparente e causa a tela preta entre o splash e a primeira renderização:
// ANTES — causa tela preta sem tratamento de insets
protected override void OnCreate(Bundle? savedInstanceState)
{
EdgeToEdge.Enable(this); // ← remova isso
base.OnCreate(savedInstanceState);
}
// DEPOIS — limpo e correto
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
}
Passo 3 — App.xaml: Configure SafeAreaEdges globalmente
Esta é a correção definitiva — compatível com o Android 16. Adicione um estilo implícito global ao App.xaml para restaurar o comportamento do .NET 9 em todas as páginas de uma só vez:
<Application.Resources>
<ResourceDictionary>
<Style TargetType="ContentPage" ApplyToDerivedTypes="True">
<Setter Property="SafeAreaEdges" Value="Container" />
</Style>
<!-- resto dos seus recursos -->
</ResourceDictionary>
</Application.Resources>
✅ Um Estilo, Todas as Páginas
Como ApplyToDerivedTypes="True" está definido, este estilo se aplica a cada página no seu app — incluindo páginas Shell e subclasses de páginas personalizadas — sem tocar em arquivos XAML individuais.
Por que SafeAreaEdges="Container" é a correção correta
SafeAreaEdges foi introduzido no .NET MAUI 10 como a API oficial para controle de área segura. Ele opera na camada do MAUI usando Window Insets — a API moderna do Android — e se adapta automaticamente a qualquer versão do SO.
| Valor | Comportamento |
|---|---|
None |
Edge-to-edge total — o conteúdo pode se estender atrás das barras do sistema |
Container |
Respeita as barras do sistema e notches (mesmo padrão do .NET 9) |
SoftInput |
Respeita apenas o inset do teclado virtual |
All |
Respeita tudo, incluindo o teclado |
A principal vantagem sobre as soluções alternativas no nível do manifesto: ele funciona em tempo de execução via Window Insets, adaptando-se corretamente independentemente da versão do Android — incluindo o Android 16, que removerá totalmente a opção windowOptOutEdgeToEdgeEnforcement.
Comparação de Soluções
| Abordagem | Android 15 | Android 16 | Complexidade |
|---|---|---|---|
Apenas windowOptOutEdgeToEdgeEnforcement |
✅ Funciona | ❌ Removido | Baixa |
EdgeToEdge.Enable sem insets |
✅ Funciona | ✅ Funciona | Alta — precisa de tratamento de insets por página |
Estilo global SafeAreaEdges="Container" |
✅ Funciona | ✅ Funciona | Baixa — uma linha |
Casos Especiais: Sobrescrevendo por Página
O estilo global Container cobre a grande maioria das telas. Para páginas específicas que precisam de um comportamento diferente, basta sobrescrever a propriedade inline:
Página Imersiva (visualizador de fotos, splash personalizado)
<ContentPage SafeAreaEdges="None">
<!-- o conteúdo se estende atrás das barras do sistema -->
</ContentPage>
Página com Entrada na Parte Inferior (chat, formulários)
<ContentPage SafeAreaEdges="All">
<!-- o teclado não cobrirá o conteúdo -->
</ContentPage>
Layout Híbrido (cabeçalho edge-to-edge + área de conteúdo segura)
<ContentPage SafeAreaEdges="None">
<Grid RowDefinitions="Auto,*">
<!-- O cabeçalho se estende atrás da barra de status -->
<Grid BackgroundColor="{StaticResource PrimaryColor}"
SafeAreaEdges="None" />
<!-- O conteúdo respeita as áreas seguras -->
<ScrollView Grid.Row="1"
SafeAreaEdges="Container" />
</Grid>
</ContentPage>
ℹ️ ScrollView e SafeAreaEdges
Definir SafeAreaEdges diretamente em um ScrollView não tem efeito para evitar o teclado. Envolva o ScrollView dentro de um layout e defina SafeAreaEdges no container.
Checklist de Migração: .NET 9 → .NET 10 (Android)
- Adicione
android:resizeableActivity="true"à tag<application>no manifesto - Adicione
<supports-screens>com todos os tamanhos de tela habilitados - Remova
EdgeToEdge.Enable(this)doMainActivity.cs - Adicione o estilo implícito global
SafeAreaEdges="Container"noApp.xaml - Teste em um dispositivo físico com Android 14 ou superior
- Teste em um dispositivo com notch ou câmera punch-hole
- Verifique se o teclado não sobrepõe os campos de entrada em páginas com muitos formulários
Perguntas Frequentes
Isso quebrará versões mais antigas do Android?
Não. SafeAreaEdges usa Window Insets, que está disponível e é seguro em todas as versões do Android suportadas pelo .NET MAUI (minSdk 23+). Em dispositivos mais antigos, o comportamento é idêntico ao anterior.
Preciso atualizar todos os arquivos XAML?
Não. O estilo global implícito no App.xaml se aplica a cada ContentPage automaticamente. Você só precisa adicionar sobrescritas por página para telas que intencionalmente precisam de um comportamento diferente.
Posso manter windowOptOutEdgeToEdgeEnforcement="true" no manifesto?
Sim, por enquanto. Não prejudica e fornece uma rede de segurança extra no Android 15. Apenas esteja ciente de que ele será removido no Android 16, e é por isso que SafeAreaEdges="Container" é a solução de longo prazo.
E quanto ao iOS?
SafeAreaEdges também funciona no iOS, substituindo o atributo legado ios:Page.UseSafeArea="True". Se você estava usando isso, pode migrar com segurança para SafeAreaEdges="Container" também.
Conclusão
A migração para net10.0-android introduziu uma mudança de comportamento silenciosa que afeta todos os apps MAUI: o comportamento padrão do ContentPage mudou de Container para None. Combinado com as novas regras de imposição de edge-to-edge do Android 15, o resultado é o layout de caixa pequena ou uma tela preta na inicialização.
A correção leva três linhas de XAML no App.xaml — mas é importante aplicá-la agora, antes que o Android 16 chegue aos dispositivos dos seus usuários e a opção de saída do manifesto pare de funcionar completamente.
Se você mantém vários apps MAUI, aplique todos os três passos em cada um. O esforço é mínimo e você estará coberto para a próxima onda de lançamentos do Android.
Leituras relacionadas
Explore por tema
FAQ
O que mudou no Android 15 e .NET 10
Quando o Google lançou o Android 15 (API 35), começou a impor o modo edge-to-edge para todos os apps. Isso significa que o conteúdo do app deve se estender por trás das barras do sistema (barra de status e barra de navegação).
