4.4.3 Google 服务框架安装器 GSI 实现
为了解决用户手动安装 Google 服务框架所遇到的机型兼容性与资源查找等难题,开发了Google 服务框架安装器 GSI。
GSI 可以集成到任意 App 中,架构采用模块化的设计方式,集成方便、快捷。图 4-10 是GSI 整体框架。

从图 4-10 中,我们可以清晰地看到, GSI 主要由以下几个部分组成。
GSI SDK。
GSI 控制端。
Google 服务框架资源库。
上面这几个部分究竟起什么作用呢?下面就来详细地解释一下。1. GSI SDK因为 Google 服务框架最终是要安装到用户手机中的,所以我们需要一个安装器 APK 帮我们实现这一过程。 GSI SDK 将整个安装服务进行了设计和封装。集成 GSI 的应用只需要通过特定的 API 接口调用,就可以掌控整个 Google 服务框架的安装流程。同时, GSI SDK 还设计了适配各种机型情况的监听器,集成了 GSI 的 App 只需要监听对应的回调事件,就可以清楚获知整个流程的结果。2. GSI 控制端
在前面的章节中曾提到 Android 生态碎片化严重的特点,所以为了应对这些碎片化的机型与系统,我们需要有一个动态化的控制端,以不断应对 Android 生态圈出现的各种新机型与高版本系统的适配问题。
GSI 控制端就是为了解决上述问题而存在的。当 GSI SDK 发送请求到 GSI 控制端的时候,请求中会上报机型的各种详细数据。控制端根据已经收集与积累的数据进行相应的适配响应,返回用户所需要的 Google 服务框架资源。
GSI 控制端的独立性使 GSI 整体的服务可以随着 Android 系统的不断迭代发展而进行相应的更新,而集成了 GSI SDK 的 App 并不需要为此进行升级。
3. Google 服务框架资源库
由于各厂商对 Android 系统进行了大量的改造,所以适配一个厂商的 Google 服务框架资源并不能完全应用到另一个厂商的机型系统上。经过 GSI 不断地积累与完善资源体系,现在GSI 已经能适配市面上的大部分机型系统。
在前面的章节中我们已经详细地介绍了 GSI 的整个架构体系与功能,下面就来具体看看GSI 的实现流程。图 4-11 是 GSI 的整体实现流程。

首先,客户端发起请求查询机型与厂商的兼容与适配数据。查询的参数主要包括以下几个方面。
brand: 机型厂商品牌。
ROM: 机型 ROM 型号。
dpi: 机型屏幕 dpi 参数。
androidVersion: 机型 ROM 的编译版本号。
sdkVersion: Android 系统版本号。
isRoot: 设备是否已经取得 Root 权限。
经过 GSI 大量的数据收集与积累,现在已经整理出适配市面上大部分机型的方案。而某些机型由于厂商禁止等原因,无法安装 Google 服务框架,这一部分机型的适配情况大致如图 4-12所示。

第 5 章 Android 工程构建进阶
做 Android 移动开发,构建是最基本的工作之一,优秀的构建犹如一栋房子的骨骼框架,至关重要。本章将从工程构建基础、进阶和定制 3 方面来进行介绍。
5.1 工程构建基础
随着 Android 应用开发技术的成熟,开发者对开发效率和编译效率逐渐有了新的要求。其中, Android 应用的研发工具也从 Eclipse 转向 Android Studio,编译工程也从 Linux 系统 MM编译过渡到 Ant 编译,最后再到 Gradle 编译。
Gradle 编译器是 Google 官方推出的 Android 编译器,具有 Gradle DSL,可以轻易地实现Android 编译配置。接下来,我们就围绕 Gradle 编译器及 Android Studio 开发工具来讲解Android 工程的构建基础。
5.1.1 应用基本信息
Android 应用程序安装包是一个压缩成 Zip 包的 APK 文件,我们可以通过解压缩查看 APK的组成,如图 5-1 所示。
一个完整的 APK,应当包含以下目录和文件。
META-INF/:包含 CERT.SF 和 CERT.RSA 签名文件以及 MANIFEST.MF 清单文件。
assets/:包含使用 AssetManager 对象检索的应用资源。
res/:包含未编译到的资源 resources.arsc。
lib/:包含特定存在于处理器软件层的编译代码。该目录包含了每种平台的子目录,
如 armeabi、 armeabi-v7a、 arm64-v8a、 x86、 x86_64 和 mips。
resources.arsc:包含已编译的资源。该文件包含 res/values/目录所有配置中的 xml 内容。打包工具提取此 xml 内容,将其编译为二进制格式,并将内容归档。此内容包括语言字符串和样式,以及直接包含在 resources.arsc 文件中的内容路径,如布局文件和图像。
classes.dex:包含以 Dalvik/ART 虚拟机可理解的 dex 文件格式编译的类。
AndroidManifest.xml:包含核心 Android 清单文件。该文件列出了应用程序的名称、版本、访问权限和引用的库文件。该文件使用 Android 的二进制 xml 格式。

