详解Android代码混淆实战

什么是代码混淆:

Android SDK 自带了混淆工具Proguard。它位于SDK根目录\tools\proguard下面。如果开启了混淆,Proguard默认情况下会对所有代码,包括第三方包都进行混淆,可是有些代码或者第三方包是不能混淆的,这就需要我们手动编写混淆规则来保持不能被混淆的部分。

为什么要混淆:

  • 优化java的字节码
  • 减小apk文件的大小,在混淆过程中会删除未使用过的类和成员
  • 代码安全,使类、函数、变量名随机变成无意义的代号形如:a,b,c...之类。防止app被反编译之后能够很容易的看懂代码

怎样使用混淆

在app下面的build.gradle添加使用混淆

buildTypes {
    release {
      //开启混淆,删除无用代码
      minifyEnabled true
      //开启删除无用资源
      shrinkResources true
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    debug {
      //在debug环境下使用混淆,方便调试
      signingConfig signingConfigs.debug
      minifyEnabled false
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
      manifestPlaceholders = [
          // UAT 测试环境
          GETUI_APP_ID  : "FZi793fjp9654LfeDPcR29",
          GETUI_APP_KEY  : "YrVmZT4KTp65hqAtZbCj79",
          GETUI_APP_SECRET: "aLf186Rb617uj7jeNnUB89"
      ]
    }
  }
}

debug环境下使用签名文件,方便在debug环境下调试混淆后的代码

混淆文件 proguard-rules.pro

通用混淆配置(APP通用)

##################################通过混淆配置#################################
# 代码混淆压缩比,在0~7之间,默认为5,一般不做修改
-optimizationpasses 5

# 混合时不使用大小写混合,混合后的类名为小写
-dontusemixedcaseclassnames

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

# 这句话能够使我们的项目混淆后产生映射文件
# 包含有类名->混淆后类名的映射关系
-verbose

# 指定不去忽略非公共库的类成员
-dontskipnonpubliclibraryclassmembers

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

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

# 保留Annotation不混淆
-keepattributes *Annotation*

# 避免混淆泛型
-keepattributes Signature
-keepattributes Exceptions,InnerClasses

-dontnote com.google.vending.licensing.ILicensingService
-dontnote com.android.vending.licensing.ILicensingService

# 抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable
-keepattributes Deprecated,Synthetic,EnclosingMethod

# 重命名抛出异常时的文件名称
-renamesourcefileattribute SourceFile

