Propojení na AndroiduLinking on Android

Aplikace Xamarin. Android používají linker ke zmenšování velikosti aplikace.Xamarin.Android applications use a linker to reduce the size of the application. Linker používá statickou analýzu vaší aplikace k určení, která sestavení se skutečně používají, které typy se skutečně používají a které členy jsou skutečně používány.The linker employes static analysis of your application to determine which assemblies are actually used, which types are actually used, and which members are actually used. Linker se pak chová jako systém uvolňování pamětia nepřetržitě hledá sestavení, typy a členy, na které se odkazuje, dokud nebude nalezen celý uzávěr odkazovaných sestavení, typů a členů.The linker then behaves like a garbage collector, continually looking for the assemblies, types, and members that are referenced until the entire closure of referenced assemblies, types, and members is found. Vše mimo tento uzávěr je pak zahozeno.Then everything outside of this closure is discarded.

Příklad: Hello, Android Sample:For example, the Hello, Android sample:

KonfiguraceConfiguration velikost 1.2.01.2.0 Size velikost 4.0.14.0.1 Size
Vydávat bez propojení:Release without Linking: 14,0 MB14.0 MB 16,0 MB16.0 MB
Vydaná verze s propojením:Release with Linking: 4,2 MB4.2 MB 2,9 MB2.9 MB

Výsledkem propojování výsledků balíčku je 30% velikost původního (nepřipojeného) balíčku v 1.2.0 a 18% nepřipojeného balíčku v 4.0.1.Linking results in a package that is 30% the size of the original (unlinked) package in 1.2.0, and 18% of the unlinked package in 4.0.1.

ŘízeníControl

Propojení je založeno na statické analýze.Linking is based on static analysis. V důsledku toho se nezjistí cokoli, co závisí na běhovém prostředí:Consequently, anything that depends upon the runtime environment won't be detected:

// To play along at home, Example must be in a different assembly from MyActivity.
public class Example {
    // Compiler provides default constructor...
}

[Activity (Label="Linker Example", MainLauncher=true)]
public class MyActivity {
    protected override void OnCreate (Bundle bundle)
    {
        base.OnCreate (bundle);

        // Will this work?
        var o = Activator.CreateInstance (typeof (ExampleLibrary.Example));
    }
}

Chování linkeruLinker Behavior

Primárním mechanismem pro řízení linkeru je chování linkeru (propojování v sadě Visual Studio) v dialogovém okně Možnosti projektu .The primary mechanism for controlling the linker is the Linker Behavior (Linking in Visual Studio) drop-down within the Project Options dialog box. Existují tři možnosti:There are three options:

  1. Neodkazovat (žádné v aplikaci Visual Studio)Don't Link (None in Visual Studio)
  2. Propojit sestavení sady SDK (pouze sestavení sady SDK)Link SDK Assemblies (Sdk Assemblies Only)
  3. Propojit všechna sestavení (sestavení sady SDK a uživatelských sestavení)Link All Assemblies (Sdk and User Assemblies)

Možnost Neodkazování vypne linker; Příklad výše uvedeného chování je uveden v části "vydání bez propojení" velikosti aplikace.The Don't Link option turns off the linker; the above "Release without Linking" application size example used this behavior. To je užitečné při řešení potíží s chybami modulu runtime, aby bylo možné zjistit, zda je linker zodpovědný.This is useful for troubleshooting runtime failures, to see if the linker is responsible. Toto nastavení se obvykle nedoporučuje pro produkční sestavení.This setting is not usually recommended for production builds.

Možnost vazby sestavení sady SDK se odkazuje jenom na sestavení, která se dodávají s Xamarin. Androidem.The Link SDK Assemblies option only links assemblies that come with Xamarin.Android. Všechna ostatní sestavení (například váš kód) nejsou propojena.All other assemblies (such as your code) are not linked.

Možnost propojit všechna sestavení propojuje všechna sestavení, což znamená, že váš kód může být také odstraněn, pokud nejsou k dispozici žádné statické odkazy.The Link All Assemblies option links all assemblies, which means your code may also be removed if there are no static references.

Výše uvedený příklad bude pracovat s možnostmi sestavení nepropojit a propojit sadu SDK a selže s chováním propojení všech sestavení a generuje následující chybu:The above example will work with the Don't Link and Link SDK Assemblies options, and will fail with the Link All Assemblies behavior, generating the following error:

