0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Android编译优化之混淆配置

哆啦安全 来源:虎哥Lovedroid 2023-12-21 09:21 次阅读

Android编译优化之混淆配置

背景

为了使用java8及后续java新版本的特性,Google增加了一步编译过程—脱糖(desugaring),但这一步会导致更长的编译时间,这也是为什么Google会推出D8和R8编译器来优化编译速度。

什么是脱糖?

脱糖即在编译阶段将在语法层面一些底层字节码不支持的特性转换为基础的字节码结构,(比如 List 上的泛型脱糖后在字节码层面实际为 Object); Android 工具链对 Java8 语法特性脱糖的过程可谓丰富多彩,当然他们的最终目的是一致的:使新的语法可以在所有的设备上运行。

D8

D8的功能是将Java字节码转化成dex代码,D8作为DX的一个替代方案。编译流程如下图所示:

eccf159c-9f9d-11ee-8b88-92fbcf53809c.png

D8

Android Studio 3.1版本开始,将D8作为默认的Dex编译器。如果想关闭D8,可以在gradle.properties里添加如下配置:

android.enableD8=false
android.enableD8.desugaring=false

开启D8的好处

•编译更快、时间更短

•DEX编译时占用内容更小

•.dex文件更小

•D8编译的.dex文件拥有相同或者更好的运行性能

如果你的工程已经使用Java 8尽可能开启D8编译,不然可能会出现编译错误。

R8

R8作为原本Proguard 压缩与优化(minification、shrinking、optimization)部分的替代品,依然使用与Proguard一样的keep规则,是新一代的代码压缩工具。 R8之前采用D8+Proguard的形式构建,R8则将混淆和D8工具进行整合,目的是加速构建时间和减少输出apk的大小。

ecebad7e-9f9d-11ee-8b88-92fbcf53809c.png

R8

Gradle插件版本达到3.4.0及以上,默认会开始R8进行代码优化。如果你不想开启R8,可以在gradle.properties里添加如下配置:

android.enableR8=false

开启R8的好处

•代码缩减:规避64引用限制

•资源缩减:移除不使用的资源

•混淆代码:减小DEX文件大小

•优化代码:进一步减小DEX文件大小

相关评测报告

ed0349de-9f9d-11ee-8b88-92fbcf53809c.png

D8R8评测报告

AS多模块混淆配置

AS多模块下,我们可以采用各个模块单独配置方式,即proguard文件配置在各个模块下,在各自的build.gradle文件中引入; 也可以采用下方集中配置方式,将各模块的proguard文件集中配置到一个文件夹下,然后在app模块中集中引入所依赖的模块的proguard文件。 下面以cmcc_service这个app模块为例加以说明,

buildTypes{
release{
minifyEnabledtrue//开启混淆
shrinkResourcestrue//无用资源去除
zipAlignEnabledtrue
proguardFilesgetDefaultProguardFile('proguard-android-optimize.txt'),'proguard-rules.pro',
'../proguardDefine/common-rules.pro','../proguardDefine/live_lib-rules.pro',
'../proguardDefine/gs_api_adapter-rules.pro','../proguardDefine/cmcc_service.pro',
'../proguardDefine/lib_voiceassistant-rules.pro','../proguardDefine/cmcc_softprobe-rules.pro'
if(propertyHaveSigningConfigs)
signingConfigsigningConfigs.release
}
}

其中,proguard-android-optimize.txt是android默认的一些通用混淆规则,proguard-rules.pro是app代码的混淆规则,proguardDefine文件夹下所依赖模块统一放置proguard规则的地方。

注意:引入的三方libs,一般都配有响应的proguard文件,所以不需要再重复配置,gradle编译时会将相关文件 proguard文件合并到一个configuration.txt文件中

ed1b5dda-9f9d-11ee-8b88-92fbcf53809c.png

configuration位置

proguard-android-optimize.txt

