android 代码混淆

整理一下关于android代码混淆,

android 中混淆采用的是ProGuard工具,默认时会混淆项目内所有源代码,但是代码中有些内容是不能被混淆的否则程序会无法运行。那么其实开发者所要做的事情就是要编写脚本告诉ProGuard哪些方法,类,接口等不能使用混淆,保证程序能正常运行。

其实编写混淆说明脚本也没啥难度主要就是稍有一点麻烦,为了在一定程度上保护代码还是值得。

关于详细内容可以参考官方文档:http://proguard.sourceforge.net/index.html#manual/usage.html。(友情提示:由于墙的原因,只能FQ才能正常访问,可恶的GWF).

其实在google已经在sdk/tools/proguard/proguard-android.txt文件内已经给出了几种,但在实际的项目中复杂性,这个配置文件并不详细,项目还需要开发者在添加一下内容。这里我先说明一下混淆前的注意事项(即不能被混淆内容):

需要保留的内容如下:

Android系统组件,系统组件有固定的回调方法被系统调用的
被Resource 文件引用到的,名字已经固定,也不能混淆,比如自定义的View ,
Parcelable ,Serializable,需要使用android 序列化的。
enum 枚举 ,系统需要处理枚举的固定方法。
native 本地方法,不能修改本地方法名
annotations 注释
使用反射方法的
使用第三方库引用不能混淆
运行时动态调用的函数或者成员变量
代码依赖于系统的接口,比如被系统代码调用的回调方法,这种情况最复杂,最费时间地方。

如果你不确定哪些需要手动配置,可以以默认的配置生成程序,当运行中发现ClassNotFoundException异常时,即可找到哪个类不该被混淆。
所以使用proguard时,我们需要有个配置文件告诉proguard 那些 元素是不能混淆的。

下面简单介绍一下如何编写内容:
1,不混淆packagecom.xiaoyu.example下的所有类/接口
-keep class com. xiaoyu.example.** { * ; }

2,不混淆com. xiaoyu.example.Test类:
-keep class com. xiaoyu.example.Test { * ;}
如果希望不混淆某个接口,则把上述命令中的class替换为interface即可。

3,不混淆com. xiaoyu.example.Test类的子类
-keep public class * extendscom.ticktick.example.Test

4,不混淆com. xiaoyu.example.TestInterface的实现
-keep class *implements com.xiaoyu.example.TestInterface {
   public static final com.xiaoyu.example.TestInterface$doSome *;
}

5,不混淆com. xiaoyu.example.Test类的setTest方法:
-keepclassmembers class
com. xiaoyu.example.Test {
   public void setTest (java.lang.String);
}
这里一个值得注意的问题是,所有类都要写全称,就是包名.类名,String要写成java.lang.String,否则还是会被混淆。

6,忽略引用的第三方库时需要添加dontwarn,因为默认情况下proguard会检查每一个引用是否正确,但是第三方库里往往有些不会用到的类,没有正确引用,所以如果不配置的话,系统会报错,如下配置
-libraryjars   libs/android-support-v4.jar
-dontwarn android.support.v4.**     
-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

说明:-dontwarn和-keep结合参数使用来保持第三方库中的类而不乱,
      -dontwarn android.support.v4.**,  意思是保持android.support.v4.**这个包里面的所有类和所有方法而不混淆
      -keep android.support.v4.** { *;} ,意思是ProGuard不要警告找不到android.support.v4.**这个包里面的类的相关引用

下面介绍一点官网上的一点语法内容:
keep   保持类类成员(Classes and class members)
keepclassmembers   仅保持类成员(Class members only)
keepclasseswithmembernames  保持类和类成员,如果类成员存在(Classes and class members, if class members present)
keepattributes  保留部分属性

每个这些-keep后跟确定的类和类成员说明字段和方法),其应该被应用。
如果你不知道你需要的选项你应该简单地使用-keep这将确保指定的类和类成员收缩步骤不会被删除并且在混淆改名

关于通配符,

1,?匹配一个类名称之中的任何一个单个字符,但是必须在同一个包目录下。例如,“mypackage.Test?”可以匹配“mypackage.Test1”和“mypackage.Test2”,但是不能匹配“mypackage.Test12”(只能是单个字符)。
2,*可以匹配任何包含特殊名称的类,但是必须在同一个包内。例如,“mypackage.*Test*,可以匹配“mypackage.Test”和“mypackage.YourTestApplication”,而不是“mypackage.mysubpackage.MyTest”。或者更一般地,“mypackage.*。*”可以匹配所有类在“mypackage”同一个包内,而不是在它的子包。
3,**任何部分的类名相匹配,可能包含任意数量的包(可以不再同一个包)。例如,“**.Test”匹配的所有软件包的所有Test类,除了根包。或者,“mypackage.**”,在“mypackage包内以及在其子包内可以匹配的所有相关的类。

<fields>匹配任意字段.
<methods> 匹配任意方法.
* . 匹配任意自动或方法
注意以上通配符没有返回值类型,只有<init>通配符有一个参数列表。

 