E/mono    (17755): [0xafd4d440:] EXCEPTION handling: System.MissingMethodException: Default constructor not found for type ExampleLibrary.Example.
I/MonoDroid(17755): UNHANDLED EXCEPTION: System.MissingMethodException: Default constructor not found for type ExampleLibrary.Example.
I/MonoDroid(17755): at System.Activator.CreateInstance (System.Type,bool) <0x00180>
I/MonoDroid(17755): at System.Activator.CreateInstance (System.Type) <0x00017>
I/MonoDroid(17755): at LinkerScratch2.Activity1.OnCreate (Android.OS.Bundle) <0x00027>
I/MonoDroid(17755): at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (intptr,intptr,intptr) <0x00057>
I/MonoDroid(17755): at (wrapper dynamic-method) object.95bb4fbe-bef8-4e5b-8e99-ca83a5d7a124 (intptr,intptr,intptr) <0x00033>
E/mono    (17755): [0xafd4d440:] EXCEPTION handling: System.MissingMethodException: Default constructor not found for type ExampleLibrary.Example.
E/mono    (17755):
E/mono    (17755): Unhandled Exception: System.MissingMethodException: Default constructor not found for type ExampleLibrary.Example.
E/mono    (17755):   at System.Activator.CreateInstance (System.Type type, Boolean nonPublic) [0x00000] in <filename unknown>:0
E/mono    (17755):   at System.Activator.CreateInstance (System.Type type) [0x00000] in <filename unknown>:0
E/mono    (17755):   at LinkerScratch2.Activity1.OnCreate (Android.OS.Bundle bundle) [0x00000] in <filename unknown>:0
E/mono    (17755):   at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState) [0x00000] in <filename unknown>:0
E/mono    (17755):   at (wrapper dynamic-method) object:95bb4fbe-bef8-4e5b-8e99-ca83a5d7a124 (intptr,intptr,intptr)

Zachování kóduPreserving Code

Linker bude někdy odebírat kód, který chcete zachovat.The linker will sometimes remove code that you want to preserve. Příklad:For example:

  • Je možné, že budete mít kód, který dynamicky voláte prostřednictvím System.Reflection.MemberInfo.Invoke .You might have code that you call dynamically via System.Reflection.MemberInfo.Invoke.

  • Pokud vytváříte instanci typů dynamicky, můžete chtít zachovat výchozí konstruktor vašich typů.If you instantiate types dynamically, you may want to preserve the default constructor of your types.

  • Pokud používáte serializaci XML, je vhodné zachovat vlastnosti vašich typů.If you use XML serialization, you may want to preserve the properties of your types.

V těchto případech můžete použít atribut Android. Runtime. Preserve .In these cases, you can use the Android.Runtime.Preserve attribute. Každý člen, který není staticky propojen aplikací, je předmětem odebrání, takže tento atribut lze použít k označení členů, kteří nejsou staticky odkazováni, ale jsou stále vyžadovány vaší aplikací.Every member that is not statically linked by the application is subject to be removed, so this attribute can be used to mark members that are not statically referenced but are still needed by your application. Tento atribut lze použít pro každého člena typu nebo pro samotný typ.You can apply this attribute to every member of a type, or to the type itself.

V následujícím příkladu je tento atribut použit k zachování konstruktoru Example třídy:In the following example, this attribute is used to preserve the constructor of the Example class:

public class Example
{
    [Android.Runtime.Preserve]
    public Example ()
    {
    }
}

Pokud chcete zachovat celý typ, můžete použít následující syntaxi atributu:If you want to preserve the entire type, you can use the following attribute syntax:

[Android.Runtime.Preserve (AllMembers = true)]

Například v následujícím fragmentu kódu Example je celá třída zachovaná pro serializaci XML:For example, in the following code fragment the entire Example class is preserved for XML serialization:

[Android.Runtime.Preserve (AllMembers = true)]
class Example
{
    // Compiler provides default constructor...
}

Někdy je vhodné zachovat určité členy, ale pouze v případě, že byl zachován nadřazený typ.Sometimes you want to preserve certain members, but only if the containing type was preserved. V těchto případech použijte následující syntaxi atributu:In those cases, use the following attribute syntax:

[Android.Runtime.Preserve (Conditional = true)]

Pokud nechcete pořídit knihovny Xamarin – , například vytváříte přenositelné knihovny tříd (PCL) pro různé platformy, – můžete přesto použít Android.Runtime.Preserve atribut.If you do not want to take a dependency on the Xamarin libraries – for example, you are building a cross platform portable class library (PCL) – you can still use the Android.Runtime.Preserve attribute. Provedete to tak, že deklarujete PreserveAttribute třídu v rámci Android.Runtime oboru názvů takto:To do this, declare a PreserveAttribute class within the Android.Runtime namespace like this:

