本博客涉及 Android 开发混淆技术,并且只是混淆 JAVA 相关代码,不涉及 JS 代码混淆…

记录一下我一步步混淆的过程吧,混淆之后虽然能保护代码不被逆向但是可能会影响软件稳定性,请酌情使用…

由于大部分是 Android 打包配置操作所以推荐使用 Android Studio 打开项目,打开 react native 项目下面的 android 目录

打开 app 目录下的 build.gradle 文件,找到 buildTypes 下面的 release 添加

minifyEnabled true
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"

shrinkResources true
// 打开资源压缩
zipAlignEnabled true
// 减少应用在运行时的内存消耗

minifyEnabled 是表示打开混淆,proguardFiles 是配置混淆相关的配置文件,其他两行是可选配置,我都用注释介绍了相关用途根据自己需求选择性添加吧

我们看到上面配置混淆修改配置的地方,导入了两个文件 proguard-android-optimize.txt 和 proguard-rules.pro

其中 proguard-android-optimize.txt 是 android 默认的一个混淆规则

proguard-rules.pro 就是相关配置文件了,它的路径就在 app 目录下,我们来写点相关配置

#指定class模糊字典
-classobfuscationdictionary ./pro-android.txt
#指定package模糊字典
-packageobfuscationdictionary ./pro-android.txt
#指定外部模糊字典
-obfuscationdictionary ./pro-android.txt


#------基本指令区------
# 代码混淆压缩比,在0~7之间,默认为5,一般不做修改
-optimizationpasses 5
# 混合时不使用大小写混合,混合后的类名为小写
-dontusemixedcaseclassnames
# 指定不去忽略非公共库的类,是否混淆第三方jar
-dontskipnonpubliclibraryclasses
# 指定不去忽略非公共库的类成员
-dontskipnonpubliclibraryclassmembers
# 不做预校验,preverify是proguard的四个步骤之一,Android不需要preverify,去掉这一步能够加快混淆速度
-dontpreverify
# 混淆时是否记录日志,包含有类名->混淆后类名的映射关系
-verbose
#混淆映射文件输出
-printmapping proguardMapping.txt
#保留Annotation不混淆
-keepattributes *Annotation*,InnerClasses
# 避免混淆泛型
-keepattributes Signature
# 抛出异常时保留源文件名及行号
-keepattributes SourceFile,LineNumberTable
# 指定混淆是采用的算法,后面的参数是一个过滤器,这个过滤器是谷歌推荐的算法,一般不做更改
-optimizations !code/simplification/cast,!field/*,!class/merging/*

# ------默认保留区------
#保留我们使用的四大组件,自定义的Application等等这些类不被混淆
-keep public class * extends android.app.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

# 保留support下的所有类及其内部类
-keep class android.support.** {*;}
# 保留继承support的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**
#Fragment不需要在AndroidManifest.xml中注册,需要额外保护下
-keep public class * extends android.support.v4.**
-keep public class * extends android.app.Fragment

#如果引用了v4或者v7包,可以忽略警告,因为用不到android.support
-dontwarn android.support.**

# 保持 native 方法不被混淆
-keepclasseswithmembernames class * {
    native <methods>;
}

# 保留在Activity中的方法参数是view的方法,这样以来我们在layout中写的onClick就不会被影响
-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}

# 保留我们自定义控件(继承自View)不被混淆
-keep public class * extends android.view.View{
    *** get*();
    void set*(***);
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

# 保持自定义控件类不被混淆
-keepclasseswithmembers class * {
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

# 保留Parcelable序列化类不被混淆
-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}

#保持 Serializable 不被混淆
-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 <fields>;
    !private <methods>;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

#保持枚举 enum 类不被混淆 如果混淆报错,建议直接使用上面的 -keepclassmembers class * implements java.io.Serializable即可
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

#保持实体类不被混淆
-keep class com.mys.example.common.entity.**{*;}

#过滤R文件的混淆:
-keep class **.R$* {
 *;
}

#------react native 基本框架避免混淆------

# google相关包
-dontwarn com.google.**
-keep class com.google.** { *; }
-dontwarn com.google.**
-keep class com.google.** { *; }

# react native相关包
-dontwarn com.facebook.**
-keep class com.facebook.** { *; }

# github相关包
-dontwarn com.github.**
-keep class com.github.** { *; }

# Gson 相关的混淆配置
-keepattributes Signature
-keepattributes *Annotation*
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.google.gson.examples.android.model.** { *; }
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# 注解类避免混淆
-keep class * extends java.lang.annotation.Annotation { *; }
-keep interface * extends java.lang.annotation.Annotation { *; }

#------第三方框架避免混淆------
# 头条相关sdk包
-dontwarn com.bytedance.**
-keep class com.bytedance.** { *; }

# 腾讯相关sdk包
-dontwarn com.tencent.**
-keep class com.tencent.**{*;}

#react-native-video 配置
-dontwarn com.brentvatne.react.**
-keep class com.brentvatne.react.** { *; }

上面我都没有细分指定某些类,而是选择指定包下的全部放弃混淆,这里其实自己可以细心配置一下,然后我们看到最开始指定了几个模糊字典 ./pro-android.txt

这个文件默认是没有的,需要自己创建添加如下内容:

O000O0O00OO0O0OOO0O
O000O0O00OO0O0OOOO0
O000O0O00OO0OO0O0OO
O000O0O00OO0OO0OO0O
O000O0O00OO0OO0OOO0
O000O0O00OO0OOO0O0O
O000O0O00OO0OOO0OO0
O000O0O00OO0OOOO0O0

我这里只放了几行,这个字典其实很大( 感谢企鹅小哥哥提供的字典 ),这边我放到 github 吧,https://github.com/PBK-B/androidproguardFilesconfig

添加好之后点击 Sync Now

配置好之后我们打一个 release 包看看效果吧

在打包过程中可能会出现有几个问题,如果一直卡在 :app:transformClassesAndResourcesWithR8ForRelease 的话去项目的 gradle.properties 文件里关闭 R8 压缩技术,我猜是电脑带不动吧( 手动狗头 ),第一次配置的时候卡在这里个把小时…

android.enableR8=false
# 因为电脑配置问题现在暂时跑不起R8压缩技术,以后有机会再打开试试
# https://issuetracker.google.com, using 'Shrinker (R8)' as component name. You can
# disable R8 by updating gradle.properties with 'android.enableR8=false'.
# Current version is: 1.4.94 (build 390954928f0db9c3b888a367f7f128ce3bbfb160 from go/r8bot (luci-r8-ci-archive-0-5g74)).

打包好了后可以利用 jadx 反编译工具看看效果

尝试 react native Android 打包混淆-天真的小窝