Vinculando um aplicativo .NET MAUI iOS

Quando ele cria seu aplicativo, o .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. Ele remove métodos, propriedades, campos, eventos, estruturas 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 suporta três modos para aplicativos .NET MAUI no iOS e Mac Catalyst:

  • Não vincule. A desativação da ligação garante que os assemblies não sejam modificados.
  • Ligar bibliotecas SDK somente. Nesse modo, o vinculador deixa os seus assemblies intocados e reduz o tamanho dos assemblies SDK removendo os tipos e membros que a sua aplicação não usa.
  • Vincular todos os conjuntos. Quando vincula todos os assemblies, o vinculador executa otimizações adicionais para tornar seu aplicativo o menor possível. Ele modifica o código intermédio do seu código-fonte, o que pode comprometer a sua aplicação se utilizar funcionalidades ao usar uma abordagem que a análise estática do linker não consiga detetar. Nesses casos, talvez seja necessário fazer ajustes no código-fonte para que o aplicativo funcione corretamente.

O comportamento do vinculador pode ser configurado para cada configuração de compilação do seu aplicativo.

Advertência

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

Para configurar o comportamento do vinculador no Visual Studio:

  1. 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, vá até ao separador iOS > Build e defina o menu suspenso do comportamento do linkador para o comportamento desejado:

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

Preservar código

Quando se utiliza o otimizador, por vezes, ele remove código que possa ter sido chamado dinamicamente, mesmo de forma indireta. Você pode instruir o aparador a preservar os membros anotando-os com o atributo DynamicDependency. Este atributo pode ser usado para expressar uma dependência de um tipo e subconjunto de membros, ou em membros específicos.

Importante

Todos os membros da BCL que não puderem 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, o DynamicDependency garante que o método Helper seja mantido. Sem o atributo, o corte removeria Helper de MyAssembly ou removeria completamente MyAssembly se não for 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 a assemblagem estão implícitos no contexto do atributo, ou são explicitamente especificados através do atributo (por Typeou por stringpara o tipo e o nome da assemblagem).

As cadeias de tipo e membro usam uma variação do formato de ID de comentário da documentação do C# , sem o prefixo de membro. A cadeia de caracteres de membro não deve incluir o nome do tipo de declaração e pode omitir os parâmetros para incluir todos os membros com o 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 montagens

É possível especificar assemblies que devem ser excluídos do processo de redução, permitindo que outros assemblies sejam reduzidos. Essa abordagem pode ser útil quando você não pode usar facilmente o atributo DynamicDependency 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 item MSBuild TrimmerRootAssembly 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 omitir uma assemblagem, isto é considerado enraizado, o que significa que ele e todas as suas dependências entendidas estaticamente são mantidas. Pode pular assemblies adicionais ao adicionar mais propriedades TrimmerRootAssembly MSBuild ao <ItemGroup>.

Preservar montagens, tipos e membros

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

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

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

Em seguida, o arquivo XML utiliza o formato descritor trimmer para definir quais membros devem ser excluídos.

<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 um assembly, tipo ou membro é listado no XML, a ação padrão é preservação, o que significa que, independentemente de o trimmer achar que é usado ou não, ele é preservado na saída.

Observação

As etiquetas de preservação são ambíguamente inclusivas. Se você não fornecer o próximo nível de detalhes, ele incluirá todas as crianças. Se um conjunto for mencionado sem nenhum tipo, todos os tipos e membros do conjunto serão preservados.

Marcar uma assemblagem como segura para aparar

Se tiveres uma biblioteca no teu projeto ou fores um desenvolvedor de uma biblioteca reutilizável e deseja que o trimmer trate o teu assembly como seguro para trimming, podes marcar o assembly como tal adicionando a propriedade IsTrimmable MSBuild ao ficheiro de projeto para o assembly.

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

Isto marca a sua montagem como "trimmable" e ativa avisos de corte para este projeto. Ser "trimmable" significa que o seu conjunto é considerado compatível com o corte e não deve ter avisos de corte quando o conjunto é construído. Quando usado numa aplicação reduzida, os membros não utilizados do assembly são removidos na saída final.

Ao usar a implantação AOT nativa no .NET 9+, definir a propriedade IsAotCompatible MSBuild como true também atribui um valor de true à propriedade IsTrimmable e habilita propriedades adicionais de compilação 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 de AOT nativo para .NET MAUI, consulte Native AOT deployment.

Defina a propriedade IsTrimmable MSBuild para true no seu arquivo de projeto, inserindo o atributo AssemblyMetadata na sua assemblagem:

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

Como alternativa, você pode adicionar o atributo AssemblyMetadata em seu assembly sem ter adicionado a propriedade IsTrimmable MSBuild ao arquivo de projeto para seu 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 por um assembly para corte, mesmo que ele não tenha o atributo, ou para desabilitar o corte de um assembly que tenha o atributo.

Suprimir avisos de análise

Quando o aparador está ativado, ele remove o IL que não está estaticamente acessível. Como resultado, os aplicativos que usam reflexão ou outros padrões que criam dependências dinâmicas podem ser quebrados. Para avisar sobre esses padrões, ao marcar um assembly como trim safe, os autores da biblioteca devem definir a propriedade SuppressTrimAnalysisWarnings 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 recorte de código produz, no máximo, um aviso para cada assemblagem que vem de um PackageReference, indicando que os componentes internos da assemblagem não são compatíveis com o recorte de código. Como autor de uma biblioteca, ao marcar um assembly como trim safe, você deve habilitar avisos individuais para todos os assemblies definindo a propriedade TrimmerSingleWarn MSBuild como false:

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

Essa configuração mostra todos os avisos detalhados, em vez de reduzi-los a um único aviso por montagem.