# 指定混淆是采用的算法,后面的参数是一个过滤器
# 这个过滤器是谷歌推荐的算法,一般不做更改
-optimizations !code/simplification/cast,!field/*,!class/merging/*

APP需要保留的公共部分(通用)

  • 四大组件以及子类;
  • 自定义Application;
  • support下面的继承子类
  • R下面的资源
  • native方法
  • Activity中参数是view的方法
  • 枚举
  • 自定义View
  • 序列化(Parcelable,Serializable)
  • 带有回调函数(On* Listener,On Event)
  • WebView
#############################################
#
# Android开发中一些需要保留的公共部分
#
#############################################

# 保留我们使用的四大组件,自定义的Application等等这些类不被混淆
# 因为这些子类都有可能被外部调用
-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 * extends android.view.View
#-keep public class com.android.vending.licensing.ILicensingService

# 保留support下的所有类及其内部类
-keep class android.support.** {*;}

# 保留继承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**

# 保留R下面的资源
-keep class **.R$* {*;}

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

# 保留在Activity中的方法参数是view的方法,
# 这样以来我们在layout中写的onClick就不会被影响
-keepclassmembers class * extends android.app.Activity{
  public void *(android.view.View);
}

# 保留枚举类不被混淆
-keepclassmembers enum * {
  public static **[] values();
  public static ** valueOf(java.lang.String);
}

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

# 保留Parcelable序列化类不被混淆
-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}

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

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

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

保留自己的项目部分代码不能被混淆(需要更具自己项目)

  1. 网络请求(如果混淆,就会发生字段的错乱,无法正常解析)
  2. 加密类
  3. 数据库实体类
  4. 工具类
  5. 项目中应用到的第三方工具类(如okhttp,eventbus,rxjava等),需要根据具体的工具介绍进行操作
  6. 保留lib和compile引用的第三方jar包不被混淆的方法:

java -keep class 包名.** { *; } 。

如:保留引用的科大讯飞的第三方jar包不被混淆

java -keep class com.iflytek.** { *; }

#网络请求等与外界通信不能混淆
-keep class com.xxxxx.function.**.net.** { *; }
-keep class com.xxxxx.function.**.bean.** { *; }
-keep class com.xxxxx.common.net.** { *; }
-keep class com.xxxxx.common.bean.** { *; }
#加密不能混淆
-keep class com.xxxxx.crypt.** {*;}

#数据库实体类不能混淆
-keep class com.xxxxxx.function.**.dao.** { *; }
#工具类不混淆
-keep class com.xxxxx.common.utils.** { *; }
#greenDAO 3
#-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
#public static java.lang.String TABLENAME;
#}
#-keep class **$Properties
#-dontwarn org.greenrobot.greendao.database.**
#-dontwarn rx.**
#greenDAO 3

# Fresco
#-keep class com.facebook.** {*;}
#-keep interface com.facebook.** {*;}
#-keep enum com.facebook.** {*;}

# OkHttp3
-dontwarn com.squareup.okhttp3.**
-keep class com.squareup.okhttp3.** { *;}
-dontwarn okio.**

#Picasso
#-dontwarn com.squareup.okhttp.**

#zxing
-dontwarn com.google.zxing.**
-keep class com.google.zxing.** { *; }

#webview
-dontwarn com.tencent.**

#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);
}
#如果项目中倒入了de.greenrobot.even的beta1版本,需要添加此行代码
-keepclassmembers class ** {
  public void onEvent*(**);
}

#高德
-dontwarn com.amap.api.**
-keep class com.amap.api.** {*;}

#bugout
-dontwarn com.qamaster.android.**
-dontwarn com.testin.agent.**
-keepattributes InnerClasses
-keep class com.testin.agent.** { *; }
-keepattributes SourceFile, LineNumberTable

#butterknife
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }
-keepclasseswithmembernames class * {
  @butterknife.* <fields>;
}
-keepclasseswithmembernames class * {
  @butterknife.* <methods>;
}

#sharesdk
-keep class cn.sharesdk.**{*;}
-keep class com.sina.**{*;}
-keep class **.R$* {*;}
-keep class **.R{*;}
-dontwarn cn.sharesdk.**
-dontwarn **.R$*
-dontwarn com.tencent.**
-keep class com.tencent.** {*;}

# rx
-dontwarn rx.**
-keepclassmembers class rx.** { *; }
# retrolambda
-dontwarn java.lang.invoke.*

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

#友盟统计
-keep class com.umeng.message.protobuffer.* {
   public <fields>;
     public <methods>;
}
-keep class com.umeng.message.* {
   public <fields>;
     public <methods>;
}

#ormLite
-keep public class * extends com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper
-keep public class * extends com.j256.ormlite.android.apptools.OpenHelperManager
-keepclassmembers class * {@com.j256.ormlite.field.DatabaseField *;}
-keep class com.j256.ormlite.** {*;}

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

#zbar
-keep class net.sourceforge.zbar.**{*;}

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

#身份证ocr
-keep class com.yd.ocr.idcard.** { *; }
-keep class com.googlecode.** { *; }
-keep class org.opencv.** { *; }

#讯飞语音
-keep class com.iflytek.** { *; }

# FastJson 混淆代码
-dontwarn com.alibaba.fastjson.**
-keep class com.alibaba.fastjson.** { *; }
-keepattributes Signature
-keepattributes *Annotation*

至此,代码混淆已经介绍完毕,有问题请及时指出,一起学习,谢谢。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

时间: 2018-08-14

android app进行代码混淆实例详解

接到一个新的任务,对现有项目进行代码混淆.之前对混淆有过一些了解,但是不够详细和完整,知道有些东西混淆起来还是比较棘手的.不过幸好目前的项目不是太复杂(针对混淆这块来说),提前完成--现总结之. 第一部分 介绍下操作流程(eclipse): 1.打开混淆器:找到项目根目录下的project.properties文件,将"#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt"

Android代码混淆的写法总结

Apk文件被反编译出来能被获取到里面的代码.对于这种情况,我们可以对项目代码进行混淆,随机生成难理解的类名,方法名,让代码难以阅读,加大功能被盗取的难度.混淆可以起到压缩Apk,混淆文件,预检,优化的作用. 1. 使用方式,在gradle文件中设置minifyEnabled为true即可开启混淆 buildTypes { release { minifyEnabled ture //是否开启代码混淆 proguardFiles getDefaultProguardFile('proguard-a

Android Studio多渠道批量打包及代码混淆

一.批量打包 1.集成了友盟统计,并在AndroidManifest.xml中添加了如下代码 <meta-data android:name="UMENG_CHANNEL" android:value="${CHANNEL_VALUE}"/> 2.在app的build.gradle的android标签下添加如下代码: productFlavors { myapp {} _360 {} appchina {} hiapk {} } productFlavo

Android应用开发之代码混淆

混淆器(ProGuard) 混淆器通过删除从未用过的代码和使用晦涩名字重命名类.字段和方法,对代码进行压缩,优化和混淆.结果是一个比較小的.apk文件,该文件比較难进行逆向project.因此,当你的应用程序对安全敏感(要求高),比如当你授权应用程序的时候,混淆器是一种重要的保护手段. 混淆器被集成在android 构建系统中,所以你不必手动调用它.同一时候混淆器仅在公布模式下进行构建应用程序的时候才会执行起来,所以在调试模式下构建程序时,你不必处理混淆代码.让混淆器执行起来是可选择的,可是推荐

详解Android的反编译和代码混淆

前言 包括以下内容 要反编译apk需要下面3个工具 反编译资源文件 反编译类文件 代码混淆 要反编译apk需要下面3个工具 1.apktool(资源文件获取) 作用:资源文件获取,可以提取图片文件和布局文件进行使用查看 2.dex2jar(源文件获取) 作用:将APK反编译成java源码(classes.dex转化成jar文件) 3.jd-gui 作用:查看APK中classes.dex转化成的jar文件,即源码文件 下面进行反编译资源文件和类文件: 反编译资源文件 资源文件:包括图片资源.布局

Android实用图文教程之代码混淆、第三方平台加固加密、渠道分发

第一步:代码混淆(注意引入的第三方jar) 在新版本的ADT创建项目时,混码的文件不再是proguard.cfg,而是project.properties和proguard-project.txt. 新建一个项目的时候,会自动生成project.properties和proguard-project.txt文件,无需自己新建,如果你的项目无法自动生成,那么你就要检查一下你的ADT版本了 如果需要对项目进行全局混码,只需要进行一步操作: 将project.properties的中 "#progua

Android 实现代码混淆的实例

Android 实现代码混淆的实例 1.简介 代码混淆(Obfuscated code)亦称花指令,是将计算机程序的代码,转换成一种功能上等价,但是难于阅读和理解的形式的行为. 混淆的目的是为了加大反编译的成本,但是并不能彻底防止反编译. 2.如何开启混淆 通常我们需要找到项目路径下app目录下的build.gradle文件,找到minifyEnabled这个配置,然后设置为true即可,如下: release { minifyEnabled true proguardFiles getDefa

Android 手势 正则匹配图片实例代码

为没有手势的控件(ViewFlipper) 添加手势 xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools

Android自定义手机界面状态栏实例代码

前言 我们知道IOS上的应用,状态栏的颜色总能与应用标题栏颜色保持一致,用户体验很不错,那安卓是否可以呢?若是在安卓4.4之前,答案是否定的,但在4.4之后,谷歌允许开发者自定义状态栏背景颜色啦,这是个不错的体验!若你手机上安装有最新版的qq,并且你的安卓SDK版本是4.4及以上,你可以看下它的效果: 实现这个效果有两个方法: 1.在xml中设置主题或自定义style: Theme.Holo.Light.NoActionBar.TranslucentDecor Theme.Holo.NoActi

Android 底部导航控件实例代码

一.先给大家展示下最终效果 通过以上可以看到,图一是简单的使用,图二.图三中为结合ViewPager共同使用,而且都可以随ViewPager的滑动渐变色,不同点是图二为选中非选中两张图片,图三的选中非选中是一张图片只是做了颜色变化. 二. 需求 我们希望做可以做成这样的,可以在xml布局中引入控件并绑定数据,在代码中设置监听回调,并且配置使用要非常简单! 三.需求分析 根据我们多年做不明确需求项目的经验,以上需求还算明确.那么我们可以采用在LinearLayout添加子View控件,这个子Vie

Android Dialog详解及实例代码

 Android Dialog详解及实例代码 概述: Android开发中最常用的就是Dialog类,除了自定义dialog布局,最多的就是用在弹出对话框.进度条.输入框.单选.复选框. 1.选择对话框: AlertDialog.Builder dialog = new AlertDialog.Builder(this); dialog.setTitle("选择对话框"); dialog.setMessage("请选择确认或取消"); dialog.setCance

Android sd卡读取数据库实例代码

Android sd卡读取数据库实例代码 前言: 本文主要给大家讲解如何利用Android SD卡读取数据库,提供一些代码如下.先在 Manifest 里添加权限: <span style="font-size:16px;"><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name=

Android okhttputils现在进度显示实例代码

OkHttpUtils是一款封装了okhttp的网络框架,支持大文件上传下载,上传进度回调,下载进度回调,表单上传(多文件和多参数一起上传),链式调用,整合Gson,自动解析返回对象,支持Https和自签名证书,支持cookie自动管理,扩展了统一的上传管理和下载管理功能. //download the new app private void downLoadNewApp(NewVersion.XianzaishiRfBean version) { if (StringUtils.isEmpt

Android DrawerLayout实现抽屉效果实例代码

官网:https://developer.android.com/training/implementing-navigation/nav-drawer.html 贴上主要的逻辑和布局文件: activity_main.xml <?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schema