除了以上所述的文件,一个 APK 文件还需要具备包名、应用名、版本号、签名以及相关的运行权限等才能上架到应用商店中,进而被下载并安装到手机上。
5.1.2 编译过程
图 5-2 对上面的步骤以及每步用到的工具进行了细分,概括如下。
Java 编译器对工程本身的 Java 代码进行编译,这些 Java 代码有 3 个来源: App 的源码、由资源文件生成的 R 文件( AAPT 工具),以及由 aidl 文件生成的 Java 接口文件( AIDL 工具),产出为 class 文件。
class 文件和依赖的第三方库文件通过 dx 工具生成 Dalvik 虚拟机可执行的 dex 文件,可能有一个或多个,包含了所有的 class 信息,包括项目自身的 class 文件和依赖的 class 文件,产出为 dex 文件。
apkbuilder 工具将 dex 文件和编译后的资源文件生成未经签名对齐的 APK 文件。这里编译后的资源文件包括两部分,一部分是由 AAPT 编译产生的资源文件,另一部分是依赖的第三方库里的资源文件,产出为未经签名的 APK 文件。分别由 Jarsigner 和 zipalign 对 APK 文件进行
签名和对齐,然后生成最终的 APK 文件。总结:编译→dex→打包→签名和对齐。

图 5-2 是 Android 应用程序编译打包的主要过程,可以分为以下几个重要流程。
1.生成资源 R.java 文件
打包资源的工具是 AAPT( The Android Asset Packing Tool),位于 android-sdk/platformtools 目录下。在这个过程中,项目中的 AndroidManifest.xml 文件和布局文件 xml 都会被编译,然后生成相应的 R.java 文件。
2.将 aidl 文件生成 java 文件
这一过程中使用到的工具是 AIDL( Android Interface Definition Language),即 Android 接口描述语言,位于 android-sdk/platform-tools 目录下。 AIDL 工具先解析接口定义文件,然后生成相应的 Java 代码接口供程序调用。
3.编译 java 文件,生成 class 文件
项目中所有的 Java 代码,包括 R.java 和 aidl 文件,都会被 Java 编译器( javac)编译成class 文件,生成的 class 文件位于工程中的 bin/classes 目录下。
4.生成 dex 文件
dx工具(该工具是 Android中将 jar 包转换成 dex 格式二进制 jar 包的工具)生成可供 Android 系统 Dalvik 虚拟机执行的 classes.dex 文件,该工具位于 android-sdk/platform-tools 目录下。
任何第三方库和 class 文件都会被转换成 dex 文件。
dx 工具的主要工作是将 Java 字节码转换成 Dalvik 字节码、压缩常量池、消除冗余信息等。
5.打包 APK 文件
所有没被编译的资源(如 images 等)、编译过的资源和 dex 文件都会被 apkbuilder 工具打包到最终的 APK 文件中。
打包工具 apkbuilder 位于 android-sdk/tools 目录下。 apkbuilder 是一个脚本文件,实际调用的是 android-sdk/tools/lib/sdklib.jar 文件中的 com.android.sdklib.build.Apkbuilder-Main 类。
6.对 APK 文件进行签名
一旦 APK 文件生成,它必须被签名才能安装到设备上。
在开发过程中,主要会用到两种签名 keystore。一种是用于调试的 debug.keystore,在Eclipse 或者 Android Studio 中直接执行 run 命令后,跑在手机上使用的就是 debug.keystore;另一种是用于发布正式版本的 keystore。
7.文件对齐
如果你发布的 APK 是正式版的话,就必须对 APK 进行对齐处理,用到的工具是zipalign,它位于 android-sdk/tools 目录下。
对齐的主要过程是,将 APK 文件中的所有资源文件距离文件起始位置偏移 4 字节整数倍,这样通过内存映射访问 APK 文件时的速度会更快。
对齐可以减少运行时使用的内存。
5.2 工程构建进阶
工程构建进阶是对构建基础的深化,那么接下来将主要以多渠道打包构建来进行说明。
5.2.1 多渠道打包
多渠道打包是应用开发过程中经常遇到的情况。 Google 在开发 Gradle 编译工具的时候,就充分考虑了多渠道打包的情况。 Google 官方为开发者提供的 DSL 接口为 productFlavors,通
过配置 productFlavors 可以轻松实现多渠道打包。具体配置如下:
1. android {
2. ...
3. productFlavors {
4. flavor1 {
5. minSdkVersion 14
6. }
7. flavor2 {
8. minSdkVersion 14
9. }
10. ...
11. }
12. }
通过 productFlavors 配置,可以实现不同渠道之间的差异化打包,比如资源、版本号、应用名、 minSdk、签名等,凡是可以在 Android Studio 中配置的,都可以实现差异化打包。
如下代码实现了 DEMO 程序在豌豆荚和应用宝两个渠道中的打包逻辑,包括渠道号以及内部应用更新的逻辑都在不同渠道中实现了不同策略:
1. android {
2. ...
3. productFlavors {
4. wandoujia {
5. applicationId com.damo.wandouijaAndroid
6. buildConfigField "boolean", "AUTO_UPDATES", "true"
7. buildConfigField "String", "channel", "wandoujia"
8. }
9. yingyongbao {
10. applicationId com.damo.yingyongbao
11. buildConfigField "boolean", "AUTO_UPDATES", "false"
12. buildConfigField "String", "channel", "yingyongbao"
13. }
14. ...
15. }
16. }
虽然 productFlavors 多渠道配置打包简单、方便,可以最大程度上实现差异化,但是打包效率却不高。每一个 productFlavors 都必须单独打包,生成 APK、签名,耗时较长。
5.2.2 渠道信息批量写入
多渠道打包的另一种方式是应用程序对不同渠道只进行渠道号的区分,而没有其他不同区分。针对这种情况,我们可以采用批量写入的方法。
通过动态添加不同渠道的文件,应用程序对 APK 中的渠道文件读取渠道信息。通常的做法是往打完包的 APK 文件中动态添加 channel.txt 文件。
如图 5-3 所示,通过往 APK 中写入 channel.txt 文件,写入指定的渠道信息。

