魅力程序猿

  • 首页
  • Java
  • Android
  • APP
    • 扑克计分器
    • Video Wallpaper
  • 联系我
  • 关于我
  • 资助
道子
向阳而生
  1. 首页
  2. Android
  3. 正文

Android面试题16–代码混淆(Proguard)

2016年12月24日 5692点热度 0人点赞 3条评论

1. Proguard认识

Proguard是一个非常高效和方便的混淆工具,使用了这个工具混淆打包后,apk体积显著的减少了,而且反编译难度也加大了。官网的介绍是:ProGuard是一个免费的Java类文件缩小,优化,混淆和预验证的工具。它检测和删除未使用的类,字段,方法和属性;优化字节码并删除未使用的指令;它使用短的无意义的名称重命名剩余的类,字段和方法。所得到的应用程序和库更小,更快,并且更好地针对逆向工程进行优化。

而且Proguard已经集成在Android studio构建系统里了,可以通过简单的代码来实现构建apk的时候进行混淆打包。

官网地址:https://developer.android.google.cn/studio/build/shrink-code.html

2. Proguard使用

我们需要在项目里的build.gradle文件里配置Proguard。

buildTypes {
        release {
            shrinkResources true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        debug {
            shrinkResources false
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

}

getDefaultProguardFile(‘proguard-android.txt') 方法可从 Android SDK tools/proguard/ 文件夹获取默认 ProGuard 设置。
提示:要想做进一步的代码压缩,可尝试使用位于同一位置的 proguard-android-optimize.txt 文件。它包括相同的 ProGuard 规则,但还包括其他在字节码一级(方法内和方法间)执行分析的优化,以进一步减小 APK 大小和帮助提高其运行速度。

shrinkResources 是去除无效的资源文件,压缩资源。

minifyEnabled 是开启混淆。

这是默认的Proguard配置,proguard-rules.pro是需要在你的项目里创建的文件,层级跟build.gradle文件一样的,当然你可以随意改他的文件名,只不过需要在配置代码里面跟着修改,其实这个文件就是Proguard的自定义配置文件,没有这个文件你构建是会报错的。

proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

如果你希望在不通的渠道版本里使用不同的ProGuard 规则,那就在相应的 productFlavor 代码块中再添加一个 proguardFiles 属性。例如,以下 Gradle 文件会向 flavor2 产品风味添加 flavor2-rules.pro。现在 flavor2 使用所有三个 ProGuard 规则,因为还应用了来自 release 代码块的规则。

android {
    ...
    buildTypes {
        release {
	    shrinkResources true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
        }
    }
    productFlavors {
        flavor1 {
        }
        flavor2 {
            proguardFile 'flavor2-rules.pro'
        }
    }
}

每次构建时 ProGuard 都会输出下列文件:

dump.txt //说明 APK 中所有类文件的内部结构。

mapping.txt //提供原始与混淆过的类、方法和字段名称之间的转换。

seeds.txt //列出未进行混淆的类和成员。

usage.txt //列出从 APK 移除的代码。

这些文件保存在 <module-name>/build/outputs/mapping/release/。

Proguard基本语法

-keep 不混淆类和成员或者被重命名

-keepnames 防止类和成员被重命名

-keepclassmembers 不混淆成员被移除或者被重命名

--keepmembernames 防止成员被重命名

-keepclasseswithmembers 不混淆拥有该成员的类和成员或者被重命名

-keepclasseswithmembernames 防止拥有该成员的类和成员被重命名

而且还支持通配符*

例如

不混淆某个类

-keep public class com.aoaoyi.example.abc { *; }

不混淆某个包

-keep public class com.aoaoyi.example.** { *; }

不混淆某个类的子类

-keep public class * extends com.aoaoyi.exampl.xy { *; }

 

3. 以下是在项目里常使用的配置

## --- 基础混淆配置 ---

# 指定代码的压缩级别
-optimizationpasses 5  

# 优化时允许访问并修改有修饰符的类和类的成员
-allowaccessmodification  
 
# 不使用大小写混合
-dontusemixedcaseclassnames 

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

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

# 忽略警告,避免打包时某些警告出现,没有这个的话,构建报错
-ignorewarnings  

# 不做预校验,preverify是proguard的四个步骤之一,Android不需要preverify,去掉这一步能够加快混淆速度。
-dontpreverify

# 过滤泛型  出现类型转换错误时,启用这个
-keepattributes Signature  

# 抛出异常时保留代码行号 方便测试
-keepattributes SourceFile,LineNumberTable

# 混淆时所采用的算法
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/* 
# --- Android开发中一些需要保留的公共部分 ---

# 不混淆注解相关
-keepattributes *Annotation* 

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

# 保持枚举 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 *;
}

# 不混淆继承Serializable的子类
-keep class * implements java.io.Serializable {*;}
-keepnames class * implements java.io.Serializable
-keepclassmembers class * implements java.io.Serializable {*;}


# --- 不能被混淆的基类 ---
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Fragment
-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 class org.xmlpull.v1.** { *; }

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

# 不混淆R文件
-keepclassmembers class **.R$* { 
    public static ;
}

# --- 不混淆android-support-v4包 ---
-dontwarn android.support.v4.**
-keep class android.support.v4.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class * extends android.support.v4.** { *; }
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v4.widget
-keep class * extends android.support.v4.app.** {*;}
-keep class * extends android.support.v4.view.** {*;}
-keep public class * extends android.support.v4.app.Fragment


# 不混淆继承的support类
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**


# 不混淆log 
-assumenosideeffects class android.util.Log {
    public static boolean isLoggable(java.lang.String, int);
    public static int v(...);
    public static int i(...);
    public static int w(...);
    public static int d(...);
    public static int e(...);
}


# 保持Activity中参数类型为View的所有方法
-keepclassmembers class * extends android.app.Activity {
          public void *(android.view.View);
}

# 有用到WebView的JS调用接口不被混淆
#webkit
-keep public class javax.**
-keep public class android.webkit.**
-dontwarn android.webkit.WebVie

#JavascriptInterface不混淆webview中对javascript接口
-keep public class * implements java.lang.reflect.Type
-keepattributes JavascriptInterface

-keepclasseswithmembernames class * {
    native ;
}

# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
       void *(**On*Event);
       void *(**On*Listener);
}

# --- 不混淆第三方库 这个可以去相关的第三方库官网找寻混淆代码 如果被混淆了会无法使用 ---

#Google
-dontwarn com.google.android.maps.**
-keepclassmembers class * {
	public (org.json.JSONObject);
}
-keep public class com.smile.android.R$*{
	public static final int *;
}

##Begin: proguard configuration for Gson
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.** {*;}
#-keep class com.google.gson.stream.** { *; }
# Prevent proguard from stripping interface information from TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
##End: proguard configuration for Gson
-keep class com.你的bean.** { *; }


# OkHttp3
-dontwarn okhttp3.logging.**
-keep class okhttp3.internal.**{*;}
-dontwarn okio.**


# Retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions

# Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}

# 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;
}

#facebook
-keep class com.facebook.** { *; }

#twitter
-keep class twitter4j.**  { *; }
-keep class oauth.signpost.**  { *; }

#cocos2dx
-keep class org.cocos2dx.lib.**  { *; }

#apache
-keep class org.apache.** { *; }
-keep class a.a.a.**      { *; }
-keep class com.mrocker.** { *; }

#umeng Analytics begin
-keep class com.umeng.commonsdk.** {*;}
-keep class com.umeng.analytics.** {*;}
-keep class com.umeng.** {*;}
#umeng Analytics end

# 微信
 -keep class com.tencent.mm.** {*;}

#Glide图片库 begin
-keep class com.bumptech.glide.**{*;}
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}
# for DexGuard only
#-keepresourcexmlelements manifest/application/meta-data@value=GlideModule
#Glide end

# Testin
-dontwarn com.testin.agent.**
-keep class com.testin.agent.** {*;}


# 支付宝钱包
-dontwarn com.alipay.**
-dontwarn HttpUtils.HttpFetcher
-dontwarn com.ta.utdid2.**
-dontwarn com.ut.device.**
-keep class com.alipay.android.app.IAlixPay{*;}
-keep class com.alipay.android.app.IAlixPay$Stub{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;}
-keep class com.alipay.sdk.app.PayTask{ public *;}
-keep class com.alipay.sdk.app.AuthTask{ public *;}
-keep class com.alipay.mobilesecuritysdk.*
-keep class com.ut.*

#nineoldandroids
-keep class com.nineoldandroids.** {*;}

#避免Log打印输出
-assumenosideeffects class android.util.Log {
   public static *** v(...);
   public static *** d(...);
   public static *** i(...);
   public static *** w(...);
}

你用了以上的配置文件,我相信大部分项目都是没有问题的

4. 容易出现的问题总结

4.1 json解析Release版APK报NullPointException错误

在混淆的时候,如果没有在混淆文件中keep掉我们的JavaBean类,那么这个类中的变量可能会被混淆成其他内容,导致在json解析的时候难以准确解析。
解决的办法是找到工程目录下的 proguard-project.txt 混淆配置文件,在文件中添加不需要混淆的类或者包名即可,取消混淆的命令如下:
# 取消com.aoaoyi.model这个包名路径下所有类和子包的混淆
-keep class com.aoaoyi.model.** {*;} 
# 取消混淆Test类
-keep public class com.aoaoyi.model.Test { *; }
# 取消混淆Test类的子类
-keep public class * extends com.aoaoyi.model.Test { *; }
#取消所有类名中包含了“model”的类及其成员的混淆
-keep public class **.*model*.** {*;}
# 取消lgInterface接口实现类的混淆
-keep class * implements com.aoaoyi.lgInterface { *; }
# 取消某个类的内部类的混淆
-keep class com.aoaoyi.model.Test$* {
      *;
}

4.2 使用第三方开源库或者引用其他第三方的SDK包记得要添加混淆规则

如Umeng,hotfix,Glide,RxJava 等吧,一定记得加入混淆规则。

4.3 AndroidMainfest中的类不混淆

四大组件和Application的子类和Framework层下所有的类默认不会进行混淆。自定义的View默认也不会被混淆;所以像网上贴的很多排除自定义View,或四大组件被混淆的规则在Android Studio中是无需加入的。
他的以后我会继续完善这一块,也希望大家多多指点.
推荐:
1. 对Android Studio 生成的包自动重命名
2.用apksigner进行批量签名的脚本

 

标签: Android Proguard 代码混淆
最后更新:2016年12月24日

daozi

这个人很懒,什么都没留下

点赞
< 上一篇
下一篇 >

文章评论

  • coin master spinuri gratis

    Awesome, this is what I was browsing for in yahoo

    2017年9月26日
    回复
  • little snitch 3.7.4

    Great, google took me stright here. thanks btw for post. Cheers!

    2017年9月27日
    回复
  • razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
    取消回复
    搜索
    联系方式

    QQ群:179730949
    QQ群:114559024
    欢迎您加入Android大家庭
    本人QQ:136049925

    赐我一丝安慰
    给我一点鼓励

    COPYRIGHT © 2023 魅力程序猿. ALL RIGHTS RESERVED.

    Theme Kratos Made By Seaton Jiang

    豫ICP备15000477号