Condividi tramite


Collegamento di un'app ANDROID .NET MAUI

Quando compila l'app, l'interfaccia utente dell'app multipiattaforma .NET (.NET MAUI) può usare un linker chiamato ILLink per ridurre le dimensioni complessive dell'app. ILLink riduce le dimensioni analizzando il codice intermedio prodotto dal compilatore. Rimuove metodi, proprietà, campi, eventi, struct e classi inutilizzati per produrre un'app che contiene solo dipendenze di codice e assembly necessarie per eseguire l'app.

Comportamento del linker

Il linker consente di tagliare le app ANDROID .NET MAUI. Quando il taglio è abilitato, il linker lascia invariati gli assembly e riduce le dimensioni degli assembly SDK rimuovendo tipi e membri che l'app non usa.

Il comportamento del linker può essere configurato per ogni configurazione di compilazione dell'app. Per impostazione predefinita, il taglio è disabilitato per le compilazioni di debug e abilitato per le build di versione.

Avviso

L'abilitazione del linker per la configurazione di debug dell'app può ostacolare l'esperienza di debug, perché può rimuovere le funzioni di accesso alle proprietà che consentono di controllare lo stato degli oggetti.

Per assicurarsi che il taglio sia abilitato:

  1. In Visual Studio, in Esplora soluzioni, fare clic con il pulsante destro del mouse sul progetto di app .NET MAUI e scegliere Proprietà. Passare quindi alla > Android e assicurarsi che il taglio sia abilitato per la configurazione della build di versione:

    Screenshot del comportamento del linker per Android in Visual Studio.

Mantenere il codice

Quando si usa il trimmer, talvolta rimuove il codice che potrebbe essere stato chiamato in modo dinamico, anche indirettamente. È possibile indicare al trimmer di mantenere i membri annotandoli con l'attributo DynamicDependency . Questo attributo può essere usato per esprimere una dipendenza da un tipo e da un subset di membri o da membri specifici.

Importante

Ogni membro dell'elenco di controllo di gruppo che non può essere determinato in modo statico da usare dall'app è soggetto a essere rimosso.

L'attributo DynamicDependency può essere applicato a costruttori, campi e metodi:

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

In questo esempio, garantisce DynamicDependency che il Helper metodo venga mantenuto. Senza l'attributo, il taglio rimuove HelperMyAssembly o rimuove MyAssembly completamente se non viene fatto riferimento altrove.

L'attributo specifica il membro da mantenere tramite o string tramite l'attributo DynamicallyAccessedMembers . Il tipo e l'assembly sono impliciti nel contesto dell'attributo oppure specificati in modo esplicito nell'attributo (da Typeo da string per il tipo e il nome dell'assembly).

Le stringhe di tipo e membro usano una variante del formato di stringa dell’ID commento della documentazione di C#, senza il prefisso del membro. La stringa del membro non deve includere il nome del tipo dichiarante e può omettere i parametri per mantenere tutti i membri del nome specificato. Gli esempi seguenti mostrano usi validi:

[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<>))]

Mantenere gli assembly

È possibile specificare assembly che devono essere esclusi dal processo di taglio, consentendo al contempo l'eliminazione di altri assembly. Questo approccio può essere utile quando non è possibile usare facilmente l'attributo DynamicDependency o non controllare il codice da tagliare.

Quando taglia tutti gli assembly, è possibile indicare al trimmer di ignorare un assembly impostando un TrimmerRootAssembly elemento MSBuild nel file di progetto:

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

Nota

L'estensione .dll non è necessaria quando si imposta la TrimmerRootAssembly proprietà MSBuild.

Se il trimmer ignora un assembly, viene considerato rooted, il che significa che vengono mantenute tutte le relative dipendenze comprensibili in modo statico. È possibile ignorare altri assembly aggiungendo altre TrimmerRootAssembly proprietà di MSBuild a <ItemGroup>.

Mantenere assembly, tipi e membri

È possibile passare il trimmer di un file di descrizione XML che specifica quali assembly, tipi e membri devono essere conservati.

