Compartilhar via


Vinculando um aplicativo Android .NET MAUI

Ao criar o seu aplicativo, a .NET Multi-Platform App UI (.NET MAUI) pode usar um vinculador chamado ILLink para reduzir o tamanho geral do aplicativo. ILLink reduz o tamanho analisando o código intermediário produzido pelo compilador. Remove métodos, propriedades, campos, eventos, structs e classes não utilizados para produzir um aplicativo que contém apenas dependências de código e assembly necessárias para executar o aplicativo.

Comportamento do vinculador

O vinculador permite que você reduza os seus aplicativos Android .NET MAUI. Quando a redução está habilitada, o vinculador deixa seus assemblies intocados e reduz o tamanho dos assemblies do SDK, removendo tipos e membros que o seu aplicativo não usa.

O comportamento do vinculador pode ser configurado para cada configuração de build do seu aplicativo. Por padrão, a redução é desabilitada para builds de depuração e habilitada para builds de lançamento.

Aviso

Habilitar o vinculador para a configuração de depuração do aplicativo pode dificultar sua experiência de depuração, pois pode remover acessadores de propriedade que permitem inspecionar o estado de seus objetos.

Para garantir que o corte esteja ativado:

  1. No Visual Studio, no Gerenciador de Soluções, clique com o botão direito do mouse em seu projeto de aplicativo .NET MAUI e selecione Propriedades. Em seguida, navegue até a guia Android > Opções e verifique se a redução está habilitada para a configuração de build de lançamento:

    Captura de tela do comportamento do vinculador para Android no Visual Studio.

Preservar código

Quando você usa o aparador, às vezes ele remove o código que você pode ter chamado dinamicamente, mesmo indiretamente. Você pode instruir o aparador a preservar os membros anotando-os com o DynamicDependency atributo. Esse atributo pode ser usado para expressar uma dependência em um tipo e subconjunto de membros ou em membros específicos.

Importante

Todos os membros do BCL que não podem ser determinados estaticamente para serem usados pelo aplicativo estão sujeitos a serem removidos.

O atributo DynamicDependency pode ser aplicado a construtores, campos e métodos:

[DynamicDependency("Helper", "MyType", "MyAssembly")]
static void RunHelper()
{
    var helper = Assembly.Load("MyAssembly").GetType("MyType").GetMethod("Helper");
    helper.Invoke(null, null);
}

Neste exemplo, DynamicDependency garante que o método Helper seja mantido. Sem o atributo, o corte removeria HelperMyAssembly ou removeria MyAssembly completamente se não fosse referenciado em outro lugar.

O atributo especifica o membro a ser mantido por meio de um string ou por meio do atributo DynamicallyAccessedMembers. O tipo e o assembly são implícitos no contexto do atributo ou explicitamente especificados no atributo (por Type, ou por strings para o tipo e nome do assembly).

As cadeias de caracteres de tipo e membro usam uma variação do formato de cadeia de caracteres de ID de comentário da documentação C#, sem o prefixo do membro. A cadeia de caracteres de membro não deve incluir o nome do tipo declarativo e pode omitir parâmetros para manter todos os membros do nome especificado. Os exemplos a seguir mostram usos válidos:

[DynamicDependency("Method()")]
[DynamicDependency("Method(System,Boolean,System.String)")]
[DynamicDependency("MethodOnDifferentType()", typeof(ContainingType))]
[DynamicDependency("MemberName")]
[DynamicDependency("MemberOnUnreferencedAssembly", "ContainingType", "UnreferencedAssembly")]
[DynamicDependency("MemberName", "Namespace.ContainingType.NestedType", "Assembly")]
// generics
[DynamicDependency("GenericMethodName``1")]
[DynamicDependency("GenericMethod``2(``0,``1)")]
[DynamicDependency("MethodWithGenericParameterTypes(System.Collections.Generic.List{System.String})")]
[DynamicDependency("MethodOnGenericType(`0)", "GenericType`1", "UnreferencedAssembly")]
[DynamicDependency("MethodOnGenericType(`0)", typeof(GenericType<>))]

Preservar assemblies

É possível especificar assemblies que devem ser excluídos do processo de corte, permitindo que outros assemblies sejam cortados. Essa abordagem pode ser útil quando você não pode usar facilmente o DynamicDependency atributo ou não controla o código que está sendo cortado.

Quando ele corta todos os assemblies, você pode dizer ao trimmer para ignorar um assembly definindo um TrimmerRootAssembly item do MSBuild no arquivo de projeto:

<ItemGroup>
  <TrimmerRootAssembly Include="MyAssembly" />
</ItemGroup>

Observação

A extensão .dll não é necessária ao definir a propriedade TrimmerRootAssembly MSBuild.