#禁用一些代码简化和优化,以及字段和类合并
-optimizations!code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
#运行优化passes的数量为5,数值越高,混淆效果越好,但耗时也更长
-optimizationpasses5
#允许访问和修改保护代码
-allowaccessmodification

#不允许使用大小写混合的类名
-dontusemixedcaseclassnames
#不跳过非公共库类
-dontskipnonpubliclibraryclasses
#详细输出
-verbose

#保留一些反射所需的属性
-keepattributes*Annotation*,Signature,InnerClasses,EnclosingMethod
#保留以下三个类及其公共成员
-keeppublicclasscom.google.vending.licensing.ILicensingService
-keeppublicclasscom.android.vending.licensing.ILicensingService
-keeppublicclasscom.google.android.vending.licensing.ILicensingService
#忽略以下类,不输出note信息
-dontnotecom.android.vending.licensing.ILicensingService
-dontnotecom.google.vending.licensing.ILicensingService
-dontnotecom.google.android.vending.licensing.ILicensingService

#对于本地方法,参见http://proguard.sourceforge.net/manual/examples.html#native
#保留包含native方法的类和方法
-keepclasseswithmembernames,includedescriptorclassesclass*{
native;
}
#保留公共的View子类的set和get方法
#以便于使用属性动画
-keepclassmemberspublicclass*extendsandroid.view.View{
voidset*(***);
***get*();
}
#保留Activity中可用于XML属性onClick中的方法
-keepclassmembersclass*extendsandroid.app.Activity{
publicvoid*(android.view.View);
}
#对于枚举类,参见http://proguard.sourceforge.net/manual/examples.html#enumerations
#保留枚举类成员
-keepclassmembersenum*{
publicstatic**[]values();
publicstatic**valueOf(java.lang.String);
}
#保留实现Parcelable接口的类的CREATOR静态成员
-keepclassmembersclass*implementsandroid.os.Parcelable{
publicstaticfinal**CREATOR;
}
#保留JavaScript接口方法上的注解
-keepclassmembersclass*{
@android.webkit.JavascriptInterface;
}
#支持库包含对新平台版本的引用
#在应用链接旧版平台版本时,不要发出警告,因为它们是安全的
-dontnoteandroid.support.**
-dontnoteandroidx.**
-dontwarnandroid.support.**
-dontwarnandroidx.**
#该类已弃用,但仍然保留用于向后兼容
-dontwarnandroid.util.FloatMath
#这段混淆规则用于保护使用了@Keep注解的类和成员不被混淆,以及忽略特定的冗余类。
-keepclassandroid.support.annotation.Keep
-keepclassandroidx.annotation.Keep
#保留使用了@Keep注解的类和接口的所有成员
-keep@android.support.annotation.Keepclass*{;}
-keep@androidx.annotation.Keepclass*{;}
#保留使用了@Keep注解的类的方法
-keepclasseswithmembersclass*{
@android.support.annotation.Keep;
}
-keepclasseswithmembersclass*{
@androidx.annotation.Keep;
}
#保留使用了@Keep注解的类的字段
-keepclasseswithmembersclass*{
@android.support.annotation.Keep;
}
-keepclasseswithmembersclass*{
@androidx.annotation.Keep;
}
#保留使用了@Keep注解的类的构造方法
-keepclasseswithmembersclass*{
@android.support.annotation.Keep(...);
}
-keepclasseswithmembersclass*{
@androidx.annotation.Keep(...);
}
#忽略特定的冗余类
#android.jar和org.apache.http.legacy.jar中的类重复
-dontnoteorg.apache.http.**
-dontnoteandroid.net.http.**
#android.jar和core-lambda-stubs.jar中的类重复
-dontnotejava.lang.invoke.**

一些三方自带混淆规则

这些规则同样合并到了configuration.txt文件中retrofit2混淆规则