Per escludere un membro dal processo di taglio quando si tagliano tutti gli assembly, impostare l'elemento TrimmerRootDescriptor MSBuild nel file di progetto sul file XML che definisce i membri da escludere:

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

Il file XML usa quindi il formato del descrittore trimmer per definire i membri da escludere:

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

In questo esempio, il file XML specifica un metodo accessibile dinamicamente dall'app, escluso dal taglio.

Quando un assembly, un tipo o un membro è elencato nel codice XML, l'azione predefinita è l'archiviazione, il che significa che indipendentemente dal fatto che il trimmer pensi che venga usato o meno, viene mantenuto nell'output.

Nota

I tag di conservazione sono ambiguamente inclusivi. Se non fornisci il livello di dettaglio successivo, includerà tutti gli elementi figlio. Se un assembly è elencato senza alcun tipo, tutti i tipi e i membri dell'assembly verranno mantenuti.

Contrassegnare un assembly come ritaglio sicuro

Se si dispone di una libreria nel progetto o si è uno sviluppatore di una libreria riutilizzabile e si vuole che il trimmer consideri l'assembly come trimmable, è possibile contrassegnare l'assembly come trim safe aggiungendo la IsTrimmable proprietà MSBuild al file di progetto per l'assembly:

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

Questo contrassegna l'assembly come "trimmable" e abilita gli avvisi di taglio per il progetto. Essere "trimmable" significa che l'assembly è considerato compatibile con il taglio e non deve avere avvisi di taglio quando viene compilato l'assembly. Se usato in un'app tagliata, i membri inutilizzati dell'assembly vengono rimossi nell'output finale.

Quando si usa la distribuzione AOT nativa in .NET 9+, impostando la proprietà IsAotCompatible MSBuild su true assegna anche un valore di true alla proprietà IsTrimmable e abilita proprietà di compilazione aggiuntive dell'analizzatore AOT. Per ulteriori informazioni sugli analizzatori di compatibilità AOT, vedere AOT-compatibility analyzers. Per ulteriori informazioni sulla distribuzione AOT nativa per .NET MAUI, vedere distribuzione AOT nativa per .NET MAUI.

L'impostazione della IsTrimmable proprietà MSBuild su true nel file di progetto inserisce l'attributo nell'assembly AssemblyMetadata :

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

In alternativa, è possibile aggiungere l'attributo nell'assembly AssemblyMetadata senza aver aggiunto la IsTrimmable proprietà MSBuild al file di progetto per l'assembly.

Nota

Se la IsTrimmable proprietà MSBuild è impostata per un assembly, viene eseguito l'override dell'attributo AssemblyMetadata("IsTrimmable", "True") . Ciò consente di acconsentire esplicitamente a un assembly di taglio anche se non dispone dell'attributo o di disabilitare il taglio di un assembly con l'attributo .

Eliminare gli avvisi di analisi

Quando il trimmer è abilitato, rimuove IL che non è raggiungibile in modo statico. Le app che usano reflection o altri modelli che creano dipendenze dinamiche possono essere interrotte di conseguenza. Per avvisare di questi modelli, quando si contrassegna un assembly come tronco sicuro, gli autori della libreria devono impostare la SuppressTrimAnalysisWarnings proprietà MSBuild su false:

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

La mancata eliminazione degli avvisi di analisi di taglio includerà avvisi sull'intera app, tra cui codice personalizzato, codice della libreria e codice SDK.

Mostra avvisi dettagliati

L'analisi trim genera al massimo un avviso per ogni assembly proveniente da un PackageReferenceoggetto , a indicare che gli elementi interni dell'assembly non sono compatibili con il taglio. In qualità di autore della libreria, quando si contrassegna un assembly come ritaglio sicuro, è necessario abilitare singoli avvisi per tutti gli assembly impostando la TrimmerSingleWarn proprietà MSBuild su false:

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

Questa impostazione mostra tutti gli avvisi dettagliati, invece di compressione in un singolo avviso per assembly.