做好应用程序发布准备

应用程序经编码和测试后,必须准备一个包进行分发。 准备此包的第一个任务是生成供发布的应用程序,其中主要涉及到设置应用程序的一些属性。

使用以下步骤生成供发布的应用:

  • 指定应用程序图标 - 应为每个 Xamarin.Android 应用程序指定一个应用程序图标。 虽然在技术层面并不需要这么做;但是,某些应用商店(例如 Google Play)对此提出了要求。

  • 应用程序版本控制 - 在此步骤中,需要初始化或更新版本信息。 这对应用程序将来的更新以及确保用户知道安装的应用程序版本非常重要。

  • 压缩 APK - 通过托管代码上的 Xamarin.Android 链接器和 Java 字节码上的 ProGuard,可大幅压缩最终 APK。

  • 保护应用程序 - 通过禁用调试、将托管代码模糊处理、添加防调试和防篡改并使用本机编译,阻止用户或攻击者对应用程序进行调试、篡改或反向工程。

  • 设置打包属性 - 打包属性控制了 Android 应用程序包 (APK) 的创建。 此步骤会优化 APK,保护其资产并根据需要模块化打包。 此外,你还可以为用户提供针对其设备进行了优化的 Android 应用程序包。

  • 编译 - 此步骤会编译代码和资产,以确认按发布模式生成。

  • 存档以供发布 - 此步骤会生成应用,并将其放置在存档中以供签名和发布。

下面详细说明了上述各步骤。

指定应用程序图标

强烈建议每个 Xamarin.Android 应用程序都指定一个应用程序图标。 某些应用程序市场将不允许发布没有图标的 Android 应用程序。 Application 特性的 Icon 属性用于指定 Xamarin.Android 项目的应用程序图标。

在 Visual Studio 2017 及更高版本中,可通过项目“属性”的“Android 清单”部分指定应用程序图标,如以下屏幕截图所示 :

Set the application icon

在这些示例中,@drawable/icon 指位于 Resources/drawable/icon.png(请注意,.png 扩展名不包含在资源名称中)中的一个图标文件。 另外,此属性也可在文件 Properties\AssemblyInfo.cs 中声明,如以下示例代码片段所示:

[assembly: Application(Icon = "@drawable/icon")]

通常情况下,using Android.AppAssemblyInfo.csApplication 属性的命名空间为 Android.App)顶部声明;不过,可能需要添加此 using 语句(如果尚不存在)。

应用程序版本控制

对于 Android 应用程序维护和分发而言,版本控制很重要。 如果没有版本控制,则很难确定应用程序是否应更新或如何更新。 为了辅助版本控制,Android 可识别两种不同类型的信息:

  • 版本号 - 一个整数值(供 Android 和应用程序内部使用),它表示应用程的版本。 对大多数应用程序而言,此值的初始设置为 1,之后随每个内部版本递增。 此值与版本名称属性(见下文)没有关系或关联。 应用程序和发布服务不应向用户显示此值。 此值在 AndroidManifest.xml 文件中存储为 android:versionCode

  • 版本名 - 一个字符串,仅用于向用户传递应用程序(安装在特定设备上)的版本相关信息。 版本名称将向用户显示,或在 Google Play 中显示。 此字符串不供 Android 内部使用。 版本名称可以是任何字符串值,它能帮助用户了解其设备上安装的版本。 此值在 AndroidManifest.xml 文件中存储为 android:versionName

在 Visual Studio 中,可在项目“属性”的“Android 清单”部分设置这些值,如以下屏幕截图所示:

Set the version number

缩小 APK

