安卓APP完整开发流程(8/12)代码混淆
牛客高级系列专栏:
安卓
- 想通关安卓面试,请看:《150道安卓高频面试题目录及答案链接》
- 想通关安卓系统面试,请看:《140道安卓系统Framework面试题目录及答案链接》
- 想进阶安卓开发,请看:《Android进阶知识体系解析_15大安卓进阶必备知识点》
- 想了解安卓APP完整开发流程,请看:《安卓APP完整开发流程》
- 想掌握安卓App性能优化,请看:《安卓性能优化讲解和实战专栏》
- 想掌握Gradle语法,制作Gradle插件,请看:《安卓Gradle语法解析和实践大全》
嵌入式
- 想通关嵌入式面试,请看: 《111道嵌入式面试题目录及答案链接》
- 想多掌握几个嵌入式项目,请看:《6个嵌入式项目交流分享(附源码)》
本人是2020年毕业于广东工业大学研究生:许乔丹,有国内大厂CVTE和世界500强企业安卓开发经验,网上安卓资料千千万,笔者将继续维护专栏,一杯奶茶价格不止提供答案解析,承诺提供专栏内容免费技术答疑,直接咨询即可。助您快速掌握安卓App完整开发流程!
正文开始⬇
1、为什么需要使用代码混淆
安卓应用中的代码可以被反编译、重组和重新打包,这导致了一些安全问题,如:攻击者可能会利用反编译得到的代码,找到应用中的漏洞或密钥,从而做出恶意行为。
代码混淆不是说可以防止他人反编译你的APK,而是可以通过修改变量名、方法名、类名等来改变代码的结构和逻辑,使得反编译后得到的源码难以理解和阅读,增加攻击者分析代码的难度,从而提高应用的安全性。
此外,代码混淆还可以减小应用安装包的大小。当代码被混淆时,重复和无用代码会被标记并在混淆后被删除,从而减小应用的大小。
我们来看看没有代码混淆的情况:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
private fun importantFun() : Int{
return 0
}
private fun importantFunTwo() : Int{
return 0
}
}
我们在MainActivity定义了2个函数,编译APK后,直接在Android Studio双击apk文件,可以看到a apk文件里面有1个dex文件,找到MainActivity的代码,importantFun()和 importantFunTwo()两个方法;
2、怎么使用代码混淆
在app模块里面的build.gradle的minifyEnabled默认为false,现在设置为true:
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
接着重新编译重新看看apk文件:
- importantFun()和 importantFunTwo()不见了,这是因为这两个方法被系统识别为无用代码直接优化掉了;
- 出现简单而无意义的名字,如‘d','h'等,别人看到这种命名,也无法分析出代码的含义;
3、代码混淆配置
上面第2小节里面的:
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
consumerProguardFiles "consumer-rules.pro"
}
}
- getDefaultProguardFile('proguard-android-optimize.txt') 返回了 Android SDK 中默认的 ProGuard 规则文件路径,这个文件包含优化过的 ProGuard 规则,可以帮助最大化地压缩 APK 文件大小和优化应用程序性能。使用这个默认规则是通常情况下推荐的。我们可以看到代码混淆后类名:MainActivity的命名不会混淆,这就是该文件里配置了不要混淆Activity类的子类。
proguard-rules.pro
: 是我们自己定义的 ProGuard 规则文件,这个文件包含自定义的混淆规则。我们可以在这里自定义类、方法、字段等的混淆规则。consumer-rules.pro
:用于保留特定类和方法,以确保公共接口对消费者可见。
通过这几个文件的组合,可以实现对代码的混淆和最小化,提高应用程序的安全性并减小 APK 文件的大小。
如果希望不混淆importantFun()方法,就可以在proguard-rules.pro文件里添加:
-keepclasseswithmembers class com.example.myapplication.MainActivity {
private int importantFun();
}
如下图所示,就可以看到importantFun()方法了。
以下是一些常见的 ProGuard 配置方法,可以在 proguard-rules.pro
文件中添加这些规则来进行混淆和优化:
- 保持特定的类或方法不被混淆:
-keep class com.example.MyClass { *; } #保留 com.example.MyClass 类和其所有成员
-keepclassmembers class com.example.MyClass { *; } #保留 com.example.MyClass 类所有成员
-keepclassmembers enum com.example.MyEnum { *; } #保留 com.example.MyEnum 枚举的所有成员
# 保留枚举类不被混淆
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keepclassmembers interface com.example.MyInterface { *; } #保留 com.example.MyInterface 接口的所有成员
-keep class * extends java.lang.Exception #保持所有继承自 java.lang.Exception 的类不被混淆
-keep class * implements com.core.IReq #保持所有实现了 com.core.IReq 接口的类不被混淆
-keep
指令用于防止类、方法等被混淆掉,指定保留的粒度比较大;-keepclassmembers
指令则用于保留某个类成员(如方法、字段)的名称或特性,并且指定保留的粒度比较小。在实际使用中,可以灵活组合和使用,以达到最佳混淆效果。
- 保持特定的代码库不被混淆(如支持库和其他第三方库):
-keep class android.support.v7.** { *; } #保留 android.support.v7 包下的所有类和成员
-keep interface android.support.v7.** { *; } #保留 android.support.v7 包下的所有接口和其所有成员
-keep class com.google.android.gms.** { *; } #保留 com.google.android.gms 包下的所有类和成员
- 将某个类标记为入口点,防止被混淆:
# 保留 com.example.MyEntryPointClass 类及其 public static main 方法
-keep public class com.example.MyEntryPointClass {
public static void main(java.lang.String[]);
}
- 禁止混淆某些类、方法、字段、注解:
-dontobfuscate #禁用代码混淆
-dontwarn kotlin.** #禁用警告,不提示包含 kotlin 的警告信息
-dontwarn com.squareup.okhttp.** #禁用警告,不提示包含 com.squareup.okhttp 的警告信息
-dontwarn org.apache.http.** #禁用警告,不提示包含 org.apache.http 的警告信息
-keepattributes *Annotation*, Signature #保留注解 @ 和签名信息
-keepclasseswithmembers class *{
public <init>(android.content.Context,android.util.AttributeSet);
public <init>(android.content.Context,android.util.AttributeSet,int);
}
-keepclassmembers class * {
@com.example.annotations.MyAnnotation *;
}
# 保留Parcelable序列化类不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# 保留Serializable序列化的类不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
!private <fields>;
!private <methods>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# 保留R下面的资源
-keep class **.R$* {*;}
# 保留本地native方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
# 保留在Activity中的方法参数是view的方法,
# 这样以来我们在layout中写的onClick就不会被影响
-keepclassmembers class * extends android.app.Activity{
public void *(android.view.View);
}
#禁止android-X混淆
-keep class com.google.android.material.** {*;}
-keep class androidx.** {*;}
-keep public class * extends androidx.**
-keep interface androidx.** {*;}
-dontwarn com.google.android.material.**
-dontnote com.google.android.material.**
-dontwarn androidx.**
# 保留四大组件,自定义的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.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep public class com.android.vending.licensing.ILicensingService
# 保留sup
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
要成为一名高级安卓APP开发工程师,只有对安卓APP完整开发流程有全面性的了解,才能在技术、产品、市场这三大模块,帮助团队找到更优的解决方案。 本专栏详细介绍安卓APP完整开发流程:配置环境--》创建工程--》工程配置--》编写代码--》引用第三方库--》多项目构建--》多Dex支持--》代码混淆--》签名/打包--》构建定制--》多渠道打包--》线上运维。 安卓系统工程师也可以参考~