8.在XamarinAndroid上进一步控制包的大小

一身转战三千里,一剑曾当百万师。这篇文章主要讲述8.在XamarinAndroid上进一步控制包的大小相关的知识,希望能为你提供帮助。
在android上链接 
Xamarin.Android应用程序使用链接器来减小应用程序的大小。链接器使用应用程序的静态分析来确定哪些程序集、类型、成员被实际使用。链接器的行为就像一个GC,不断寻找被引用的程序集,类型和成员,直到整个引用的程序集,类型和成员都被找到。没被引用到的类型和程序集都被抛弃掉。
例如,Hello, Android  示例:

组态 1.2.0大小 4.0.1大小
无链接发布: 14.0 MB 16.0 MB
通过链接发布: 4.2 MB 2.9 MB
通过链接器处理后的尺寸在1.2.0版本中相当于原来的30%,在4.0.1版本中就只相当于原来的18%。效果非常好啊
控制
链接器基于静态分析。因此,依赖运行时环境的代码都不会被检测到(比如反射,动态生成对象等等都无法被链接器检测到):
// 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)); } }


链接器行为控制链接器的主要机制是“  项目选项”对话框中的链接器行为(在Visual Studio中)下拉列表。有三个选项:
  1. 不要链接(在Visual Studio中
  2. 链接SDK程序集(仅限Sdk程序集
  3. 链接所有程序集(Sdk和用户程序集
8.在XamarinAndroid上进一步控制包的大小

文章图片

 
在没有链接选项将禁用链接器;   上面的“无链接发布”应用程序大小就是这样的。这种方法对于解决运行时故障很有用,以查看链接器是否做得对。通常不建议在生产版本中使用此设置。
该链接SDK组件选项仅链接  来与Xamarin.Android组件。所有其他程序集(如您的代码)不链接。
该链接的所有组件的选择链路上的所有组件,这意味着你的代码如果没有被静态引用则会被删除。
上面的示例代码可以成功使用“不链接链接SDK程序集”链接选项。但选择“  链接所有程序集”选项将会失败,并生成以下错误:
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)


保留代码链接器有时会删除掉你本来要保留的代码。例如:
  • 您可能有通过动态反射调用的代码  System.Reflection.MemberInfo.Invoke
  • 如果动态实例化类型,则可能需要保留类型的默认构造函数。
  • 如果使用XML序列化,则可能需要保留类型的属性。
在这些情况下,您可以使用  Android.Runtime.Preserve  属性用来标记没有被静态引用,但是你的应用程序仍然所需要的成员。您可以将此属性应用于类型的每个成员或类型本身。
在下面的例子中,这个属性用来保存Example类的构造函数:

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


 
如果要保留整个类型,则可以使用以下属性语法:
[Android.Runtime.Preserve (AllMembers = true)]

 
例如,在下面的代码片段中,整个Example类都被保留用于XML序列化:

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


 
有时候你想保留某些成员,但是只有保留了包含的类型。在这些情况下,请使用以下属性语法:
[Android.Runtime.Preserve (Conditional = true)]

 
如果您不想依赖Xamarin库(例如,您正在构建一个跨平台的可移植类库(PCL)),你仍然可以使用该Android.Runtime.Preserve  属性。为此,请在Android.Runtime名称空间内声明一个PreserveAttribute类,  如下所示:

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


 
错误标识如果不能使用[Preserve]属性,通常需要提供一段预处理指令,以便链接器相信这个类型被使用并保留这个代码块。要使用这个技术我们可以这样做:
[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// ... }

 
linkskip可以指定一组用户提供的程序集不被链接处理(以保留整个程序集),同时允许使用AndroidLinkSkip MSBuild属性通过链接SDK程序集行为跳过其他用户程序集:

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


 
链接说明该生成操作可在其中可以包含一个文件中使用  自定义连接配置文件定义需要保留的私有或者内部成员。

 
自定义属性链接程序集时,将从所有成员中删除以下自定义属性类型:
  • System.ObsoleteAttribute
  • System.MonoDocumentationNoteAttribute
  • System.MonoExtensionAttribute
  • System.MonoInternalNoteAttribute
  • System.MonoLimitationAttribute
  • System.MonoNotSupportedAttribute
  • System.MonoTODOAttribute
  • System.Xml.MonoFIXAttribute
【8.在XamarinAndroid上进一步控制包的大小】链接程序集时,下列自定义属性类型将从发布版本中的所有成员中删除:
  • System.Diagnostics.DebuggableAttribute
  • System.Diagnostics.DebuggerBrowsableAttribute
  • System.Diagnostics.DebuggerDisplayAttribute
  • System.Diagnostics.DebuggerHiddenAttribute
  • System.Diagnostics.DebuggerNonUserCodeAttribute
  • System.Diagnostics.DebuggerStepperBoundaryAttribute
  • System.Diagnostics.DebuggerStepThroughAttribute
  • System.Diagnostics.DebuggerTypeProxyAttribute
  • System.Diagnostics.DebuggerVisualizerAttribute

    推荐阅读