#Theproguardconfigurationfileforthefollowingsectionis/home/cl/.gradle/caches/transforms-3/29b6aa006718d6829551a18646bf70bb/transformed/rules/lib/META-INF/proguard/retrofit2.pro
#Retrofitdoesreflectionongenericparameters.InnerClassesisrequiredtouseSignatureand
#EnclosingMethodisrequiredtouseInnerClasses.
-keepattributesSignature,InnerClasses,EnclosingMethod

#Retainservicemethodparameterswhenoptimizing.
-keepclassmembers,allowshrinking,allowobfuscationinterface*{
@retrofit2.http.*;
}

#Ignoreannotationusedforbuildtooling.
-dontwarnorg.codehaus.mojo.animal_sniffer.IgnoreJRERequirement

#IgnoreJSR305annotationsforembeddingnullabilityinformation.
-dontwarnjavax.annotation.**

#GuardedbyaNoClassDefFoundErrortry/catchandonlyusedwhenontheclasspath.
-dontwarnkotlin.Unit

#Top-levelfunctionsthatcanonlybeusedbyKotlin.
-dontwarnretrofit2.-KotlinExtensions

#Endofcontentfrom/home/cl/.gradle/caches/transforms-3/29b6aa006718d6829551a18646bf70bb/transformed/rules/lib/META-INF/proguard/retrofit2.pro

RxJava2RxAndroid混淆规则

-dontwarnjava.util.concurrent.Flow*

Okhttp3混淆规则

#Theproguardconfigurationfileforthefollowingsectionis/home/cl/.gradle/caches/transforms-3/af3ecb4c3ae4accf6423845d738f047d/transformed/rules/lib/META-INF/proguard/okhttp3.pro
#JSR305annotationsareforembeddingnullabilityinformation.
-dontwarnjavax.annotation.**

#Aresourceisloadedwitharelativepathsothepackageofthisclassmustbepreserved.
-keepnamesclassokhttp3.internal.publicsuffix.PublicSuffixDatabase

#AnimalSniffercompileOnlydependencytoensureAPIsarecompatiblewitholderversionsofJava.
-dontwarnorg.codehaus.mojo.animal_sniffer.*

#OkHttpplatformusedonlyonJVMandwhenConscryptdependencyisavailable.
-dontwarnokhttp3.internal.platform.ConscryptPlatform

#Endofcontentfrom/home/cl/.gradle/caches/transforms-3/af3ecb4c3ae4accf6423845d738f047d/transformed/rules/lib/META-INF/proguard/okhttp3.pro

更多可能用到的混淆配置

#指定不去忽略非公共库的类
-dontskipnonpubliclibraryclasses
#指定不去忽略非公共库的成员
-dontskipnonpubliclibraryclassmembers
#混淆时不做预校验
-dontpreverify
#忽略警告
-ignorewarnings
#保留代码行号,方便异常信息的追踪
-keepattributesSourceFile,LineNumberTable
#appcompat库不做混淆
-keepclassandroidx.appcompat.**
#保留AndroidManifest.xml文件:防止删除AndroidManifest.xml文件中定义的组件
-keeppublicclass*extendsandroid.app.Fragment
-keeppublicclass*extendsandroid.app.Activity
-keeppublicclass*extendsandroid.app.Application
-keeppublicclass*extendsandroid.app.Service
-keeppublicclass*extendsandroid.content.BroadcastReceiver
-keeppublicclass*extendsandroid.content.ContentProvider
-keeppublicclass*extendsandroid.preference.Preference
-keeppublicclass*extendsandroid.view.View

#保留序列化,例如Serializable接口
-keepclassmembersclass*implementsjava.io.Serializable{
staticfinallongserialVersionUID;
privatestaticfinaljava.io.ObjectStreamField[]serialPersistentFields;
privatevoidwriteObject(java.io.ObjectOutputStream);
privatevoidreadObject(java.io.ObjectInputStream);
java.lang.ObjectwriteReplace();
java.lang.ObjectreadResolve();
}

