专栏首页Android 进阶Android 混淆打包

Android 混淆打包

代码混淆

代码混淆原因

Java 是一种跨平台的、解释型语言,Java 源代码编译成中间”字节码”存储于 class 文件中。

由于跨平台的需要,Java 字节码中包括了很多源代码信息,如变量名、方法名,并且通过这些名称来访问变量和方法,这些符号带有许多语义信息,很容易被反编译成 Java 源代码。为了防止这种现象,我们可以使用 Java 混淆器对 Java 字节码进行混淆。 混淆就是对发布出去的程序进行重新组织和处理,使得处理后的代码与处理前代码完成相同的功能,而混淆后的代码很难被反编译,即使反编译成功也很难得出程序的真正语义。被混淆过的程序代码,仍然遵照原来的档案格式和指令集,执行结果也与混淆前一样,只是混淆器将代码中的所有变量、函数、类的名称变为简短的英文字母代号,在缺乏相应的函数名和程序注释的况下,即使被反编译,也将难以阅读。同时混淆是不可逆的,在混淆的过程中一些不影响正常运行的信息将永久丢失,这些信息的丢失使程序变得更加难以理解。

Proguard 作用:

  • 压缩shrinks :检查并移除代码中无用的类,字段,方法,属性。
  • 优化optimizes:对字节码进行优化,移除无用的指令。
  • 混淆obfuscates:使用a,b,c,d等简短而无意义的名称,对类,字段和方法进行重名,这样即使代码被逆向工程,对方也比较难以读懂。
  • 预检测Preveirfy:在java平台上对处理后的代码进行再次检测。

Keep 关键字

有时候你是不是还想着,我不需要保持类名,我只需要把该类下的特定方法保持不被混淆就好,那你就不能用keep方法了,keep方法会保持类名,而需要用keepclassmembers ,如此类名就不会被保持,为了便于对这些规则进行理解,官网给出了以下表格:

保留

防止被移除或者被重命名

防止被重命名

类和类成员

-keep

-keepnames

仅类成员

-keepclassmembers

-keepclassmembernames

如果拥有某成员,保留类和类成员

-keepclasseswithmembers

-keepclasseswithmembernames

keep:

  • keep:包留类和类中的成员,防止他们被混淆
  • keepnames:保留类和类中的成员防止被混淆,但成员如果没有被引用将被删除
  • keepclassmembers :只保留类中的成员,防止被混淆和移除。
  • keepclassmembernames:只保留类中的成员,但如果成员没有被引用将被删除。
  • keepclasseswithmembers:如果当前类中包含指定的方法,则保留类和类成员,否则将被混淆。
  • keepclasseswithmembernames:如果当前类中包含指定的方法,则保留类和类成员,如果类成员没有被引用,则会被移除。

混淆原则

  • jni方法不可混淆,因为需要与native方法保持一致;
  • 反射用到的类不混淆(否则反射可能出现问题);
  • AndroidMainfest中的类不混淆,四大组件和Application的子类和Framework层下所有的类默认不会进行混淆;
  • Parcelable的子类和Creator静态成员变量不混淆,否则会产生Android.os.BadParcelableException异常;
  • 使用GSON、fastjson等框架时,所写的JSON对象类不混淆,否则无法将JSON解析成对应的对象;
  • 使用第三方开源库或者引用其他第三方的SDK包时,需要在混淆文件中加入对应的混淆规则;
  • 有用到WEBView的JS调用也需要保证写的接口方法不混淆;
  • 使用enum类型时需要注意避免以下两个方法混淆,因为enum类的特殊性,以下两个方法会被反射调用 -keepclassmembers enum * {   public static **[] values();   public static ** valueOf(java.lang.String);   }

第三方库的混淆原则

一般的第三方库都有自身的混淆方案,可直接引用其自身的混淆配置即可 若无混淆配置,一般的可配置不混淆第三方库

基本配置

