2024年Android最全玩转APK:实现Android-APK瘦身99-99%,android面试题handler

作者2013年从java开发,转做Android开发,在小厂待过,也去过华为,OPPO等大厂待过,18年四月份进了阿里一直到现在。

参与过不少面试,也当面试官 面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长,而且极易碰到天花板技术停滞不前!

我整理了一份阿里P7级别的最系统的Android开发主流技术,特别适合有3-5年以上经验的小伙伴深入学习提升。

主要包括阿里,以及字节跳动,腾讯,华为,小米,等一线互联网公司主流架构技术。如果你想深入系统学习Android开发,成为一名合格的高级工程师,可以收藏一下这些Android进阶技术选型

我搜集整理过这几年阿里,以及腾讯,字节跳动,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。

Java语言与原理;
大厂,小厂。Android面试先看你熟不熟悉Java语言

高级UI与自定义view;
自定义view,Android开发的基本功。

性能调优;
数据结构算法,设计模式。都是这里面的关键基础和重点需要熟练的。

NDK开发;
未来的方向,高薪必会。

前沿技术;
组件化,热升级,热修复,框架设计

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

我在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多,CodeChina上可见;

当然,想要深入学习并掌握这些能力,并不简单。关于如何学习,做程序员这一行什么工作强度大家都懂,但是不管工作多忙,每周也要雷打不动的抽出 2 小时用来学习。

不出半年,你就能看出变化!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile(
‘proguard-android.txt’), ‘proguard-rules.pro’
}
}
}

-keep class com.fractalwrench.** { *; }

minifyEnabled属性设置为“true”值,这将启用 Proguard