#带有Context、View、AttributeSet类型参数的初始化方法
-keepclasseswithmembersclass*{
public(android.content.Context);
}
-keepclasseswithmembersclass*{
public(android.content.Context,android.util.AttributeSet);
}
-keepclasseswithmembersclass*{
public(android.content.Context,android.util.AttributeSet,int);
}
-keepclassmembersclass*extendsandroid.app.Activity{
publicvoid*(android.view.View);
}

#保留资源R类
-keepclass**.R$*{*;}

#避免回调函数onXXEvent混淆
-keepclassmembersclass*{
void*(**On*Event);
void*(**On*Listener);
void*(**on*Changed);
}

#业务实体不做混淆,避免gson解析错误
-dontwarncom.grandstream.convergentconference.entity.**
-keepclasscom.grandstream.convergentconference.entity.**{*;}

#Rxjava、RxAndroid,官方ReadMe文档中说明无需特殊配置
-dontwarnjava.util.concurrent.Flow*
#okhttp3、okio、retrofit,jar包中已包含相关proguard规则,无需配置
#其他一些配置

Android.bp混淆配置

android_app{
name:"MyApp",
package_name:"com.example.myapp",
srcs:["java/**/*.java"],
manifest:"AndroidManifest.xml",
dex_preopt:{
enabled:true,
},
apk_cert_permissions:[
"android.permission.ACCESS_FINE_LOCATION",
"android.permission.RECORD_AUDIO",
"android.permission.READ_CONTACTS",
],
certificates:["platform"],
resource_files:["res/**/*"],
enable_proguard:true,
proguard_flags:["proguard-android.txt"],
dex_preopt_image_dir:"target/product/${TARGET_PRODUCT}/obj/dex_preopt_image",
}

其中,enable_proguard 设置为 true 表示启用代码和资源混淆,proguard_flags 指定了 Proguard 混淆规则文件,可以在文件中指定代码和资源混淆规则。 resource_files 指定了应用程序的资源文件,包括 AndroidManifest.xml 文件。

android.mk混淆配置

LOCAL_PROGUARD_ENABLED:=obfuscationoptimization

LOCAL_PROGUARD_FLAG_FILES:=proguard.flags
ifeq(eng,$(TARGET_BUILD_VARIANT))
LOCAL_PROGUARD_FLAG_FILES+=proguard-test.flags
else
LOCAL_PROGUARD_FLAG_FILES+=proguard-release.flags
endif

LOCAL_PROGUARD_ENABLED有以下几种配置:

1.LOCAL_PROGUARD_ENABLED := disabled:禁用混淆。

2.LOCAL_PROGUARD_ENABLED := obfuscate:只开启代码混淆,不进行优化。

3.LOCAL_PROGUARD_ENABLED := optimize:只开启优化,不进行代码混淆。

4.LOCAL_PROGUARD_ENABLED := obfuscate optimize:同时开启代码混淆和优化。

编译系统默认应该会加载一个android通用的混淆文件,LOCAL_PROGUARD_FLAG_FILES用于指定app特定的proguard文件。 如果我们不太会配置这些选项,可以去查看原生应用的混淆配置,这对你会有很大启发。

混淆堆栈还原

使用 android 自带的混淆堆栈还原工具 proguardgui 解决

Android/Sdk/tools/proguard/bin$ls
proguard.shproguardgui.shretrace.sh
/Android/Sdk/tools/proguard/bin$./proguardgui.sh

脚本运行后会打开 ProGuard 调试界面

ed3192b2-9f9d-11ee-8b88-92fbcf53809c.png

proguard gui tools

填写混淆前后的映射文件 mapping.txt 和需要还原的 logcat 异常日志,点击 Retrace 按钮就能还原混淆前的异常信息

结论