-optimizationpasses 5  #指定代码的压缩级别 0 - 7,一般都是5,无需改变
-dontusemixedcaseclassnames #不使用大小写混合,混淆后类名称为小写
#告诉Proguard 不要跳过对非公开类的处理,默认是跳过
-dontskipnonpubliclibraryclasses #如果应用程序引入的有jar包,并且混淆jar包里面的class
#不做预校验,preverify是proguard的4个功能之一
#android不需要preverify,去掉这一步加快混淆速度
-dontpreverify
-verbose #混淆时记录日志(混淆后生产映射文件 map 类名 -> 转化后类名的映射
-printmapping proguardMapping.txt #指定映射文件的名称
#指定混淆时的算法,后面的参数是一个过滤器
#这个过滤器是谷歌推荐的算法,一般也不会改变
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#类型转换错误 添加如下代码以便过滤泛型(不写可能会出现类型转换错误,一般情况把这个加上就是了),即避免泛型被混淆
-keepattributes Signature
#假如项目中有用到注解,应加入这行配置,对JSON实体映射也很重要,eg:fastjson
-keepattributes *Annotation*
#抛出异常时保留代码行数
-keepattributes SourceFile,LineNumberTable

比较完整的配置

-optimizationpasses 5  #指定代码的压缩级别 0 - 7,一般都是5,无需改变
-dontusemixedcaseclassnames #不使用大小写混合
#告诉Proguard 不要跳过对非公开类的处理,默认是跳过
-dontskipnonpubliclibraryclasses #如果应用程序引入的有jar包,并且混淆jar包里面的class
-verbose #混淆时记录日志(混淆后生产映射文件 map 类名 -> 转化后类名的映射
#指定混淆时的算法,后面的参数是一个过滤器
#这个过滤器是谷歌推荐的算法,一般也不会改变
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#类型转换错误 添加如下代码以便过滤泛型(不写可能会出现类型转换错误,一般情况把这个加上就是了),即避免泛型被混淆
-keepattributes Signature
#假如项目中有用到注解,应加入这行配置,对JSON实体映射也很重要,eg:fastjson
-keepattributes *Annotation*
#抛出异常时保留代码行数
-keepattributes SourceFile,LineNumberTable
#保持 native 的方法不去混淆
-keepclasseswithmembernames class * {
    native <methods>;
}
#第三方开源框架以及第三方jar包中的代码不是我们的目标和关心的对象,因此我们全部忽略不进行混淆。
#EventBus的代码没必要混合
-keep class com.XXX.eventbus.** { *; }
-keep class com.XXX.event.** { *; }
-keep class com.XXX.eventbus.util.** { *; }
-keep class android.os.**{*;}
-keepclassmembers class ** {
    public void onEvent*(**);
}
#litepal 数据库框架
-dontwarn org.litepal.*
-keep class org.litepal.** { *; }
-keep enum org.litepal.**
-keep interface org.litepal.** { *; }
-keep public class * extends org.litepal.**
-keepclassmembers class * extends org.litepal.crud.DataSupport{*;}
#v4包下的文件都不要混淆 -dontwarn   如果有警告也不终止
-dontwarn android.support.v4.**
-keep class android.support.v4.app.**{*;}
-keep class android.support.v4.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep public class * extends android.support.v4.**
-keep public class * extends android.app.Fragment  #所有fragment的子类不要去混淆
-keep public class * extends android.app.Activity  #所有activity的子类不要去混淆
-keep public class * extends android.app.Application #用法同上
-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
#保持指定规则的方法不被混淆(Android layout 布局文件中为控件配置的onClick方法不能混淆)
-keepclassmembers class * extends android.app.Activity {
    public void *(android.view.View);
}
#保持自定义控件指定规则的方法不被混淆
-keep public class * extends android.view.View {
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
    public void set*(...);
}
#保持枚举 enum 不被混淆
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
#保持 Parcelable 不被混淆(aidl文件不能去混淆)
-keep class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator *;
}
#需要序列化和反序列化的类不能被混淆(注:Java反射用到的类也不能被混淆)
-keepnames class * implements java.io.Serializable
#保护实现接口Serializable的类中,指定规则的类成员不被混淆
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient <fields>;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}
#保持R文件不被混淆,否则,你的反射是获取不到资源id的
-keep class **.R$* { *; }
#以下针对App本身设置
#保护WebView对HTML页面的API不被混淆
-keep class **.Webview2JsInterface { *; }
#如果你的项目中用到了webview的复杂操作,最好加入
-keepclassmembers class * extends android.webkit.WebViewClient {
  public void *(android.webkit.WebView,java.lang.String,android.graphics.Bitmap);
  public boolean *(android.webkit.WebView,java.lang.String);
}
-keepclassmembers class * extends android.webkit.WebChromeClient {
  public void *(android.webkit.WebView,java.lang.String);
}
#转换JSON的JavaBean,类成员名称保护,使其不被混淆
-keepclassmembernames class com.cgv.cn.movie.common.bean.** { *; }
#保证自定义类不被混淆 XXX换成你自己的包名
-keep class com.XXX.view.** {*;}
# 保持实体数据结构接口不被混淆(也就是被GSON注解的实体结构)此处是自己接口的包名 XXX换成你自己的包名
-keep class com.XXX.model.** { *; }
#使用gson包解析数据时,出现 missing type parameter 异常,添加如下代码
-dontobfuscate #不混淆输入的类文件
-dontoptimize  #不优化输入的类文件
# 不混淆 GSON
-keep class com.google.gson.** { *; }
-keep class com.google.gson.JsonObject {*;}
-keep class org.json.** {*;}
-keep class com.badlogic.** { *;}
-keep class * extends com.badlogic.gdx.utils.Json*
-keep class com.google.** {*;}
-keep class sun.misc.Unsafe { *; }
-keep class com.futurice.project.models.pojo.** { *; }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 绘制优化

    过度绘制(Overdraw)描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次。在多层次重叠的 UI 结构里面,如果不可见的 UI 也在做绘制的操作,会导致某...

    Yif
  • Binder 进程通信

    对应一个4GB的虚拟地址空间,其中3GB是用户空间,1GB是内核空间,当然内核空间的大小是可以通过参数配置调整的。对于用户空间,不同进程之间彼此是不能共享的,而...

    Yif
  • Activity 基础知识

    类加载方案需要重启App后让ClassLoader重新加载新的类,为什么需要重启,因为类是无法卸载的,要想重新加载类就需要重启App,因此采用类加载方案的热修复...

    Yif
  • Android开发笔记(七十三)代码混淆与反破解

    ProGuard是ADT自带的apk混淆器,它的用途有: 1、压缩apk包的大小,能删除无用的代码,并简化部分类名和方法名。 2、加大破解源码的难度,因...

    用户4464237
  • 详解Android的反编译和代码混淆

    1、apktool(资源文件获取) 作用:资源文件获取,可以提取图片文件和布局文件进行使用查看

    砸漏
  • android代码混淆

    proguard 原理 Java代码编译成二进制class 文件,这个class 文件也可以反编译成源代码 ,除了注释外,原来的code 基本都可以看到。为了...

    xiangzhihong
  • Android项目实战(二十五):Android studio 混淆+打包+验证是否成功

    听着music睡
  • Android如何防止apk程序被反编译

    作为Android应用开发者,不得不面对一个尴尬的局面,就是自己辛辛苦苦开发的应用可以被别人很轻易的就反编译出来。

    阳光岛主
  • Android Studio实现打渠道包,切换环境,混淆配置等

    最近遇到项目从Eclispe迁移到Android studio,以前的Ant自动打包脚本已经兼容不好了,所以用了Gradle实现打渠道包,切换环境等。

    开发者技术前线
  • 关于AndroidStudio混淆打包 proguard-rules.pro 的配置关于AndroidStudio混淆打包 proguard-rules.pro 的配置

    Xiaolei123

扫码关注云+社区

领取腾讯云代金券