优化。分析和优化方法的二进制代码;根据proguard-android-optimize.txt
中的描述,优化可能会造成一些潜在风险,不能保证在所有版本的Dalvik上都正常运行。
混淆。把类名、属性名、方法名替换为简短且无意义的名称;
预校验。添加预校验信息。这个预校验是作用在Java平台上的,Android平台上不需要这项功能,去掉之后还可以加快混淆速度。
这四个流程默认开启。
在Android
项目中我们可以选择将“优化”和“预校验”关闭,对应命令是-dontoptimize、-dontpreverify
(当然,默认的 proguard-android.txt
文件已包含这两条混淆命令,不需要开发者额外配置)。
资源压缩
====
资源压缩将移除项目及依赖的库中未被使用的资源,这在减少apk
包体积上会有不错的效果,一般建议开启。具体做法是在 build.grade
文件中,将shrinkResources
属性设置为true
。需要注意的是,只有在用minifyEnabled true
开启了代码压缩后,资源压缩才会生效。
资源压缩包含了“合并资源”和“移除资源”两个流程。
“合并资源”流程中,名称相同的资源被视为重复资源会被合并。需要注意的是,这一流程不受shrinkResources
属性控制,也无法被禁止,gradle
必然会做这项工作,因为假如不同项目中存在相同名称的资源将导致错误。gradle
在四处地方寻找重复资源:
src/main/res/
路径
不同的构建类型(debug
、release
等等)
不同的构建渠道
项目依赖的第三方库
合并资源时按照如下优先级顺序
依赖 -> main -> 渠道 -> 构建类型
假如重复资源同时存在于main文件夹和不同渠道中,gradle 会选择保留渠道中的资源。
同时,如果重复资源在同一层次出现,比如src/main/res/ 和 src/main/res2/
,则 gradle
无法完成资源合并,这时会报资源合并错误。
“移除资源”流程则见名知意,需要注意的是,类似代码,混淆资源移除也可以定义哪些资源需要被保留,这点在下文给出。
自定义混淆规则
=======
在上文“混淆配置”中有这样一行代码
proguardFiles getDefaultProguardFile(‘proguard-android.txt’), ‘proguard-rules.pro’
这行代码定义了混淆规则由两部分构成:位于 SDK 的 tools/proguard/ 文件夹中的 proguard-android.txt 的内容以及默认放置于模块根目录的 proguard-rules.pro 的内容。前者是 SDK 提供的默认混淆文件,后者是开发者自定义混淆规则的地方。
常见的混淆指令
=======
-
optimizationpasses
-
dontoptimize
-
dontusemixedcaseclassnames
-
dontskipnonpubliclibraryclasses
-
dontpreverify
-
dontwarn
-
verbose
-
optimizations
-
keep
-
keepnames
-
keepclassmembers
-
keepclassmembernames
-
keepclasseswithmembers
-
keepclasseswithmembernames
更多详细的请到官网
需要特别介绍的是与保持相关元素不参与混淆的规则相关的几种命令:
| 命令 | 作用 |
| — | — |
| -keep | 防止类和成员被移除或者被重命名 |
| -keepnames | 防止类和成员被重命名 |
| -keepclassmembers | 防止成员被移除或者被重命名 |
| -keepnames | 防止成员被重命名 |
| -keepclasseswithmembers | 防止拥有该成员的类和成员被移除或者被重命名 |
| -keepclasseswithmembernames | 防止拥有该成员的类和成员被重命名 |
保持元素不参与混淆的规则
[保持命令] [类] {
[成员]
}
“类”代表类相关的限定条件,它将最终定位到某些符合该限定条件的类。它的内容可以使用:
-
具体的类
-
访问修饰符(public、protected、private)
-
通配符*,匹配任意长度字符,但不含包名分隔符(.)
-
通配符**,匹配任意长度字符,并且包含包名分隔符(.)
-
extends,即可以指定类的基类
-
implement,匹配实现了某接口的类
-
$,内部类
“成员”代表类成员相关的限定条件,它将最终定位到某些符合该限定条件的类成员。它的内容可以使用:
-
匹配所有构造器
-
匹配所有域
-
匹配所有方法
-
通配符*,匹配任意长度字符,但不含包名分隔符(.)
-
通配符**,匹配任意长度字符,并且包含包名分隔符(.)
-
通配符***,匹配任意参数类型
-
…,匹配任意长度的任意类型参数。比如void test(…)就能匹配任意 void test(String a) 或者是 void test(int a, String b) 这些方法。
-
访问修饰符(public、protected、private)
举个例子,假如需要将com.biaobiao.test包下所有继承Activity的public类及其构造函数都保持住,可以这样写:
-keep public class com.biaobiao.test.** extends Android.app.Activity {
}
常用自定义混淆规则
- 不混淆某个类
-keep public class com.biaobiao.example.Test { *; }
不混淆某个包所有的类
-keep class com.biaobiao.test.** { *; }
}
不混淆某个类的子类
-keep public class * extends com.biaobiao.example.Test { *; }
不混淆所有类名中包含了“model”的类及其成员
-keep public class * extends com.biaobiao.example.Test { *; }
不混淆某个接口的实现
-keep class * implements com.biaobiao.example.TestInterface { *; }
不混淆某个类的构造方法
-keepclassmembers class com.biaobiao.example.Test {
public ();
}
不混淆某个类的特定的方法
-keepclassmembers class com.biaobiao.example.Test {
public void test(java.lang.String);
}
}
不混淆某个类的内部类
-keep class com.biaobiao.example.Test$* {
*;
}
自定义资源保持规则
1. keep.xml
用shrinkResources true
开启资源压缩后,所有未被使用的资源默认被移除。假如你需要定义哪些资源必须被保留,在 res/raw/
路径下创建一个 xml 文件,例如keep.xml
。
通过一些属性的设置可以实现定义资源保持的需求,可配置的属性有:
-
keep
定义哪些资源需要被保留(资源之间用“,”隔开) -
discard
定义哪些资源需要被移除(资源之间用“,”隔开) -
shrinkMode
开启严格模式 -
当代码中通过
Resources.getIdentifier()
用动态的字符串来获取并使用资源时,普通的资源引用检查就可能会有问题。例如,如下代码会导致所有以“img_”开头的资源都被标记为已使用。
当代码中通过 Resources.getIdentifier()
用动态的字符串来获取并使用资源时,普通的资源引用检查就可能会有问题。例如,如下代码会导致所有以“img_”开头的资源都被标记为已使用。
String name = String.format(“img_%1d”, angle + 1);
res = getResources().getIdentifier(name, “drawable”, getPackageName());
我们可以设置 tools:shrinkMode
为strict
来开启严格模式,使只有确实被使用的资源被保留。
以上就是自定义资源保持规则相关的配置,举个例子:
<?xml version="1.0" encoding="utf-8"?><resources xmlns:tools=“http://schemas.android.com/tools”
tools:keep=“@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*”
tools:discard=“@layout/unused2”
tools:shrinkMode=“strict”/>
移除替代资源
一些替代资源,例如多语言支持的 strings.xml,多分辨率支持的 layout.xml 等,在我们不需要使用又不想删除掉时,可以使用资源压缩将它们移除。
我们使用 resConfig 属性来指定需要支持的属性,例如
一些替代资源,例如多语言支持的strings.xml
,多分辨率支持的 layout.xml
等,在我们不需要使用又不想删除掉时,可以使用资源压缩将它们移除。
我们使用 resConfig
属性来指定需要支持的属性,例如
android {
defaultConfig {
…
resConfigs “en”, “fr”
}
}
其他未显式声明的语言资源将被移除。
最后附上一个我在实际项目中的混淆方案
==================
proguard-android.txt
文件内容
代码混淆压缩比,在0~7之间
-optimizationpasses 5
混合时不使用大小写混合,混合后的类名为小写
-dontusemixedcaseclassnames
指定不去忽略非公共库的类
-dontskipnonpubliclibraryclasses
不做预校验,preverify是proguard的四个步骤之一,Android不需要preverify,去掉这一步能够加快混淆速度。
-dontpreverify
-verbose
避免混淆泛型
-keepattributes Signature
保留Annotation不混淆
-keepattributes Annotation,InnerClasses
#google推荐算法
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/,!class/merging/
避免混淆Annotation、内部类、泛型、匿名类
-keepattributes Annotation,InnerClasses,Signature,EnclosingMethod
重命名抛出异常时的文件名称
-renamesourcefileattribute SourceFile
抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable
处理support包
-dontnote android.support.**
-dontwarn android.support.**
保留继承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**
保留R下面的资源
-keep class *.R$ {*;}
保留四大组件,自定义的Application等这些类不被混淆
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Appliction
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
保留在Activity中的方法参数是view的方法,
这样以来我们在layout中写的onClick就不会被影响
-keepclassmembers class * extends android.app.Activity{
public void *(android.view.View);
}
对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
void (**OnEvent);
void (**OnListener);
}
保留本地native方法不被混淆
-keepclasseswithmembernames class * {
native ;
}
保留枚举类不被混淆
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
保留Parcelable序列化类不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
#assume no side effects:删除android.util.Log输出的日志
-assumenosideeffects class android.util.Log {
public static *** v(…);
public static *** d(…);
public static *** i(…);
public static *** w(…);
public static *** e(…);
}
#保留Keep注解的类名和方法
-keep,allowobfuscation @interface android.support.annotation.Keep
-keep @android.support.annotation.Keep class *
-keepclassmembers class * {
@android.support.annotation.Keep *;
}
#3D 地图 V5.0.0之前:
-dontwarn com.amap.api.**
-dontwarn com.autonavi.**
-keep class com.amap.api.**{*;}
-keep class com.autonavi.**{*;}
-keep class com.amap.api.maps.**{*;}
-keep class com.autonavi.amap.mapcore.{;}
-keep class com.amap.api.trace.**{*;}
#3D 地图 V5.0.0之后:
-keep class com.amap.api.maps.**{*;}
-keep class com.autonavi.**{*;}
-keep class com.amap.api.trace.**{*;}
#定位
-keep class com.amap.api.location.**{*;}
-keep class com.amap.api.fence.**{*;}
-keep class com.autonavi.aps.amapapi.model.**{*;}
#搜索
-keep class com.amap.api.services.**{*;}
#2D地图
-keep class com.amap.api.maps2d.**{*;}
-keep class com.amap.api.mapcore2d.**{*;}
#导航
-keep class com.amap.api.navi.**{*;}
-keep class com.autonavi.**{*;}
Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
Retain service method parameters when optimizing.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
@retrofit2.http.* ;
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
最后
简历首选内推方式,速度快,效率高啊!然后可以在拉钩,boss,脉脉,大街上看看。简历上写道熟悉什么技术就一定要去熟悉它,不然被问到不会很尴尬!做过什么项目,即使项目体量不大,但也一定要熟悉实现原理!不是你负责的部分,也可以看看同事是怎么实现的,换你来做你会怎么做?做过什么,会什么是广度问题,取决于项目内容。但做过什么,达到怎样一个境界,这是深度问题,和个人学习能力和解决问题的态度有关了。大公司看深度,小公司看广度。大公司面试你会的,小公司面试他们用到的你会不会,也就是岗位匹配度。
选定你想去的几家公司后,先去一些小的公司练练,学习下面试技巧,总结下,也算是熟悉下面试氛围,平时和同事或者产品PK时可以讲得头头是道,思路清晰至极,到了现场真的不一样,怎么描述你所做的一切,这绝对是个学术性问题!
面试过程一定要有礼貌!即使你觉得面试官不尊重你,经常打断你的讲解,或者你觉得他不如你,问的问题缺乏专业水平,你也一定要尊重他,谁叫现在是他选择你,等你拿到offer后就是你选择他了。
金九银十面试季,跳槽季,整理面试题已经成了我多年的习惯!在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。
附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
做你会怎么做?做过什么,会什么是广度问题,取决于项目内容。但做过什么,达到怎样一个境界,这是深度问题,和个人学习能力和解决问题的态度有关了。大公司看深度,小公司看广度。大公司面试你会的,小公司面试他们用到的你会不会,也就是岗位匹配度。
选定你想去的几家公司后,先去一些小的公司练练,学习下面试技巧,总结下,也算是熟悉下面试氛围,平时和同事或者产品PK时可以讲得头头是道,思路清晰至极,到了现场真的不一样,怎么描述你所做的一切,这绝对是个学术性问题!
面试过程一定要有礼貌!即使你觉得面试官不尊重你,经常打断你的讲解,或者你觉得他不如你,问的问题缺乏专业水平,你也一定要尊重他,谁叫现在是他选择你,等你拿到offer后就是你选择他了。
金九银十面试季,跳槽季,整理面试题已经成了我多年的习惯!在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。
附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
[外链图片转存中…(img-4nmlXdC5-1712515133935)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!