.NET MAUI-alkalmazás optimalizálása
Az alkalmazás létrehozásakor a .NET többplatformos alkalmazás felhasználói felülete (.NET MAUI) használhat egy ILLink nevű linkert az alkalmazás általános méretének csökkentéséhez egy úgynevezett vágási technikával. ILLink csökkenti a méretet a fordító által létrehozott köztes kód elemzésével. Eltávolítja a nem használt metódusokat, tulajdonságokat, mezőket, eseményeket, szerkezeteket és osztályokat egy olyan alkalmazás létrehozásához, amely csak az alkalmazás futtatásához szükséges kód- és szerelvényfüggőségeket tartalmazza.
Az alkalmazások levágásakor bekövetkező viselkedésváltozások megakadályozása érdekében a .NET a vágási kompatibilitás statikus elemzését teszi lehetővé vágási figyelmeztetések használatával. A vágógép vágási figyelmeztetéseket hoz létre, amikor olyan kódot talál, amely nem kompatibilis a vágással. Ha vannak vágási figyelmeztetések, ezeket ki kell javítani, és a vágás után alaposan tesztelni kell az alkalmazást annak érdekében, hogy ne változhasson a viselkedés. További információkért lásd: Bevezetés a vágási figyelmeztetésekbe.
Vágási folyamat
A vágási viselkedés úgy szabályozható, hogy a $(TrimMode)
build tulajdonságot partial
vagy full
értékre állítjuk.
<PropertyGroup>
<TrimMode>full</TrimMode>
</PropertyGroup>
Fontos
A $(TrimMode)
build tulajdonságot nem szabad a buildkonfiguráció határozza meg. Ennek az az oka, hogy a funkciók kapcsolói a $(TrimMode)
buildtulajdonság értéke alapján vannak engedélyezve vagy letiltva, és minden buildkonfigurációban engedélyezni vagy letiltani kell ugyanazokat a funkciókat, hogy a kód azonos módon viselkedjen.
A full
vágási mód eltávolítja az alkalmazás által nem használt kódot. A partial
vágási mód levágja az alaposztály-kódtárat (BCL), az alapul szolgáló platformok (például Mono.Android.dll és Microsoft.iOS.dll) szerelvényeket, valamint azokat a szerelvényeket, amelyek a $(TrimmableAsssembly)
összeállítási elemhez való vágást űzték:
<ItemGroup>
<TrimmableAssembly Include="MyAssembly" />
</ItemGroup>
Ez egyenértékű a [AssemblyMetadata("IsTrimmable", "True")]
beállításával a szerelvény létrehozásakor.
Jegyzet
Nem szükséges a $(PublishTrimmed)
buildtulajdonságot úgy beállítani, hogy true
legyen az alkalmazás projektfájljában, mert ez alapértelmezés szerint be van állítva.
További vágási beállításokért lásd .
Az alapértelmezett vágási beállítások
Alapértelmezés szerint az Android- és Mac Catalyst-buildek részleges vágást használnak, ha a buildkonfiguráció kiadási buildre van állítva. Az iOS részleges vágást használ az eszköz buildjeihez, függetlenül a buildkonfigurációtól, és nem használ vágást szimulátor-buildekhez.
Inkompatibilitások vágása
A következő .NET MAUI-funkciók nem kompatibilisek a teljes vágással, és a vágó eltávolítja őket:
- Kötési kifejezések, amelyeknél a kötési útvonal sztringre van állítva. Ehelyett használjon kompilált kötéseket. További információ: Lefordított kötések.
- Implicit konverziós operátorok, amikor inkompatibilis típusú értéket rendelnek egy XAML-tulajdonsághoz, vagy ha két különböző típusú tulajdonság használ adatkötést. Ehelyett meg kell adnia egy TypeConverter a típushoz, és csatolnia kell a típushoz a TypeConverterAttributehasználatával. További információért lásd: - hogyan definiáljunk egy TypeConvertert egy implicit konverziós operátor helyettesítésére.
- Az XAML betöltése futásidőben a LoadFromXaml bővítménymetódussal. Ez az XAML biztonságossá tehető az összes olyan típus megjegyzésével, amely futásidőben betölthető a
DynamicallyAccessedMembers
attribútummal vagy aDynamicDependency
attribútummal. Ez azonban nagyon gyakori hiba, és nem ajánlott. - Navigációs adatok fogadása a QueryPropertyAttributehasználatával. Ehelyett a IQueryAttributable felületet olyan típusokra kell implementálnia, amelyeknek el kell fogadniuk a lekérdezési paramétereket. További információ: Navigációs adatok feldolgozása egyetlen metódussal.
- A
SearchHandler.DisplayMemberName
tulajdonság. Ehelyett célszerű megadnia egy ItemTemplate-t a SearchHandler eredmények megjelenésének meghatározásához. További információ: Keresési eredmények elem megjelenésének meghatározása. - A HybridWebView vezérlő használatának oka a dinamikus
System.Text.Json
szerializálási funkciók. - Felhasználói felület testreszabása az
OnPlatform
XAML korrektúrakiterjesztéssel. Ehelyett a OnPlatform<T> osztályt kell használnia. További információ: Felhasználói felület megjelenésének testreszabása a platformalapján. - Felhasználói felület testreszabása az
OnIdiom
XAML korrektúrakiterjesztéssel. Ehelyett a OnIdiom<T> osztályt kell használnia. További információ: A felhasználói felület megjelenésének testreszabása az eszköz típusának alapján.
Alternatív megoldásként használhat funkciókapcsolókat is, hogy a vágó megőrizze ezeknek a funkcióknak a kódját. További információért lásd: Trimming funkciókapcsolók.
A .NET trimmelési inkompatibilitásairól lásd: Ismert trimmelési inkompatibilitások.
TypeConverter definiálása implicit konverziós operátor helyére
Nem lehet implicit konverziós operátorokra támaszkodni, ha inkompatibilis típusú értéket rendel egy XAML-tulajdonsághoz, vagy ha két különböző típusú tulajdonság használ adatkötést, ha engedélyezve van a teljes vágás. Ennek az az oka, hogy az implicit operátori metódusokat a vágó eltávolíthatja, ha nem használják őket a C#-kódban. További információ az implicit konverziós operátorokról: Felhasználó által definiált explicit és implicit konverziós operátorok.
Vegyük például az alábbi típust, amely implicit konverziós operátorokat határoz meg SizeRequest
és Size
között:
namespace MyMauiApp;
public struct SizeRequest : IEquatable<SizeRequest>
{
public Size Request { get; set; }
public Size Minimum { get; set; }
public SizeRequest(Size request, Size minimum)
{
Request = request;
Minimum = minimum;
}
public SizeRequest(Size request)
{
Request = request;
Minimum = request;
}
public override string ToString()
{
return string.Format("{{Request={0} Minimum={1}}}", Request, Minimum);
}
public bool Equals(SizeRequest other) => Request.Equals(other.Request) && Minimum.Equals(other.Minimum);
public static implicit operator SizeRequest(Size size) => new SizeRequest(size);
public static implicit operator Size(SizeRequest size) => size.Request;
public override bool Equals(object? obj) => obj is SizeRequest other && Equals(other);
public override int GetHashCode() => Request.GetHashCode() ^ Minimum.GetHashCode();
public static bool operator ==(SizeRequest left, SizeRequest right) => left.Equals(right);
public static bool operator !=(SizeRequest left, SizeRequest right) => !(left == right);
}
Ha a teljes vágás engedélyezve van, a SizeRequest
és Size
közötti implicit konverziós operátorokat a vágó eltávolíthatja, ha nem használják őket a C# kódban.
Ehelyett definiáljon egy TypeConverter-t a típus számára, és csatolja a TypeConverterAttribute-et a típushoz.
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
namespace MyMauiApp;
[TypeConverter(typeof(SizeRequestTypeConverter))]
public struct SizeRequest : IEquatable<SizeRequest>
{
public Size Request { get; set; }
public Size Minimum { get; set; }
public SizeRequest(Size request, Size minimum)
{
Request = request;
Minimum = minimum;
}
public SizeRequest(Size request)
{
Request = request;
Minimum = request;
}
public override string ToString()
{
return string.Format("{{Request={0} Minimum={1}}}", Request, Minimum);
}
public bool Equals(SizeRequest other) => Request.Equals(other.Request) && Minimum.Equals(other.Minimum);
public static implicit operator SizeRequest(Size size) => new SizeRequest(size);
public static implicit operator Size(SizeRequest size) => size.Request;
public override bool Equals(object? obj) => obj is SizeRequest other && Equals(other);
public override int GetHashCode() => Request.GetHashCode() ^ Minimum.GetHashCode();
public static bool operator ==(SizeRequest left, SizeRequest right) => left.Equals(right);
public static bool operator !=(SizeRequest left, SizeRequest right) => !(left == right);
private sealed class SizeRequestTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
=> sourceType == typeof(Size);
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
=> value switch
{
Size size => (SizeRequest)size,
_ => throw new NotSupportedException()
};
public override bool CanConvertTo(ITypeDescriptorContext? context, [NotNullWhen(true)] Type? destinationType)
=> destinationType == typeof(Size);
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
{
if (value is SizeRequest sizeRequest)
{
if (destinationType == typeof(Size))
return (Size)sizeRequest;
}
throw new NotSupportedException();
}
}
}
Trimmelési funkciókapcsolók
A .NET MAUI rendelkezik trimmer-irányelvekkel, amelyek funkciókapcsolókként is ismertek, és amelyek lehetővé teszik a kód megőrzését olyan funkciók esetében, amelyeknél a vágás nem biztonságos. Ezek a nyesési irányelvek akkor használhatók, ha a $(TrimMode)
buildtulajdonság full
-re van állítva, valamint a natív AOT esetében is.
MSBuild tulajdonság | Leírás |
---|---|
MauiEnableVisualAssemblyScanning |
Ha true értékre van állítva, a .NET MAUI megvizsgálja a szerelvényeket a IVisual -t implementáló típusok és a [assembly:Visual(...)] attribútumokkal rendelkező típusok után, majd regisztrálja ezeket a típusokat. Ez a buildtulajdonság alapértelmezés szerint false , ha engedélyezve van a teljes vágás. |
MauiShellSearchResultsRendererDisplayMemberNameSupported |
Ha false értékre van állítva, a SearchHandler.DisplayMemberName értéke figyelmen kívül lesz hagyva. Ehelyett meg kell adnia a ItemTemplate-t a SearchHandler eredmények megjelenésének meghatározásához. Alapértelmezés szerint ez a build-tulajdonság false -ra van állítva, amikor a teljes ritkítás vagy a natív AOT engedélyezve van. |
MauiQueryPropertyAttributeSupport |
Ha false értékre van állítva, [QueryProperty(...)] attribútumok nem használhatók a tulajdonságértékek beállítására navigáláskor. Ehelyett a IQueryAttributable felületet kell implementálnia a lekérdezési paraméterek elfogadásához. Alapértelmezés szerint ez a buildtulajdonság false -ra van állítva, ha a teljes metszés vagy a Natív AOT engedélyezve van. |
MauiImplicitCastOperatorsUsageViaReflectionSupport |
Ha false értékre van állítva, a .NET MAUI nem fog implicit konverziós operátorokat keresni az értékek egyik típusból a másikba való konvertálásakor. Ez hatással lehet a különböző típusú tulajdonságok közötti kötésekre, valamint egy más típusú kötésű objektum tulajdonságértékének beállítására. Ehelyett definiáljon egy TypeConverter definíciót a típushoz, és csatolja a típushoz a TypeConverterAttribute attribútum használatával. Alapértelmezés szerint, ha a teljes trimmelés vagy a natív AOT engedélyezve van, ez a build tulajdonság false . |
_MauiBindingInterceptorsSupport |
Ha false értékre van állítva, a .NET MAUI nem fogja elfogni a SetBinding metódusokra irányuló hívásokat, és nem próbálja meg lefordítani őket. Alapértelmezés szerint ennek a buildtulajdonságnak az értéke true . |
MauiEnableXamlCBindingWithSourceCompilation |
Ha true értékre van állítva, a .NET MAUI az összes kötést lefordítja, beleértve azokat is, ahol a Source tulajdonságot használják. Ha engedélyezi ezt a funkciót, győződjön meg arról, hogy minden kapcsolat rendelkezzen a megfelelő x:DataType -val a fordításhoz, vagy törölje az adattípust x:Data={x:Null}} , ha nem kell a kapcsolatokat fordítani. Alapértelmezés szerint ez a build tulajdonság true -ra van állítva, ha engedélyezve van a teljes metszés vagy a natív AOT. |
MauiHybridWebViewSupported |
Ha false értékre van állítva, a HybridWebView vezérlő nem lesz elérhető. Alapértelmezés szerint ez a build tulajdonság false -ra van állítva, ha a teljes trimmelés vagy a natív AOT engedélyezve van. |
Ezek az MSBuild tulajdonságok egyenértékű AppContext kapcsolókkal is rendelkeznek:
- Az
MauiEnableVisualAssemblyScanning
MSBuild tulajdonságnak van egy érvényes AppContext kapcsolója, amelynek neveMicrosoft.Maui.RuntimeFeature.IsIVisualAssemblyScanningEnabled
. - Az
MauiShellSearchResultsRendererDisplayMemberNameSupported
MSBuild tulajdonságMicrosoft.Maui.RuntimeFeature.IsShellSearchResultsRendererDisplayMemberNameSupported
nevű egyenértékű AppContext kapcsolóval rendelkezik. - Az
MauiQueryPropertyAttributeSupport
MSBuild tulajdonságMicrosoft.Maui.RuntimeFeature.IsQueryPropertyAttributeSupported
nevű egyenértékű AppContext kapcsolóval rendelkezik. - Az
MauiImplicitCastOperatorsUsageViaReflectionSupport
MSBuild tulajdonságnak van egyMicrosoft.Maui.RuntimeFeature.IsImplicitCastOperatorsUsageViaReflectionSupported
nevű egyenértékű AppContext kapcsolója. - Az
_MauiBindingInterceptorsSupport
MSBuild tulajdonságnak van egy AppContext kapcsoló nevű egyenértékűje, amelyetMicrosoft.Maui.RuntimeFeature.AreBindingInterceptorsSupported
-nek hívnak. - Az
MauiEnableXamlCBindingWithSourceCompilation
MSBuild tulajdonságnak van egy AppContext kapcsolóval egyenértékű kapcsolója, amelyetMicrosoft.Maui.RuntimeFeature.MauiEnableXamlCBindingWithSourceCompilationEnabled
-nek hívnak. - Az
MauiHybridWebViewSupported
MSBuild tulajdonságnak van egyMicrosoft.Maui.RuntimeFeature.IsHybridWebViewSupported
nevű egyenértékű AppContext kapcsolója.
A funkciókapcsolók legegyszerűbben úgy használhatók, ha a megfelelő MSBuild tulajdonságot az alkalmazás projektfájljába (*.csproj) helyezik, ami miatt a kapcsolódó kód le lesz vágva a .NET MAUI-szerelvényekből.
Kód megőrzése
Ha a vágót használja, az néha eltávolítja a dinamikusan, akár közvetetten is meghívható kódot. Megadhatja a vágónak az utasítást, hogy őrizze meg a tagokat azáltal, hogy ellátja őket a DynamicDependency
attribútummal. Ez az attribútum a tagok típusától és részhalmazától, illetve adott tagoktól való függőség kifejezésére használható.
Fontos
A BCL minden olyan tagjának eltávolítására van szükség, amelyről nem állapítható meg statikusan, hogy az alkalmazás használja.
A DynamicDependency
attribútum konstruktorokra, mezőkre és metódusokra alkalmazható:
[DynamicDependency("Helper", "MyType", "MyAssembly")]
static void RunHelper()
{
var helper = Assembly.Load("MyAssembly").GetType("MyType").GetMethod("Helper");
helper.Invoke(null, null);
}
Ebben a példában a DynamicDependency
biztosítja, hogy a Helper
metódus megmarad. Az attribútum nélkül a vágás eltávolítja Helper
-t a MyAssembly
-ből, vagy teljesen eltávolítja MyAssembly
-t, ha nincs másutt hivatkozva rá.
Az attribútum egy string
vagy a DynamicallyAccessedMembers
attribútumon keresztül adja meg a megtartandó tagot. A típus és a szerelvény implicit módon szerepel az attribútumkörnyezetben, vagy explicit módon meg van adva az attribútumban (Type
vagy string
s a típus és a szerelvény neve alapján).
A típus- és tagsztringek a C#-dokumentáció megjegyzésazonosító-sztringjének egy változatát, a formátumot használják, a tagelőtag nélkül,. A tagsztring nem tartalmazhatja a deklarálási típus nevét, és kihagyhatja a paramétereket a megadott név összes tagjának megtartásához. Az alábbi példák érvényes felhasználási módokat mutatnak be:
[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<>))]
Szerelvények megőrzése
Megadhatja azokat a szerelvényeket, amelyeket ki kell zárni a vágási folyamatból, miközben más szerelvényeket is levághat. Ez a módszer akkor lehet hasznos, ha nem tudja könnyen használni a DynamicDependency
attribútumot, vagy nem tudja szabályozni a levágott kódot.
Ha az összes szerelvényt levágja, megadhatja a vágónak, hogy hagyja ki a szerelvényt, ha beállít egy TrimmerRootAssembly
MSBuild elemet a projektfájlban:
<ItemGroup>
<TrimmerRootAssembly Include="MyAssembly" />
</ItemGroup>
Jegyzet
A .dll
bővítmény nem szükséges az TrimmerRootAssembly
MSBuild tulajdonság beállításakor.
Ha a nyíró kihagy egy összeszerelést, akkor gyökérkénttekinthető, ami azt jelenti, hogy az és az összes statikusan értett függősége megmarad. Más összeállításokat kihagyhat, ha további TrimmerRootAssembly
MSBuild tulajdonságokat ad hozzá a <ItemGroup>
.
Szerelvények, típusok és tagok megőrzése
A vágónak átadhat egy XML-leírásfájlt, amely meghatározza, hogy mely szerelvényeket, típusokat és tagokat kell megőrizni.
Ha ki szeretne zárni egy tagot a vágási folyamatból az összes szerelvény levágásakor, állítsa a TrimmerRootDescriptor
MSBuild elemet a projektfájlban arra az XML-fájlra, amely meghatározza a kizárni kívánt tagokat:
<ItemGroup>
<TrimmerRootDescriptor Include="MyRoots.xml" />
</ItemGroup>
Az XML-fájl ezután a jelölőt használja formátumban annak meghatározására, hogy mely tagokat kell kizárni:
<linker>
<assembly fullname="MyAssembly">
<type fullname="MyAssembly.MyClass">
<method name="DynamicallyAccessedMethod" />
</type>
</assembly>
</linker>
Ebben a példában az XML-fájl egy olyan metódust határoz meg, amelyet az alkalmazás dinamikusan elér, és amely nincs kizárva a vágásból.
Ha egy szerelvény, típus vagy tag szerepel az XML-ben, az alapértelmezett művelet a megőrzés, ami azt jelenti, hogy függetlenül attól, hogy a vágó azt használja-e vagy sem, megmarad a kimenetben.
Jegyzet
A tartósítási címkék nem egyértelműek. Ha nem adja meg a következő részletességi szintet, az az összes gyermekre kiterjed. Ha egy szerelvény típusok nélkül szerepel a listán, akkor a rendszer megőrzi a szerelvény összes típusát és tagját.
Szerelvény megjelölése vágásbiztosként
Ha van egy kódtár a projektben, vagy Ön egy újrafelhasználható kódtár fejlesztője, és azt szeretné, hogy a vágó a szerelvényt vághatóként kezelje, a szerelvényt vágásbiztosként megjelölheti úgy, hogy hozzáadja a IsTrimmable
MSBuild tulajdonságot a szerelvény projektfájljához:
<PropertyGroup>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>
Ez "vághatóként" jelöli meg a szerelvényt, és engedélyezi az adott projektre vonatkozó vágási figyelmeztetéseket. A "vágható" állapot azt jelenti, hogy a szerelvény kompatibilisnek tekinthető a vágással, és a szerelvény létrehozásakor nem lehetnek vágási figyelmeztetések. Ha egy optimalizált alkalmazásban használják, a rendszer eltávolítja az összetevő nem használt elemeit a végső kimenetben.
Ha natív AOT-telepítést használ a .NET 9+-ban, a IsAotCompatible
MSBuild tulajdonság beállítása true
a IsTrimmable
tulajdonsághoz is hozzárendel egy true
értéket, és további AOT-elemző buildtulajdonságokat tesz lehetővé. További információ az AOT-elemzőkről: AOT-kompatibilis elemzők. További információért a .NET MAUI natív AOT-üzembe helyezéséről lásd: - natív AOT-üzembe helyezés -.
Ha a projektfájlban beállítja a(z) IsTrimmable
MSBuild tulajdonságot true
értékre, a AssemblyMetadata
attribútumot beszúrja az összeállításba.
[assembly: AssemblyMetadata("IsTrimmable", "True")]
Másik lehetőségként hozzáadhatja a AssemblyMetadata
attribútumot a szerelvényhez anélkül, hogy hozzáadta volna a IsTrimmable
MSBuild tulajdonságot a szerelvény projektfájljához.
Jegyzet
Ha a IsTrimmable
MSBuild tulajdonság be van állítva egy szerelvényhez, ez felülbírálja a AssemblyMetadata("IsTrimmable", "True")
attribútumot. Ez lehetővé teszi, hogy a szerelvényt akkor is levágja, ha nem rendelkezik az attribútummal, vagy letiltsa az attribútummal rendelkező szerelvény levágását.
Elemzési figyelmeztetések mellőzése
Ha a vágóegység engedélyezve van, eltávolítja a statikusan nem elérhető IL-t. A dinamikus függőségeket létrehozó tükröződéseket vagy más mintákat használó alkalmazások emiatt megszakadhatnak. Az ilyen mintákra való figyelmeztetéshez, amikor egy szerelvényt vágásbiztosként jelöl meg, a könyvtár-szerzőknek a SuppressTrimAnalysisWarnings
MSBuild tulajdonságot false
értékre kell állítaniuk:
<PropertyGroup>
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
</PropertyGroup>
A vágáselemzési figyelmeztetések figyelmen kívül hagyása a teljes alkalmazásra vonatkozó figyelmeztetéseket be fogja vonni, beleértve a saját kódját, a könyvtár kódját és az SDK kódját is.
Részletes figyelmeztetések megjelenítése
A vágáselemzés legfeljebb egy figyelmeztetést eredményez minden olyan összeállításhoz, amely egy PackageReference
-ból származik, ami azt jelzi, hogy az összeállítás belső elemei nem kompatibilisek az optimalizálással. Kódtár-szerzőként, ha egy szerelvényt vágásbiztosként jelöl meg, az TrimmerSingleWarn
MSBuild tulajdonság false
beállításával engedélyezheti az egyes szerelvényekre vonatkozó figyelmeztetéseket:
<PropertyGroup>
<TrimmerSingleWarn>false</TrimmerSingleWarn>
</PropertyGroup>
Ez a beállítás az összes részletes figyelmeztetést megjeleníti ahelyett, hogy szerelvényenként egyetlen figyelmeztetésre összecsukja őket.