可通过结合使用 Xamarin.Android 链接器(删除不必要的托管代码)和 Android SDK 中的 ProGuard 工具(删除未使用的 Java 字节码)缩小 Xamarin.Android APK。 生成过程首先使用 Xamarin.Android 链接器以托管代码 (C#) 级别优化应用,然后使用 ProGuard(如已启用)以 Java 字节码级别优化 APK。

配置链接器

发布模式会关闭共享运行时并打开链接,使应用程序只提供运行时需要的 Xamarin.Android 部分。 Xamarin.Android 中的链接器使用静态分析来确定 Xamarin.Android 应用程序所使用或引用的程序集、类型和类型成员。 然后,链接器将放弃所有未使用(或引用)的程序集、类型和成员。 这可显著减小包的大小。 例如,HelloWorld 示例,其 APK 的最终大小减少了 83%:

  • 配置:无 - Xamarin.Android 4.2.5 大小 = 17.4 MB。

  • 配置:仅 SDK 程序集 - Xamarin.Android 4.2.5 大小 = 3.0 MB。

通过项目“属性”的“Android 选项”部分设置链接器选项:

Linker options

“链接”下拉菜单提供以下选项,用于控制链接器:

  • - 这会关闭链接器;不会执行任何链接。

  • 仅 SDK 程序集 - 这仅链接 Xamarin.Android 所需的程序集。 不会链接其他程序集。

  • SDK 和用户程序集 - 这会链接应用程序所需的所有程序集,而不是仅链接 Xamarin.Android 所需的程序集。

链接可能产生一些意外的副作用,因此必须在物理设备上的发布模式下重新测试应用程序。

ProGuard

ProGuard 是一种链接和模糊处理 Java 代码的 Android SDK 工具。 ProGuard 通常用于创建小型应用程序,工作原理是减少 APK 中包含的大型库的内存占用。 ProGuard 将删除未使用的 Java 字节码,使生成的应用变得更小。 例如,在小型 Xamarin.Android 应用中使用 ProGuard 通常可减少约 24% 的大小;在具有多个库依赖关系的大型应用中使用 ProGuard 通常可更大幅度地缩减大小。

ProGuard 不是 Xamarin.Android 链接器的替代工具。 Xamarin.Android 链接器链接托管代码,而 ProGuard 链接 Java 字节码。 生成过程首先在应用中使用 Xamarin.Android 链接器优化托管的 (C#) 代码,然后在 Java 字节码级别使用 ProGuard(若已启用)优化 APK。

选择“启用 ProGuard”P时,Xamarin.Android 将在生成的 APK 中运行 ProGuard 工具。 ProGuard 配置文件由 ProGuard 在生成时生成和使用。 Xamarin.Android 还支持自定义 ProguardConfiguration 生成操作。 可以将自定义 ProGuard 配置文件添加到项目中,右键单击并选中该文件作为生成操作,如此示例中所示:

默认情况下,禁用 ProGuard。 仅在项目设置为“发布”模式时才能使用“启用 ProGuard”选项。 除非选中“启用 ProGuard”,否则会忽略所有 ProGuard 生成操作。 Xamarin.Android ProGuard 配置不会模糊处理 APK,且不能启用模糊处理,即使处理自定义配置文件也不例外。 如果想要模糊处理,请参阅使用 Dotfuscator 保护应用程序

有关 ProGuard 工具用法的详细信息,请参阅 ProGuard

保护应用程序

禁用调试

在 Android 应用程序开发期间,将使用 Java 调试线路协议 (JDWP) 执行调试。 这是一种技术,它允许 adb 等工具出于调试目的与 JVM 通信。 默认对 Xamarin.Android 应用程序的调试版本启用 JDWP。 虽然 JDWP 在开发过程中很重要,但它会对已发布的应用程序造成安全问题。

重要

请始终禁用已发布应用程序中的调试状态,因为如果不禁用此状态,则可能(通过 JDWP)获得 Java 进程的完全访问权限并在应用程序的上下文中执行任意代码。

Android 清单包含 android:debuggable 属性,该属性控制是否可以调试应用程序。 将 android:debuggable 属性设置为 false 被视为一种很好的做法。 执行此操作最简单的方法是在 AssemblyInfo.cs 中添加条件编译语句:

#if DEBUG
[assembly: Application(Debuggable=true)]
#else
[assembly: Application(Debuggable=false)]
#endif

注意,调试版本会自动设置某些权限以简化调试(如 InternetReadExternalStorage)。 但是,发布版本只使用显式配置的权限。 若发现切换到发布版本会导致应用失去可在调试版本中使用的权限,请验证是否已在“所需权限”列表中显式启用了此权限,如权限中所述。

使用 Dotfuscator 保护应用程序

即使已禁用调试,攻击者仍可能重新打包应用程序,从而添加或删除配置选项或权限。 这可使他们对应用程序进行反向工程、调试或篡改。 Dotfuscator Community Edition (CE) 可用于混淆托管代码,并在生成时向 Xamarin.Android 应用插入运行时安全状态检测代码,对应用是否在根设备上运行进行检测和响应。

Visual Studio 2017 附带了 Dotfuscator CE。 若要使用 Dotfuscator,请单击“工具”>“PreEmptive 保护”-“Dotfuscator”。

若要配置 Dotfuscator CE,请参阅 Using Dotfuscator Community Edition with Xamarin(结合使用 Dotfuscator Community Edition 和 Xamarin)。 完成配置后,Dotfuscator CE 将自动保护创建的每个生成。

将程序集捆绑到本机代码

此选项启用时,程序集会捆绑到本机共享库中。 这样便可以对程序集进行压缩,减小 .apk 文件的大小。 程序集压缩还提供最小形式的模糊处理;此类模糊处理不应作为依据。

此选项需要 Enterprise 许可证,仅当“使用快速部署”禁用时才可用。 “将程序集捆绑到本机代码”在默认情况下处于禁用状态。

请注意,“捆绑到本机代码”选项执行不意味着程序集会编译到本机代码中。 无法使用 AOT 编译将程序集编译为本机代码。

AOT 编译

打包属性页上的AOT 编译选项支持预先编译程序集。 启用此选项后,通过在运行时之前预编译程序集可将实时 (JIT) 启动开销降到最低。 生成的本机代码包括在 APK 以及未编译程序集中。 这可缩短应用程序启动时间,但代价是 APK 大小会变得稍大。

“AOT 编译”选项要求使用 Enterprise 或更高版本的许可证。 仅在项目配置为发布模式时,才可使用“AOT 编译”,并且该选项默认处于禁用状态。 有关 AOT 编译的详细信息,请参阅 AOT

LLVM 优化编译器

LLVM 优化编译器会创建更小更快速的编译代码,并将 AOT 编译的程序集转换为本机代码,但生成时间会变缓慢。 默认情况下,LLVM 编译器处于禁用状态。 要使用 LLVM 编译器,必须首先启用“AOT 编译”选项(在打包属性页面上)。

注意

“LLVM 优化编译器”选项需要企业许可证。

设置打包属性

可在项目“属性”的“Android 选项”部分设置打包属性,如以下屏幕截图所示:

Packaging Properties

其中许多属性(例如“使用共享运行时”和“使用快速部署”)专用于调试模式。 但是,在发布模式下配置应用程序时,还需要进行其他设置,这些设置用于确定如何针对大小和执行速度优化应用、如何防止篡改应用,以及如何打包应用以支持不同的体系结构和大小限制。

指定支持的体系结构

准备 Xamarin.Android 应用进行发布时,必须指定支持的 CPU 体系结构。 单个 APK 可包含计算机代码,以支持多个不同的体系结构。 请参阅 CPU 体系结构,深入了解如何支持多个 CPU 体系结构。

每个选定 ABI 生成一个包 (.APK)

启用此选项后,会为每个支持的 ABI(在“高级”选项卡上进行选择,如 CPU 体系结构中所述)分别创建一个 APK,而不是为所有支持的 ABI 创建单个大型 APK。 仅在项目配置为用于发布模式时,才可使用此选项,并且其默认处于禁用状态。

Multi-Dex

如果启用“启用 Multi-Dex”选项,Android SDK 工具将用于绕过 .dex 文件格式的 65K 方法限制。 65K 方法限制基于应用引用的 Java 方法数(包括应用依赖的任何库中的方法数),它不基于源代码中写入的方法数。 如果应用程序只定义了几个方法,却使用了多个方法或大型库,则可能超出 65K 限制。

应用可能未使用每个引用库中的每个方法;因此,ProGuard(见上文)等工具可能会将未使用的方法从代码中删除。 最佳做法是仅在绝对必要时启用“启用 Multi-Dex”,也就是说,即使使用 ProGuard,应用引用的 Java 方法仍然超过 65K。

若要深入了解 Multi-Dex,请参阅配置超出 64K 方法的应用

Android 应用程序包

应用程序包不同于 APK,因为它们不能直接部署到设备。 相反,它是一种旨在与所有已编译代码和资源一起上传的格式。 上传已签名的应用程序包后,Google Play 将获得构建和签署应用程序 APK 所需的一切内容,并使用动态交付功能将它们提供给客户。

要启用对 Android 应用程序包的支持,你需要在 Android 项目选项中选择 Android 包格式属性的 bundle 值。 执行此操作之前,请确保将项目更改为 Release 配置,因为应用程序包仅用于发布包。

现在,你可以按照存档流程生成应用程序包。 这会为应用程序生成应用程序包。

有关 Android 应用程序包的详细信息,请参阅 Android 应用程序包

Compile

完成上述所有步骤后,应用即可用于编译。 选择“生成”>“重新生成解决方案”以验证其是否在发布模式下成功生成。 请注意,此步骤尚不会产生 APK。

对应用包进行签名中更详细地讨论了打包和签名。

存档以供发布

若要开始发布过程,请在解决方案资源管理器中右键单击项目,然后选择“存档...”上下文菜单项:

Archive app

选择“存档...”选项将启动存档管理器并开始应用程序包的存档过程,如以下屏幕截图所示:

Archive Manager

另一种创建存档的方法是:在解决方案资源管理器中,右键单击“解决方案”,然后选择“全部存档...”,这会生成解决方案并存档可生成存档的所有 Xamarin 项目:

Archive All

“存档”和“全部存档”均会自动启动存档管理器。 若要直接启动存档管理器,请单击“工具”>“存档管理器...”菜单项:

Launch Archive Manager

右键单击“解决方案”节点并选择“查看存档”可随时查看该解决方案的存档:

View Archives

存档管理器

存档管理器由“解决方案列表”窗格、“存档列表”和“详细信息面板”组成:

Archive Manager Panes

“解决方案列表”将显示所有解决方案,其中至少有一个项目已存档。 “解决方案列表”包括以下各部分:

  • 当前解决方案 - 显示当前的解决方案。 请注意,如果当前解决方案不含现有存档,此区域可能为空。
  • 全部存档 - 显示包含存档的所有解决方案。
  • “搜索”文本框(顶部)- 根据在文本框中输入的搜索字符串筛选“全部存档”列表中列出的解决方案。

“存档列表”显示有关所选解决方案的所有存档的列表。 “存档列表”包括以下各部分:

  • 所选解决方案名称 - 显示解决方案列表中所选解决方案的名称。 “存档列表”中显示的所有信息均与此选定的解决方案有关。
  • 平台筛选器 - 此字段可按平台类型(如 iOS 或 Android)筛选存档。
  • 存档项目 - 选定解决方案的存档列表。 此列表中的每个项均包括项目名称、创建日期和平台。 还可以显示其他信息,例如存档或发布项目时的进度。

“详细信息面板”显示有关每个存档的其他信息。 用户还可以从此面板启动分发工作流或打开创建分发的文件夹。 “生成注释”部分可将生成注释包括在存档中。

分布

准备好发布存档版应用程序后,请在“存档管理器”中选择该存档,然后单击“分发...”按钮:

Distribute button

“分发通道”对话框包括以下方面的信息:应用、分发工作流进度指示以及分发渠道选项。 首次运行时,提供两个选项:

Select Distribution Channel

可选择以下分发通道之一:

  • Ad-Hoc - 将已签名的 APK 保存到磁盘,以将其旁加载到 Android 设备。 继续查看对应用包进行签名,了解如何创建 Android 签名标识、为 Android 应用程序创建新的签名证书以及将“临时”版本的应用发布到磁盘。 这是为测试创建 APK 的好方法。

  • Google Play - 将已签名的 APK 发布到 Google Play。 继续查看发布到 Google Play,了解如何对 APK 进行签名并将其发布到 Google Play 商店。