namespace Android.Runtime
{
    public sealed class PreserveAttribute : System.Attribute
    {
        public bool AllMembers;
        public bool Conditional;
    }
}

Ve výše uvedených příkladech Preserve je atribut deklarován v Android.Runtime oboru názvů; Nicméně můžete použít Preserve atribut v jakémkoli oboru názvů, protože linker vyhledá tento atribut podle názvu typu.In the above examples, the Preserve attribute is declared in the Android.Runtime namespace; however, you can use the Preserve attribute in any namespace because the linker looks up this attribute by type name.

falseflagfalseflag

Pokud atribut [Preserve] nelze použít, je často užitečné poskytnout blok kódu, aby linker byl přesvědčen, že typ je použit, a přitom brání spuštění bloku kódu za běhu.If the [Preserve] attribute can't be used, it is often useful to provide a block of code so that the linker believes that the type is used, while preventing the block of code from being executed at runtime. K použití této techniky bychom mohli provádět tyto akce:To make use of this technique, we could do:

[Activity (Label="Linker Example", MainLauncher=true)]
class MyActivity {

#pragma warning disable 0219, 0649
    static bool falseflag = false;
    static MyActivity ()
    {
        if (falseflag) {
            var ignore = new Example ();
        }
    }
#pragma warning restore 0219, 0649

    // ...
}

linkskiplinkskip

Je možné určit, že sada uživatelsky dodaných sestavení by neměla být vůbec propojena, zatímco povolení jiných uživatelských sestavení bude přeskočeno pomocí chování sestavení sady SDK pomocí vlastnosti AndroidLinkSkip MSBuild:It is possible to specify that a set of user-provided assemblies should not be linked at all, while allowing other user assemblies to be skipped with the Link SDK Assemblies behavior by using the AndroidLinkSkip MSBuild property:

<PropertyGroup>
    <AndroidLinkSkip>Assembly1;Assembly2</AndroidLinkSkip>
</PropertyGroup>

LinkDescriptionLinkDescription

@(LinkDescription) Akci sestavení lze použít pro soubory, které mohou obsahovat vlastní konfigurační soubor linkeru.The @(LinkDescription) Build action may be used on files which can contain a Custom linker configuration file. souborů.file. Vlastní konfigurační soubory linkeru můžou být nutné k zachování internal nebo private členům, kteří musí být zachováni.Custom linker configuration files may be required to preserve internal or private members that need to be preserved.

Vlastní atributyCustom Attributes

Pokud je sestavení propojeno, následující typy vlastních atributů budou odebrány ze všech členů:When an assembly is linked, the following custom attribute types will be removed from all members:

  • System. ObsoleteAttributeSystem.ObsoleteAttribute
  • System. MonoDocumentationNoteAttributeSystem.MonoDocumentationNoteAttribute
  • System. MonoExtensionAttributeSystem.MonoExtensionAttribute
  • System. MonoInternalNoteAttributeSystem.MonoInternalNoteAttribute
  • System. MonoLimitationAttributeSystem.MonoLimitationAttribute
  • System. MonoNotSupportedAttributeSystem.MonoNotSupportedAttribute
  • System. MonoTODOAttributeSystem.MonoTODOAttribute
  • System.Xml. MonoFIXAttributeSystem.Xml.MonoFIXAttribute

Když je sestavení propojeno, následující typy vlastních atributů budou odebrány ze všech členů v sestaveních vydaných verzí:When an assembly is linked, the following custom attribute types will be removed from all members in Release builds:

  • System. Diagnostics. DebuggableAttributeSystem.Diagnostics.DebuggableAttribute
  • System. Diagnostics. DebuggerBrowsableAttributeSystem.Diagnostics.DebuggerBrowsableAttribute
  • System. Diagnostics. DebuggerDisplayAttribute –System.Diagnostics.DebuggerDisplayAttribute
  • System. Diagnostics. DebuggerHiddenAttribute neovlivňujeSystem.Diagnostics.DebuggerHiddenAttribute
  • System. Diagnostics. DebuggerNonUserCodeAttributeSystem.Diagnostics.DebuggerNonUserCodeAttribute
  • System. Diagnostics. DebuggerStepperBoundaryAttributeSystem.Diagnostics.DebuggerStepperBoundaryAttribute
  • System. Diagnostics. DebuggerStepThroughAttributeSystem.Diagnostics.DebuggerStepThroughAttribute
  • System. Diagnostics. DebuggerTypeProxyAttribute –System.Diagnostics.DebuggerTypeProxyAttribute
  • System. Diagnostics. DebuggerVisualizerAttributeSystem.Diagnostics.DebuggerVisualizerAttribute