通过写入渠道文件的方式,可以方便地快速写入渠道信息。在我们开发完 APK 后,打包完 release 包,再通过动态添加的形式,批量写入渠道文件,写入后再对应用程序进行签名。
5.2.3 资源混淆
资源混淆 AndResGuard 是微信开源的一个帮助你缩小 APK 包体大小的工具,它的原理类似于 Java Proguard,但只针对资源。它会将原本冗长的资源路径变短,如将 res/drawable/ wechat 变为 r/d/a。
AndResGuard 不涉及编译过程,只需输入一个 APK(无论签名与否、 debug 版、 release 版均可,在处理过程中会直接将原签名删除),即可得到一个实现资源混淆后的 APK(若在配置文件中输入签名信息,可自动重签名并对齐,得到可直接发布的 APK)以及对应资源 ID 的映射文件。
其主要原理是, APK 中的 resources.arsc 文件保存着文件的映射,通过修改 resources.arsc中文件的映射及文件名称,同时对图片及 APK 执行 7zip 压缩,让应用 APK 包体尽量缩小。
具体的接入及使用方法如下。
第一步,配置项目根目录的 build.gradle,加入 freeline-gradle 的依赖:
1. buildscript {
2. repositories {
3. jcenter()
4. }
5. dependencies {
6. classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.2.13'
7. }
8. }
第二步,在主 Module 的 build.gradle 中,应用 freeline 插件的依赖:
1. apply plugin: 'AndResGuard'
2. android {
3. ...
4. }
第三步,进行 AndResGuard 资源混淆配置:
1. andResGuard {
2. // mappingFile = file("./resource_mapping.txt")
3. mappingFile = null
4. use7zip = true
5. useSign = true
6. // 打开这个开关,会保持所有资源的原始路径,只混淆资源的名字
7. keepRoot = false
8. whiteList = [
9. // 图标
10. "R.drawable.icon",
11. // 字符串资源
12. "R.string.com.crashlytics.*",
13. // Google 服务相关资源
14. "R.string.google_app_id",
15. "R.string.gcm_defaultSenderId",
16. "R.string.default_web_client_id",
17. "R.string.ga_trackingId",
18. "R.string.firebase_database_url",
19. "R.string.google_api_key",
20. "R.string.google_crash_reporting_api_key"
21. ]
22. compressFilePattern = [
23. "*.png",
24. "*.jpg",
25. "*.jpeg",
26. "*.gif",
27. ]
28. sevenzip {
29. artifact = 'com.tencent.mm:SevenZip:1.2.15'
30.
31. }
32. /**
33. * 可选:如果不设置,则会默认覆盖 assemble 输出的 APK 文件
34. **/
35. // finalApkBackupPath = "${project.rootDir}/final.apk"
36. /**
37. * 可选:指定 V1 签名时生成 jar 文件的摘要算法
38. * 默认值为"SHA-1"
39. **/
40. // digestalg = "SHA-256"
41. }
通过以上 3 步配置,便可对资源进行混淆,缩小 APK 包体大小。但是要记得对 APK 混淆过的映射进行保存,防止出现问题无法追踪的情况。




![[office] 怎样给Excel加密?给Excel加密的方法 - 宋马](https://pic.songma.com/blogimg/20250329/43d1405495cf4bae9f4f7a77b10255d4.jpg)













暂无评论内容