混淆 Android 文件

mPaaS Android 客户端开发的应用程序是通过 Java 代码编写而成,而 Java 代码易被反编码,因此为了保护 Java 源代码,需要使用 ProGuard 混淆 Android 文件。

ProGuard 是一个压缩、优化和混淆 Java 字节码文件的工具。

  • 压缩 指检测以及删除没有用到的类、字段、方法以及属性。

  • 优化 指分析以及优化方法的字节码。

  • 混淆 指使用无意义的短变量,对类、变量、方法进行重命名。

使用 ProGuard 可以让代码更精简,更高效,也更难被逆向或破解。

前置条件

您已经配置 mPaaS 工程。

关于此任务

采用组件化方案的 mPaaS 工程,每一个 bundle 的编译产物都是一个已经混淆的 dex 文件,所以配置混淆文件是以 bundle 工程为单位而进行的。Portal 工程通常没有代码,不需要开启混淆。

代码示例

  • Gradle 配置

    android {
      compileSdkVersion 23
      buildToolsVersion "19.1.0"
    
      defaultConfig {
          applicationId "com.youedata.xionganmaster.launcher"
          minSdkVersion 15
          targetSdkVersion 23
          versionCode 1
          versionName "1.0"
      }
      buildTypes {
          release {
              // 混淆开关,是否混淆
              minifyEnabled true
              // 混淆文件列表,混淆规则配置
              proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
          }
      }
      lintOptions {
            checkReleaseBuilds false
            // Or, if you prefer, you can continue to check for errors in release builds,
            // but continue the build even when errors are found:
            abortOnError false
      }
    }
  • 混淆文件示例

    下列混淆是一个基本示例(如果要添加额外的第三方库,需要加入其它混淆,通常配置文件可在第三方库的官网中找到):

      # Add project specific ProGuard rules here.
      # By default, the flags in this file are appended to flags specified
      # in ${sdk.dir}/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 [Shrink your code and resources](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
      -dontusemixedcaseclassnames
      -dontskipnonpubliclibraryclasses
      -dontpreverify
      -verbose
      -ignorewarnings
      -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
    
      -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 com.android.vending.licensing.ILicensingService
      -keep public class com.alipay.mobile.phonecashier.*
      -keepnames public class *
      -keepattributes SourceFile,LineNumberTable
      -keepattributes *Annotation*
    
      #-keep public class * extends com.alipay.mobile.framework.LauncherApplicationAgent {
      #    *;
      #}
    
      #-keep public class * extends com.alipay.mobile.framework.LauncherActivityAgent {
      #    *;
      #}
    
      -keepclasseswithmembernames class * {
          native <methods>;
      }
    
      -keepclasseswithmembernames class * {
          public <init>(android.content.Context, android.util.AttributeSet);
      }
    
      -keepclasseswithmembernames class * {
          public <init>(android.content.Context, android.util.AttributeSet, int);
      }
    
      -keepclassmembers enum * {
          public static **[] values();
          public static ** valueOf(java.lang.String);
      }
    
      -keep class * extends java.lang.annotation.Annotation { *; }
      -keep interface * extends java.lang.annotation.Annotation { *; }
    
      -keep class * implements android.os.Parcelable {
        public static final android.os.Parcelable$Creator *;
      }
    
      -keep public class * extends android.view.View{
          !private <fields>;
          !private <methods>;
      }
    
      -keep class android.util.**{
           public <fields>;
           public <methods>;
       }
    
      -keep public class  com.squareup.javapoet.**{
          !private <fields>;
            !private <methods>;
      }
      -keep public class   javax.annotation.**{
              !private <fields>;
              !private <methods>;
        }
      -keep public class   javax.inject.**{
           !private <fields>;
           !private <methods>;
       }
      -keep interface **{
        !private <fields>;
        !private <methods>;
      }
      # for dagger
        -keep class * extends dagger.internal.Binding
        -keep class * extends dagger.internal.ModuleAdapter
    
        -keep class **$$ModuleAdapter
        -keep class **$$InjectAdapter
        -keep class **$$StaticInjection
    
        -keep class dagger.** { *; }
    
        -keep class javax.inject.**{ *; }
        -keep class * extends dagger.internal.Binding
        -keep class * extends dagger.internal.ModuleAdapter
        -keep class * extends dagger.internal.StaticInjection
    
      # for butterknife
        -keep class butterknife.* { *; }
        -keep class butterknife.** { *; }
        -dontwarn butterknife.internal.**
        -keep class **$$ViewBinder { *; }
    
        -keepclasseswithmembernames class * {
            @butterknife.* <fields>;
        }
    
        -keepclasseswithmembernames class * {
            @butterknife.* <methods>;
        }
    说明

    如果在您的 bundle 工程中定义了框架类LauncherApplicationAgentLauncherActivityAgent,请注意进行防混淆设置

  • 避免混淆通用组件

    如果在metainfo.xml中注册了通用组件,编译时会检查这些组件是否存在,请避免这些组件被混淆,否则会编译失败。例如注册了以下组件:

       <metainfo>
       <service>
           <className>com.mpaas.cq.bundleb.MyServiceImpl</className>
           <interfaceName>com.mpaas.cq.bundleb.api.MyService</interfaceName>
           <isLazy>true</isLazy>
       </service>
    </metainfo>

    请在混淆配置中添加:

      -keep class com.mpaas.cq.bundleb.MyServiceImpl
      -keep class com.mpaas.cq.bundleb.api.MyService