androidStudio 打包与混淆

在gradle中通过makeJar打包

  不同模块的gradle都支持打包功能,application module的build.gradle中引入的是com.android.application插件来打包,而library module的build.gradle中引入的是com.android.library插件进行打包。

一. 基本概念(Project 和 Task)

  Gradle中有两个基本的概念:project和task。每个Gradle的构建由一个project构成,它代表着需要被构建的组件或者构建的整个项目。每个project由一个或者多个task组成。task代表着Gradle构建过程中可执行的最小单元。例如当构建一个组件时,可能需要先编译、打包、然后再生成文档或者发布等,这其中的每个步骤都可以定义成一个task,gradle会创建一个脚本来执行这些task

Task实例:

在app目录的gradle中新建一个任务:

  task hello {
      doLast{
           println "hello world"
      }
 }

通过 gradlew hello  就可以在终端运行这个 task

“doLast” :  为定义的一个映射,意思为在这个task的最后运行。同样还可以在定义doFirst:在task的开始执行

Task中的依赖: dependsOn      

如果B.dependOn A ;     B的执行必须在A执行,在二:项目中在Task中打Jar包  代码中,

dependsOn:['compileReleaseJavaWithJavac']  表示在编译完release的版本之后再执行该任务

二:项目中在Task中打Jar包

   task makeJar(dependsOn:['compileReleaseJavaWithJavac'], type: Jar) {
        archiveName = 'AssistSDK.jar';
        delete 'build/libs/AssistSDK.jar'
        from('build/intermediates/classes/release')
        from(project.zipTree("libs/liteProtobuf.jar"));
        destinationDir = file('sbuild/lib')
        exclude('xxx/BuildConfig.class')
        exclude('xxx/BuildConfig$*.class')
        exclude('**/R.class')
        exclude('**/R$*.class')
        include('xxx/**/*.class')
//      include('com/google/protobuf/**/*.class')
    }

上述代码中  

exclude('xxx/BuildConfig.class')
exclude('xxx/BuildConfig$*.class')

两行代码的目的是为了 去掉jar中的 buildconfig.class (记录的一些参数)

        exclude('**/R.class')
        exclude('**/R$*.class')

这两行代码的效果目前还不是很清楚,

将第三方库的依赖代码 包含到Jar包中,这样 在包含本Jar的时候就不用再去包含第三方的Jar

  from(project.zipTree("libs/liteProtobuf.jar"));

最后在命令行窗口 输入命令:  gradlew makeJar

三、在Task中打混淆的Jar包

   task proguardJar(dependsOn: ['makeJar'], type: proguard.gradle.ProGuardTask) {
        configuration 'proguard-rules.pro'
        String inJar = makeJar.archivePath.getAbsolutePath()
        //输入 jar
        injars inJar
        println "lixiang->>"+inJar
        //输出 jar 的位置和名称
        String outJar = inJar.substring(0, inJar.lastIndexOf(File.separator)) + "/proguard-${makeJar.archiveName}"
        outjars outJar
        println "lixiang->>"+outJar
        //设置不删除未引用的资源(类,方法等)
        dontshrink
    }

混淆proguard-rules.pro文件与混淆规则

# 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
# 是否使用大小写混合
-dontusemixedcaseclassnames
# 是否混淆第三方jar
-dontskipnonpubliclibraryclasses
-dontoptimize
# 预校验
-dontpreverify
# 混淆时是否记录日志
-verbose
# 混淆时所采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
# 保护注解
#-keepattributes *Annotation*
#避免混淆泛型 如果混淆报错建议关掉
#-keepattributes Signature

# 保持哪些类不被混淆
-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.app.IntentService
-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 * extends android.support.v4.app.Fragment

#忽略警告
-ignorewarning

##记录生成的日志数据,gradle build时在本项目根目录输出##

#apk 包内所有 class 的内部结构
-dump class_files.txt
#未混淆的类和成员
-printseeds seeds.txt
#列出从 apk 中删除的代码
-printusage unused.txt
#混淆前后的映射
#-printmapping mapping.txt

########记录生成的日志数据,gradle build时 在本项目根目录输出-end######

