在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和用户程序集

没有链接选项将禁用链接器; 上面的“无链接发布”应用程序大小就是这样的。这种方法对于解决运行时故障很有用,以查看链接器是否做得对。通常不建议在生产版本中使用此设置。

链接SDK组件选项仅链接 来与Xamarin.Android组件。所有其他程序集(如您的代码)不链接。

链接的所有组件的选择链路上的所有组件,这意味着你的代码如果没有被静态引用则会被删除。

上面的示例代码可以成功使用“不链接链接SDK程序集”链接选项。但选择“ 链接所有程序集”选项将会失败,并生成以下错误:

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

链接程序集时,下列自定义属性类型将从发布版本中的所有成员中删除:

  • 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

8.在XamarinAndroid上进一步控制包的大小的更多相关文章

  1. 为 .net 生态贡献力量——制作并上传 nuget 包(内有独家彩蛋)

    前言 nuget 是 .net 的常用包管理器,目前已经内置到 Visual Studio 2012 以后的版本.大多数 .net 包都托管在 nuget.org,包括 .net core 框架基础包 ...

  2. 如何在Windows系统上用抓包软件Wireshark截获iPhone等网络通讯数据

    http://www.jb51.net/os/windows/189090.html 今天给大家介绍一种如何在Windows操作系统上使用著名的抓包工具软件Wireshark来截获iPhone.iPa ...

  3. maven安装 maven上传jar包到库里面

    maven的安装与配置:http://pansanday.blog.163.com/blog/static/381662802012727103454743/ maven上传jar包到库里面: 将私有 ...

  4. 如何在 Android 手机上实现抓包?

    如何在 Android 手机上实现抓包? http://www.zhihu.com/question/20467503 我想知道某个应用究竟在数据提交到哪里,提交了什么.网上的教程太复杂,不想麻烦.有 ...

  5. (转)上传jar包到nexus私服

    场景:在使用私服Nexus时候经常需要上传jar包,但是对上传jar包的方式不是很熟悉,所以很有必要学习下. 1 通过网页上传 GAV Definition:选择GAV Parameters 输入JA ...

  6. Maven第四篇【私有仓库、上传jar包、引用私服jar包、上传本地项目到私服】

    搭建私有服务器 前面已经说过了,我们使用Maven的使用,如果需要导入相对应的jar包,Maven首先会在我们的本地仓库中寻找->私有仓库->中心仓库- 然而,我们的本地仓库常常没有想要的 ...

  7. 在pypi上发布python包详细教程

    使用Python编程中Python的包安装非常方便,一般都是可以pip来安装搞定:pip install <package name>,我们自己写的python也可以发布在pypi上,很简 ...

  8. Maven上传jar包到私服

    1.认证,在M2_HOME/conf/settings.xml配置用户名密码 <server> <id>releases</id> <username> ...

  9. maven上传jar包到nexus私服后的存放路径 以及 使用IDEA上传jar包的步骤

    maven上传jar包到nexus私服的方法,网上大神详解很多,那么上传后的jar包存放到哪里了呢? 在下使用nexus3.2.1版本,在本地搭建了私服,使用maven上传jar包.最后结果如下: 点 ...

随机推荐

  1. 进度条ProgressBar

    在本节中,作者只写出了进度条的各种样式,包括圆形.条形,还有自定义的条形,我想如果能让条形进度条走满后再继续从零开始,于是我加入了一个条件语句.作者的代码中需要学习的是handler在主线程和子线程中 ...

  2. noip第10课作业

    1.     统计不同类型字符出现次数 [问题描述] 输入一个字符串(假设长度不超过1000个字符),统计其中大写,小写,数字,其他字符出现的次数. [样例输入]Hello,what are you ...

  3. VC++ 定制应用程序的外观

    一.在窗口创建之前改变窗口的大小和标题 要改变应用程序窗口的大小可以通过在PreCreatWindowl函数中修改CREATSTRUCT结构体变量成员的值 BOOL CMainFrame::PreCr ...

  4. hdu 4004 最大值最小化

    http://acm.hdu.edu.cn/showproblem.php?pid=4004 一条线段长度为L,线段上有n个点,最多选取 m-1 个点,使得包括线段端点在内的相邻点之间的最大距离值最小 ...

  5. Ansible Ad-Hoc命令

    -a:传入模块的参数,不同的模块要传入的参数不同 -B SECOND:当任务放到后台执行异步任务,设置程序运行的超时时间,传入的是一个数值,单位秒 -C:测试该任务能否正常运行,不对被管理主机做出任何 ...

  6. const 用法全面总结

    C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,本人根据各方面查到的资料进行总结如下,期望对朋友们有所帮助. Const 是C++中常用的类型修饰符,常类型是指使用类 ...

  7. ASP.NET MVC ScriptBundle 不能加载.min.js文件

    比如我用 bundles.Add(new ScriptBundle("~/bundles/easyui").Include( "~/Content/easyui/jque ...

  8. 【AppCan 开发者】移动信息化随想

    现在的移动信息化,准确来说,是手机智能网络化.从08年到14年这6年时间里,手机发生翻天覆地的变化,成为移动设备智能中心,取得巨大成就,也成就一批公司,带动移动互联网的发展,引来众多人眼红热血投入.其 ...

  9. NVIC配置中的分组详解

    在配置优先级的时候,要注意一个很重要的问题,中断种类的数量. NVIC只可以配置 16 种 中断向量的优先级,也就是说,抢占优先级和响应优先 级的数量由一个 4 位的数字来决定, 把这个 4 位数字的 ...

  10. 编码CODING

    摘自(复制)于海燕博客: http://www.cnblogs.com/haiyan123/p/7230533.html 1.内存和硬盘都是用来存储的. CPU:速度快 硬盘:永久保存 2.文本编辑器 ...