Android Studio打包混淆及语法规则

在使用Android Studio混淆打包时,Studio自身集成了Java语言的ProGuard作为压缩,优化和混淆工具,配合Gradle构建工具使用很简单。只需要在工程应用目录的gradle文件中设置minifyEnabled为true即可。然后我们就可以到proguard-rules.pro文件中加入我们的混淆规则了。

ProGuard作用
压缩(Shrinking):默认开启,用以减小应用体积,移除未被使用的类和成员,并且会在优化动作执行之后再次执行(因为优化后可能会再次暴露一些未被使用的类和成员)。如果想要关闭压缩,在proguard-rules.pro文件中加入:

# 关闭压缩
-dontshrink 

优化(Optimization):默认开启,在字节码级别执行优化,让应用运行的更快。同上,如果想要关闭优化,在proguard-rules.pro文件中加入:

# 关闭优化
-dontoptimize
-optimizationpasses n 表示proguard对代码进行迭代优化的次数,Android一般为5

混淆(Obfuscation):默认开启,增大反编译难度,类和类成员会被随机命名,除非用keep保护。

# 关闭混淆
-dontobfuscate

混淆后默认会在工程目录app/build/outputs/mapping/release下生成一个mapping.txt文件,这就是混淆规则,我们可以根据这个文件把混淆后的代码反推回源本的代码,所以这个文件很重要,注意保护好。原则上,代码混淆后越乱越无规律越好,但有些地方我们是要避免混淆的,否则程序运行就会出错,所以就有了下面要教大家的,如何让自己的部分代码避免混淆从而防止出错。

代码中开启混淆:
在app 的module 下的 build.gradle 文件中修改 minifyEnabled false 为 true。
也可以同时设置删除无用资源。(删除无用的Resource)

 修改完这里,需要操作app模块下的 proguard-rules.pro 文件来定义项目打包的混淆选项:

下面是自己常用的混淆模板,可以根据实际需求进行增删:
 


#--------------------------1.实体类 ↓---------------------------------
-keep public class com.XX.XX.bean.** { *; }

#--------------------------1.实体类 ↑---------------------------------


#--------------------------2.第三方包 ↓-------------------------------
# Glide
-keep public class * implements com.bumptech.glide.module.AppGlideModule
-keep public class * implements com.bumptech.glide.module.LibraryGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}
#gson
-keep class com.google.gson.** { *; }
-keep class com.google.**{ *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.google.gson.examples.android.model.** { *; }


#retrofit2
-dontwarn javax.annotation.**
-dontwarn javax.inject.**
# OkHttp3
-dontwarn okhttp3.logging.**
-keep class okhttp3.internal.**{*;}
-dontwarn okio.**
# Retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
# RxJava RxAndroid
-dontwarn sun.misc.**
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
    long producerIndex;
    long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
    rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
    rx.internal.util.atomic.LinkedQueueNode consumerNode;
}

# eventbus
-keepattributes *Annotation*
-keepclassmembers class * {
    @org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }

# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
    <init>(java.lang.Throwable);
}

#--------------------------2.第三方包 ↑-------------------------------


#--------------------------3.与js互相调用的类 ↓------------------------
-keep class **.AndroidJavaScript { *; }
-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);
}
-keepattributes JavascriptInterface
#-------------------------3.与js互相调用的类 ↑------------------------


#-------------------------4.基本不用动区域 ↓--------------------------
#指定代码的压缩级别
-optimizationpasses 5

#包明不混合大小写
-dontusemixedcaseclassnames

#不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers

#混淆时是否记录日志
-verbose

#优化  不优化输入的类文件
-dontoptimize

#预校验
-dontpreverify

# 保留sdk系统自带的一些内容 【例如:-keepattributes *Annotation* 会保留Activity的被@override注释的onCreate、onDestroy方法等】
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod

# 记录生成的日志数据,gradle build时在本项根目录输出
# apk 包内所有 class 的内部结构
-dump proguard/class_files.txt
# 未混淆的类和成员
-printseeds proguard/seeds.txt
# 列出从 apk 中删除的代码
-printusage proguard/unused.txt
# 混淆前后的映射
-printmapping proguard/mapping.txt


# 避免混淆泛型
-keepattributes Signature
# 抛出异常时保留代码行号,保持源文件以及行号
-keepattributes SourceFile,LineNumberTable
#-------------------------4.基本不用动区域 ↑--------------------------

#-------------------------5.默认保留区 ↓-----------------------
# 保持 native 方法不被混淆
-keepclasseswithmembernames class * {
    native <methods>;
}

-keepclassmembers 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*(***);
}

#保持 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();
}

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

# 保持枚举 enum 类不被混淆
-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 *;
}

# 不混淆R文件中的所有静态字段,我们都知道R文件是通过字段来记录每个资源的id的,字段名要是被混淆了,id也就找不着了。
-keepclassmembers class **.R$* {
    public static <fields>;
}

#如果引用了v4或者v7包
-dontwarn android.support.**

# 保持哪些类不被混淆
-keep public class * extends android.app.Application
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Fragment
-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
#-------------------------5.默认保留区 ↑-----------------------