Se o aparador ignorar um assembly, ele será considerado enraizado, o que significa que ele e todas as suas dependências estaticamente compreendidas serão mantidos. Você pode ignorar os outros assemblies adicionando mais propriedades TrimmerRootAssembly MSBuild ao <ItemGroup>.

Preservar assemblies, tipos e membros

Você pode passar ao aparador um arquivo de descrição XML que especifica quais montagens, tipos e membros precisam ser mantidos.

Para excluir um membro do processo de corte ao aparar todos os assemblies, defina o TrimmerRootDescriptor item do MSBuild no arquivo de projeto como o arquivo XML que define os membros a serem excluídos:

<ItemGroup>
  <TrimmerRootDescriptor Include="MyRoots.xml" />
</ItemGroup>

Em seguida, o arquivo XML usa o formato de descritor de corte para definir quais membros excluir:

<linker>
  <assembly fullname="MyAssembly">
    <type fullname="MyAssembly.MyClass">
      <method name="DynamicallyAccessedMethod" />
    </type>
  </assembly>
</linker>

Neste exemplo, o arquivo XML especifica um método que é acessado dinamicamente pelo aplicativo, que é excluído do corte.

Quando uma montagem, tipo ou membro é listado no XML, a ação padrão é preservação, o que significa que, independentemente de o aparador achar que é usado ou não, ele é preservado na saída.

Observação

As marcas de preservação são ambíguas inclusivas. Se você não fornecer o próximo nível de detalhes, ele incluirá todos os filhos. Se um assembly estiver listado sem nenhum tipo, todos os tipos e membros do assembly serão preservados.

Marcar uma montagem como segura para corte

Se você tiver uma biblioteca em seu projeto ou for um desenvolvedor de uma biblioteca reutilizável e quiser que o aparador trate seu assembly como aparável, poderá marcar o assembly como seguro para corte adicionando a IsTrimmable propriedade MSBuild ao arquivo de projeto do assembly:

<PropertyGroup>
    <IsTrimmable>true</IsTrimmable>
</PropertyGroup>

Isso marca o assembly como "pode ser cortado" e habilita os avisos de corte para o respectivo projeto. "Pode ser cortado" significa que o assembly é considerado compatível com cortes e não deve haver avisos relacionados a cortes quando o assembly for criado. Quando usados em um aplicativo cortado, os membros não utilizados do assembly serão removidos na saída final.

Ao usar a implantação AOT nativa no .NET 9+, definir a propriedade IsAotCompatible MSBuild para true também atribui um valor de true à propriedade IsTrimmable e habilita propriedades adicionais de build do analisador AOT. Para obter mais informações sobre analisadores AOT, consulte analisadores de compatibilidade AOT. Para obter mais informações sobre a implantação do AOT nativo para o .NET MAUI, consulte implantação de AOT nativo.

Definir a propriedade IsTrimmable MSBuild como true no arquivo de projeto insere o atributo AssemblyMetadata no assembly:

[assembly: AssemblyMetadata("IsTrimmable", "True")]

Como alternativa, você pode adicionar o atributo AssemblyMetadata ao assembly sem ter adicionado a propriedade IsTrimmable MSBuild ao arquivo de projeto do assembly.

Observação

Se a propriedade IsTrimmable MSBuild estiver definida para um assembly, isso substituirá o atributo AssemblyMetadata("IsTrimmable", "True"). Isso permite que você opte pelo corte em um assembly mesmo que ele não tenha o atributo ou desabilite o corte de um assembly que tenha o atributo.

Suprimir avisos de análise

Quando o aparador está ativado, ele remove IL que não é estaticamente acessível. Como resultado, os aplicativos que usam reflexão ou outros padrões que criam dependências dinâmicas podem ser interrompidos. Para avisar sobre esses padrões, ao marcar um assembly como seguro para corte, os autores da biblioteca devem definir a SuppressTrimAnalysisWarnings propriedade MSBuild como false:

<PropertyGroup>
  <SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
</PropertyGroup>

Não suprimir avisos de análise de corte incluirá avisos sobre todo o aplicativo, incluindo seu próprio código, código de biblioteca e código SDK.

Mostrar avisos detalhados

A análise de corte produz no máximo um aviso para cada assembly proveniente de um PackageReference, indicando que os internos do assembly não são compatíveis com cortes. Como autor da biblioteca, ao marcar um assembly como trim safe, você deve habilitar avisos individuais para todos os assemblies definindo a TrimmerSingleWarn propriedade MSBuild como false:

<PropertyGroup>
  <TrimmerSingleWarn>false</TrimmerSingleWarn>
</PropertyGroup>

Essa configuração mostra todos os avisos detalhados, em vez de recolhê-los em um único aviso por assembly.