总之,一些通用混淆规则Android已经帮我写好了,我们关心的可能就是我们自己开发的那部分代码的混淆规则,混淆工作做的好有很多好处: 代码更安全、包体积更小、运行速度更快,但是混淆也会带来意想不到的运行异常,希望你做好测试,希望你尽快用起来。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Android
    +关注

    关注

    12

    文章

    3851

    浏览量

    125642
  • JAVA
    +关注

    关注

    19

    文章

    2904

    浏览量

    102994
  • 代码
    +关注

    关注

    30

    文章

    4555

    浏览量

    66772
  • 编译
    +关注

    关注

    0

    文章

    615

    浏览量

    32394

原文标题:Android编译优化之混淆配置

文章出处:【微信号:哆啦安全,微信公众号:哆啦安全】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    干货!Android蓝牙驱动开发经验

    干货!Android蓝牙驱动开发经验目录一 Bluetooth基本概念1二 Android Bluetooth架构12.1 Bluetooth架构图12.2 Bluetooth代码层次结构3三
    发表于 02-29 15:53

    基于Android的Brillo编译环境配置

    相同,可以参考Android编译环境配置方法设置。   以Ubuntu 14.04为例简单介绍一下:   1、安装JDKsudo apt-get updatesudo apt-get install
    发表于 09-21 10:32

    Build settings探究编译优化介绍

    Build settings探究编译优化
    发表于 06-19 10:17

    Android内核编译教程

    标准的Linux开发流程一样,Android平台开发的一个很重要的基础工作就是对其内核的编译和移植。本文结合Android的开发文档以及本人的实践经验,简单介绍了Android内核的
    发表于 06-22 09:11 93次下载

    Android编译工具

    Android编译工具
    发表于 12-17 15:59 21次下载

    第10章Linux及Android操作系统的编译

    10.1 Android系统架构 10.2 Ubuntu编译环境配置 10.3 快速入门与预编译二进制文件 10.4 从源代码构建
    发表于 04-11 14:59 0次下载

    Android源代码编译

    Android源代码编译
    发表于 10-24 09:30 5次下载
    <b class='flag-5'>Android</b>源代码<b class='flag-5'>编译</b>

    fireflyAIO-3399C主板编译 Android8.1 固件简介

    编译 Android8.1 固件 准备工作 编译 Android 对机器的配置要求较高
    的头像 发表于 12-13 10:31 971次阅读

    fireflyAIO-3288C主板编译Android固件简介

    编译 Android 对机器的配置要求较高
    的头像 发表于 12-16 14:53 865次阅读

    fireflyROC-RK3399主板PC编译Android 8.1简介

    编译 Android 8.1 准备 硬件配置 编译 Android 8.1 开发环境硬件配置
    的头像 发表于 12-20 10:38 2618次阅读

    fireflyROC-RK3328主板编译Android 7.1简介

    编译 Android 7.1 开发环境硬件配置建议
    的头像 发表于 12-21 10:52 2194次阅读

    fireflyAIO-3399J编译 Android 固件简介

    编译 Android 固件 准备工作 编译 Android 对机器的配置要求较高: 64 位 CPU 16GB 物理
    的头像 发表于 12-24 11:03 1107次阅读

    深入浅出编译优化选项(下)

    在《深入浅出编译优化选项(上)》中,我们介绍了如何在IAR Embedded Workbench编译器中进行编译优化等级
    的头像 发表于 04-21 10:19 782次阅读

    Java反编译混淆编程实例分析

    支持对已混淆的ja (1).控制台输出(没有反混淆)r包进行反混淆
    发表于 06-01 14:48 887次阅读
    Java反<b class='flag-5'>编译</b>反<b class='flag-5'>混淆</b>编程实例分析

    APP混淆实战(Java/so代码混淆)

    Android App Bundle混淆加密加壳加固保护的解决方案(过Google App上架审核)最全Android及资源混淆方法汇总(无需加固节约成本并将APP上架Google P
    的头像 发表于 06-29 15:42 590次阅读
    APP<b class='flag-5'>混淆</b>实战(Java/so代码<b class='flag-5'>混淆</b>)