# ============忽略警告,否则打包可能会不成功=============
-ignorewarnings

混淆的一些基本规则:

-keep class com.XX.test.**
-keep class com.XX.test.*

一颗星 
  表示只是保持该包下的类名,而子包下的类名还是会被混淆; 
两颗星 
  表示把本包和所含子包下的类名都保持;用以上方法保持类后,你会发现类名虽然未混淆,但里面的具体方法和变量命名还是变了。 

如果既想保持类名,又想保持里面的内容不被混淆,使用:
 

-keep class com.XX.test.* {*;}

在此基础上,我们也可以使用Java的基本规则来保护特定类不被混淆,比如我们可以用extends,implements等这些Java规则。如下例子就避免所有继承Activity的类被混淆

-keep public class * extends android.app.Activity

如果我们要保留一个类中的内部类不被混淆则需要用$符号,如下例子表示保持XxFragment内部类JavaScriptInterface中的所有public内容不被混淆。

-keepclassmembers class com.XX.ui.fragment.XxFragment$JavaScriptInterface {
   public *;
}

如果一个类中你不希望保持全部内容不被混淆,而只是希望保护类下的特定内容,可以使用

<init>;     //匹配所有构造器
<fields>;   //匹配所有域
<methods>;  //匹配所有方法方法

还可以在<fields>或<methods>前面加上private 、public、native等来进一步指定不被混淆的内容,比如下面代码,表示名为Demo的类下的所有Public方法都不会被混淆

-keep class com.XX.test.Demo {
    public <methods>;
}

比如下面代码表示用JSONObject作为入参的构造函数不会被混淆

-keep class com.XX.test.Demo {
   public <init>(org.json.JSONObject);
}

不需要保持类名,只需要把该类下的特定方法保持不被混淆的话,那就不能用keep方法了,keep方法会保持类名,而需要用keepclassmembers ,如此类名就不会被保持。

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

注意事项

1,jni方法不可混淆,因为这个方法需要和native方法保持一致;

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

2,反射用到的类不混淆(否则反射可能出现问题);

3、AndroidMainfest中的类不混淆,所以四大组件和Application的子类和Framework层下所有的类默认不会进行混淆,自定义的View默认也不会被混淆。所以像网上贴的很多排除自定义View,或四大组件被混淆的规则在Android Studio中是无需加入的。

4、与服务端交互时,使用GSON、fastjson等框架解析服务端数据时,所写的JSON对象类不混淆,否则无法将JSON解析成对应的对象;

5、使用第三方开源库或者引用其他第三方的SDK包时,如果有特别要求,也需要在混淆文件中加入对应的混淆规则;

6、有用到WebView的JS调用也需要保证写的接口方法不混淆,原因和第一条一样;

7、Parcelable的子类和Creator静态成员变量不混淆,否则会产生Android.os.BadParcelableException异常;

# 保持Parcelable不被混淆    
-keep class * implements Android.os.Parcelable {         
    public static final Android.os.Parcelable$Creator *;
}

8、使用enum类型时需要注意避免以下两个方法混淆,因为enum类的特殊性,以下两个方法会被反射调用,见第二条规则。

-keepclassmembers enum * {  
    public static **[] values();  
    public static ** valueOf(java.lang.String);  
}

发布一款应用除了设minifyEnabled为ture,你也应该设置zipAlignEnabled为true,像Google Play强制要求开发者上传的应用必须是经过zipAlign的,zipAlign可以让安装包中的资源按4字节对齐,这样可以减少应用在运行时的内存消耗。

参考:
android打包混淆及语法规则详解_wx60e80a6332641的技术博客_51CTO博客

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Studio中进行打包混淆时,可能会遇到包冲突的报错。这种情况下,需要解决包冲突问题。 首先,查看报错信息中提到的包冲突详情。在你提供的引用中,报错信息中提到了冲突的包路径为"android/support/design/widget/CoordinatorLayout$LayoutParams.class"。 解决包冲突的方法有多种,以下是一种解决方法: 1. 打开项目中的build.gradle文件。 2. 在buildTypes中找到release配置,并将minifyEnabled属性设置为true,表示开启代码混淆。 3. 在proguardFiles中添加proguard-rules.pro文件,该文件用于指定混淆规则。 4. 在proguard-rules.pro文件中添加以下规则,以保持特定的类和接口不被混淆: -keep class okhttp3.** { *; } -keep interface okhttp3.** { *; } -dontwarn okhttp3.** -keep class okio.** { *; } -keep interface okio.** { *; } -dontwarn okio.** -keep class com.hitomi.** { *; } -keep interface com.hitomi.** { *; } -dontwarn com.hitomi.** 5. 重新编译并打包你的应用程序,这次应该不再出现包冲突的报错。 请注意,这只是一种解决包冲突问题的方法之一。在实际操作中,可能需要根据具体情况进行调整和修改。 参考引用: - http://blog.csdn.net/u012246458/article/details/79446784 - build.gradle文件中的代码 - proguard-rules.pro文件中的代码<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [AndroidStudio打包混淆](https://blog.csdn.net/qq_24570087/article/details/80620546)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值