#####混淆保护自己项目的部分代码以及引用的第三方jar包library#######
#-libraryjars libs/umeng-analytics-v5.2.4.jar

#三星应用市场需要添加:sdk-v1.0.0.jar,look-v1.0.1.jar
#-libraryjars libs/sdk-v1.0.0.jar
#-libraryjars libs/look-v1.0.1.jar

#如果引用了v4或者v7包
-dontwarn android.support.**
-keep class android.support.** {*; }

####混淆保护自己项目的部分代码以及引用的第三方jar包library-end####

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

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

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

-keepclasseswithmembernames class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembernames class * {
    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 不被混淆并且enum 类也不被混淆
-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();
    public void set*(***);
    public *** get*();
}

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

-keepclassmembers class * {
    public void *ButtonClicked(android.view.View);
}

#不混淆资源类
-keepclassmembers class **.R$* {
    public static <fields>;
}

# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# For using GSON @Expose annotation
-keepattributes *Annotation*

# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }

# Application classes that will be serialized/deserialized over Gson
#-keep class com.google.gson.examples.android.model.** { *; }

#第三方jar包
-keep class com.nostra13.universalimageloader.** { *; }
-keep class com.android.volley.** {*; }
-keep class org.apache.http.** {*; }

2,内嵌类(尤为注意)

内嵌类经常会被混淆,结果在调用的时候为空就崩溃了,最好的解决方法就是把这个内嵌类拿出来,单独成为一个类。如果一定要内置,那么这个类就必须在混淆的时候保留,比如如下:

# 保留内嵌类不被混淆
-keep class com.example.xxx.MainActivity$* { *; }

这个$符号就是用来分割内嵌类与其母体的标志。

(实际遇到匿名内部类被混淆,调用时找不到接口。 通过把匿名内部类设置为 内部类,然后保留不混淆)

四、 dependencies 中六种依赖

Android Studio引用第三方库很方便,只需要一句代码就可以搞定,几种引用第三方库的方式,总结一下:

方式:1:它就会自动把这个包下载下来,并且引用它。节省git空间,而且修改版本也很方便。

  compile 'com.android.support:support-v4:23.3.0'    // 实际使用中经常会用 xxxx:+    insteadof version number

方式2:引用libs下所有jar包

  compile fileTree(dir: 'libs', include: ['*.jar'])

方式3:引用一个jar

  compile files('libs/fastjson-1.1.53.android.jar')

方式4:引用一个aar文件,注意并不能像 方式2 那样自动引用全部的aar,而需要对每个aar分别进行引用。

  compile(name: 'aar_file_name', ext: 'aar')

方式5:引用库类型的项目

  compile project(':xxxsdk')

方式6:仅仅在编译时使用,但最终不会被编译到apk或aar里

  provided files('libs/glide-3.7.0.jar')

Compile

compile是对所有的build type以及favlors都会参与编译并且打包到最终的apk文件中。

Provided

Provided是对所有的build type以及favlors只在编译时使用,类似eclipse中的external-libs,只参与编译,不打包到最终apk。

APK

只会打包到apk文件中,而不参与编译,所以不能再代码中直接调用jar中的类或方法,否则在编译时会报错

Test compile

Test compile 仅仅是针对单元测试代码的编译编译以及最终打包测试apk时有效,而对正常的debug或者release apk包不起作用。

Debug compile

Debug compile 仅仅针对debug模式的编译和最终的debug apk打包。

Release compile

Release compile 仅仅针对Release 模式的编译和最终的Release apk打包。

查看依赖结构命令  ./gradlew -q app:dependencies

gredle 命令说明:

https://docs.gradle.org/current/userguide/command_line_interface.html#para:commandline_dependency_report

混淆规则参考:

  http://blog.csdn.net/nature_day/article/details/51545849

  http://www.jianshu.com/p/158aa484da13

打包

      http://unclechen.github.io/2015/10/25/Gradle%E5%AE%9E%E8%B7%B5%E4%B9%8B%E6%89%93%E5%8C%85jar+Log%E5%BC%80%E5%85%B3%E8%87%AA%E5%8A%A8%E5%85%B3%E9%97%AD/

原文地址:https://www.cnblogs.com/NeilZhang/p/7128136.html