Collegamento di un'app iOS MAUI .NET
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 supporta tre modalità per le app MAUI .NET in iOS e Mac Catalyst:
- Non collegare. La disabilitazione del collegamento garantisce che gli assembly non siano modificati.
- Collegare solo assembly SDK. In questa modalità, il linker lascia invariati gli assembly e riduce le dimensioni degli assembly SDK rimuovendo tipi e membri che l'app non usa.
- Collegare tutti gli assembly. Quando collega tutti gli assembly, il linker esegue ottimizzazioni aggiuntive per rendere l'app il più piccola possibile. Modifica il codice intermedio per il codice sorgente, che potrebbe interrompere l'app se usi funzionalità usando un approccio che l'analisi statica del linker non è in grado di rilevare. In questi casi, potrebbe essere necessario apportare modifiche al codice sorgente per fare in modo che l'app funzioni correttamente.
Il comportamento del linker può essere configurato per ogni configurazione di compilazione dell'app.
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 configurare il comportamento del linker 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 scheda Compilazione iOS > e impostare l'elenco a discesa Comportamento del linker sul comportamento del linker desiderato:
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 Helper
MyAssembly
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 Type
o 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.
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 PackageReference
oggetto , 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.