2017-08-11更新:

Android studio内使用混淆,

在module目录下的proguard-rules.pro写入混淆规则

我的项目配置:

# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in D:\android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}
-optimizationpasses 5                                                           # 代码混淆压缩比,在0~7之间,默认为5
-dontusemixedcaseclassnames                                                     # 混合时不使用大小写混合,混合后的类名为小写
-dontskipnonpubliclibraryclasses                                                # 指定不去忽略非公共库的类,第三方jar
-dontpreverify                                                                  # 不做预校验,preverify是proguard的四个步骤之一,去掉这一步能够加快混淆速度
-verbose                                                                        # 混淆时能够使我们的项目混淆后产生映射文件
# 指定混淆是采用的算法,后面的参数是一个过滤器
# 这个过滤器是谷歌推荐的算法,一般不做更改
-optimizations !code/simplification/cast,!field/*,!class/merging/*

# 避免混淆泛型
-keepattributes Signature
# 保留Annotation不混淆
-keepattributes *Annotation*,InnerClasses
# 抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable

-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 com.android.vending.licensing.ILicensingService
-keep public class com.google.vending.licensing.ILicensingService
-keep public class * extends android.view.View
# 保留support下的所有类及其内部类
-keep class android.support.** {*;}
-keep public class * extends android.support.annotation.**
# 保留R下面的资源
-keep class **.R$* {*;}
-keepclassmembers class **.R$* {
    public static <fields>;
}
# 保留本地native方法不被混淆
-keepclasseswithmembernames class * {
    native <methods>;
}
# 保持枚举 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 不被混淆
-keepnames class * implements java.io.Serializable
# webView处理,项目中没有使用到webView忽略即可
-keepclassmembers class fqcn.of.javascript.interface.for.webview {
    public *;
}
-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.webViewClient {
    public void *(android.webkit.webView, jav.lang.String);
}

-dontwarn eclipse.paho.mqttv3.**
-keep class eclipse.paho.mqttv3.** { *; }
-keep public class * extends eclipse.paho.mqttv3.**

-dontwarn android.support.appcompat-v7.**
-keep class android.support.appcompat-v7.** { *; }
-keep public class * extends android.support.appcompat-v7.**

-dontwarn android.support.v4.**
-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

-dontwarn android.support.v7.**
-keep class android.support.v7.** { *; }
-keep interface android.support.v7.app.** { *; }
-keep public class * extends android.support.v7.**

-keepclassmembers public class * extends android.widget.TextView {
   void set*(***);
   *** get*();
}

-keep class com.xinju.publishersystem.model.** { * ; }
#-keep class com.xinju.publishersystem.tools.** { * ; }
-keep class com.xinju.publishersystem.mqtt { * ;}

#-----------处理反射类---------------

#-----------处理js交互---------------

#-----------处理第三方依赖库---------
# ButterKnife
-keep public class * implements butterknife.Unbinder {
    public <init>(**, android.view.View);
}
-keep class butterknife.*
-keepclasseswithmembernames class * {
    @butterknife.* <methods>;
}
-keepclasseswithmembernames class * {
    @butterknife.* <fields>;
}
# EventBus
-keepattributes *Annotation*
-keepclassmembers class ** {
    @org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
# OkHttp
-dontwarn okhttp3.**
-dontwarn javax.annotation.Nullable
-dontwarn javax.annotation.ParametersAreNonnullByDefault
-keep class okhttp3.** { *; }
-keep public class * extends okhttp3.**
# Okio
-dontwarn okio.**
-keep class okio.** { *; }
-keep public class java.nio.* { *; }
# Retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
# Picasso
-dontwarn com.squareup.picasso.**
-keep class com.squareup.picasso.** { *; }
# Retrolambda
-dontwarn java.lang.invoke.*
# rxJava
-dontwarn io.reactivex.**
-keep class io.reactivex.** { *; }
# RxJava RxAndroid
-dontwarn io.reactivex.android.**
-keep class io.reactivex.android.** { *; }
-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;
}
-dontnote rx.internal.util.PlatformDependent
# Gson
-keep class com.google.gson.** { *; }
-keep public class * extends com.google.gson.**
# Jackson
-dontwarn org.codehaus.jackson.**
-dontwarn com.fasterxml.jackson.databind.**
-keep class org.codehaus.jackson.** { *;}
-keep class com.fasterxml.jackson.** { *; }

 

gradle编译配置:

buildTypes {
        debug {
            versionNameSuffix "-debug"
            minifyEnabled false
            zipAlignEnabled false
            shrinkResources false
//            signingConfig signingConfigs.assist
        }

        release {
            //混淆
            minifyEnabled true
            //Zipalign优化
            zipAlignEnabled true
            // 移除无用的resource文件
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

    }

 签名打包好就可以混淆了。


更多高级介绍

https://drakeet.me/android-advanced-proguard-and-security/
https://github.com/drakeet/proguard-dict
https://github.com/shwenzhang/AndResGuard


posted @ 2014-10-25 22:48  HappyCode002  阅读(667)  评论(0编辑  收藏  举报