(https://www.guardsquare.com/en/proguard) ,

该功能将从 App 中剥离出那些未使用的代码,并对符号的名称做模糊化处理,使得 App 难以被反向工程。

设置shrinkResources属性,将会在 APK 中移除任何并非直接引用的资源。这时如果我们使用反射机制间接地访问资源,就会导致问题,但是本文给出的 App 并不存在这样的问题。

##优化为 786 Kb(削减 50%)

我们已经实现了 APK 规模减半,并未对我们的 APP 有任何可见的影响。

对于那些尚未在 App 中启用AndroidManifest.xmlshrinkResources的开发人员,这是本文给出的最需要重视的并应学会的技巧。他们仅花费数小时做配置和测试,就能轻松地削减数兆的规模。

##我们尚未了解 AppCompat 的工作机制

现在classes.dex文件已削减到占用 APK 的 57%。在我们的 Dex 文件中,大多数方法引用属于android.support软件包,因此我们将要去除该支持库。具体做法为:

  • build.gradle中彻底清除依赖块。

dependencies {
implementation ‘com.android.support:appcompat-v7:26.1.0’
implementation ‘com.android.support.constraint:constraint-layout:1.0.2’
}

  • 更新MainActivity,以扩展android.app.Activity

public class MainActivity extends Activity

  • 更新布局,使用单一的TextView
<?xml version="1.0" encoding="utf-8"?>

  • 删除styles.xml文件,并从AndroidManifest文件的<application>元素中移除android:theme属性。
  • 删除colors.xml文件。
  • 在 gradle 同步时做 50 次上推(push-up)。

##优化为 108 Kb(削减 87%)

天哪,我们刚刚实现了近十倍的削减,即从 786Kb 削减到 108Kb。唯一可见的更改是工具条(Toolbar)的颜色,现在它使用了缺省的 OS 主题。

目录“res”现在占用 APK 规模约 95%,原因是所有的加载图标。如果这些 PNG 图片是由我们自己的设计师所给出的,那么我们可以尝试 将它们转换为 WebP 格式,该格式更加高效,并被 API 15 及以上所支持。

幸运的是,Google 已经优化了我们的 Drawable。即便没有这种优化,ImageOptim 也可优化 PNG 并从中剥离不必要的元数据。

让我们当一次坏人,将我们所有的加载图标替换为单一的单像素黑点,并置于未验证的res/drawable目录中。图片大小约 67 个字节。

##优化为 6808 字节(削减 94%)

我们已经移除了几乎全部的资源,因此毫不奇怪 APK 规模已经削减了约 95%。但是resources.arsc依然引用了如下项:

  • 一个布局文件;
  • 一个字符串资源;
  • 一个调用图标。

让我们从第一项着手。

####布局文件(优化为 6262 字节,削减 9%)

Android 框架会膨胀我们的 XML 文件

(https://developer.android.com/reference/android/view/LayoutInflater.html) ,

并自动创建一个TextView对象,用于Activity对象的contentView

我们可以尝试一些跳过中间的过程,具体做法是移除 XML 文件,并使用程序设置contentView。这样会降低资源的规模,因为我们减少了一个 XML 文件。但是 Dex 文件将会增大,因为我们引用了额外的TextView方法。

TextView textView = new TextView(this);
textView.setText(“Hello World!”);
setContentView(textView);

让我们查看一下这一权衡做法的工作情况,它削减了 5710 个字节。

####App 名称(优化为 6034 字节,削减 4%)

下面我们将删除strings.xml文件,并将AndroidManifest中的android:label属性值更改为“A”。这看上去是一个小更改,但是它从resources.arsc中删除了一项,削减了 Manifest 文件中的字符数,并从“res”目录中移除了一个文件。略有裨益,我们削减了 228 个字节。

####加载图标(优化为 5300 字节,削减 13%)

Android Platform 代码库中的resources.arsc的文档

(https://android.googlesource.com/platform/frameworks/native/+/jb-dev/libs/utils/README)

告诉我们,APK 中的每个资源通过resources.arsc中的一个整数 ID 引用。这些 ID 具有两个命名空间(Namespace):

0x01: 系统资源(预装在 framework-res.apk 中);

0x7f: 应用资源(捆绑在应用的.apk 文件中)。

那么如果在0x01命名空间中引用了一个资源,我们的 APK 发生了什么?我们应该可以在削减文件规模的同时,得到一个更漂亮的图标。

android:icon=“@android:drawable/btn_star”

虽然文档是这样说的,但是在一个生产 App 中,我们应该保持“永远不要信任系统资源”这一原则。该步骤会导致 Google Play 验证失败,而且考虑到我们知道某些制造商已经重定义了白色

(https://www.reddit.com/r/androiddev/comments/71fpru/android_color_resources_not_safe/),

因此在具体操作时需要慎重。

####Manifest 文件(优化为 5252 字节,削减 1%)

目前为止,我们尚未对 Manifest 文件下手。

android:allowBackup=“true”
android:supportsRtl=“true”

移除这些属性将会削减 48 个字节。

####防止破解(优化为 4984 字节,削减 5%)

看上去 Dex 文件中依然包括BuildConfigR

-keep class com.fractalwrench.MainActivity { *; }

如果我们精炼 Proguard 规则,就会清除掉这些类。

####命名混淆(优化为 4936 字节,削减 1%)

现在对我们的Activity赋予一个混淆后的名字。对于正常类,Proguard 可自动实现混淆功能,但是考虑到Activity类名会通过Intents唤醒,因此缺省情况下不要混淆Activity的名字。

MainActivity -> c.java

com.fractalwrench.apkgolf -> c.c

####META-INF(优化为 3307 字节,削减 33%)

当前在 App 签名中,我们使用了 v1 和 v2 签名。看上去这完全是浪费,尤其是 v2 会对整个 APK 做哈希,提供了更高级的保护能力和性能

(https://source.android.com/security/apksigning/#apk-signing-schemes)。

在 APK Analyser 中,v2 签名并不可见,因为它在 APK 文件本身中以二进制块的形式存在。v1 签名是可见的,它是以CERT.RSA 和 CERT.SF文件的形式给出。

Android Studio UI 中提供了 v1 签名的复选框,我们需要去除该选择,并生成一个签名的 APK。我们也需要做相反的过程。

签名大小(字节)
v13511
v23307

看上去从此以后我们使用的是 v2。

##下面的操作将无需 IDE 的支持

现在我们要手工编辑我们的 APK 了。我们将使用如下命令:

1. 创建一个未签名的 APK。

./gradlew assembleRelease

2. 解压缩归档文件。

unzip app-release-unsigned.apk -d app

对文件进行编辑。

3. 压缩归档文件

zip -r app app.zip

4. 运行 zipalign。

zipalign -v -p 4 app-release-unsigned.apk app-release-aligned.apk

5. 使用 v2 签名运行 apksigner。

apksigner sign --v1-signing-enabled false --ks $HOME/fake.jks --out signed-release.apk app-release-unsigned.apk

6. 验证签名。

apksigner verify signed-release.apk

此链接

详细概述了 APK 签名过程。总而言之,gradle 生成了一个未签名的归档文件,zipalign 更改了未压缩资源的字节对齐方式,用于改进加载 APK 时的 RAM 使用,最后 APK 将被加密签名。

未签名且未对齐的 APK 大小为 1902 字节,这意味着签名和对齐过程增加了约 1 Kb。

####文件大小差异(优化为 2608 字节,削减 21%)

很奇怪!我们对未对齐的 APK 解压缩并手工签名,并手动移除了META-INF/MANIFEST.MF,这削减了 543 字节。如果有人知道原因,请告诉我!

现在我们的签名 APK 中只有三个文件,当然还可以去除resources.arsc,因为我们并未定义任何资源!

这将使我们仅保留 Manifest 和classes.dex文件,两个文件大小相当。

####压缩破解(Compression Hack)(优化为 2599 个字节,削减 0.5%)

让我们将剩余的字符串都更改为‘c’,更新版本为 26,然后生成一个签名的 APK。

compileSdkVersion 26
buildToolsVersion “26.0.1”
defaultConfig {
applicationId “c.c”
minSdkVersion 26
targetSdkVersion 26
versionCode 26
versionName “26”
}

<application
android:icon=“@android:drawable/btn_star”
android:label=“c”

这将削减 9 个字节。

尽管文件中的字符数并未改变,但是我们更改了‘c’字符的频次。这使得压缩算法可以进一步降低文件的大小。

####你好,ADB(优化到 2462 字节,削减 5%)

adb shell am start -a android.intent.action.MAIN -n c.c/.c

下面给出新的 Manifest 文件:

我们还移除了加载图标。

####削减方法引用(优化为 2179 字节,削减 12%)

我们最初需求是生成一个可安装在设备上的 APK。现在是运行“Hello World”的时候了。

我们的 App 引用了TextViewBundleActivity中的方法。通过移除Activity,并替换为用户定义的Application类,我们可以进一步削减 Dex 文件大小。现在我们的 Dex 文件应该仅引用了单一的方法,即Application的构造函数。

现在我们的源文件如下:

package c.c;
import android.app.Application;
public class c extends Application {}

最后

分享一份NDK基础开发资料

详解:Linux网络虚拟化技术

分享内容包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值