IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android混淆大法 -> 正文阅读

[移动开发]Android混淆大法

Android混淆大法

本文涉及内容:
1.混淆的基本介绍,混淆的基本配置及示例
2.如何进行多模块的混淆
3.实际项目中混淆时会遇到的问题
4.混淆后如何进行debug和日志查看



前言

混淆,主要作用就是对把项目的原本清晰的类名、方法名等转换为难易理解的a/b/c名字,不会改变原有的代码逻辑,但是会增大阅读难度。如果是为了应用安全,通常直接使用应用加固处理。但是,有些情况下,无法使用加固,但为了防止程序主要逻辑泄露,混淆还是很有必要的。

Android SDK 自带了混淆工具Proguard。它位于SDK根目录\tools\proguard下面。如果开启了混淆,Proguard默认情况下会对所有代码,包括第三方包都进行混淆,但并不是所有的文件都可以进行混淆,有些文件混淆后,会影响程序运行,这些是需要避免混淆的,配置文件的主要作用也即是如此。


一、gradle 混淆开启

Proguard是android Studio自带的混淆工具,通过gradle可以进行配置,主要作用是对java代码的混淆优化和对资源文件的压缩,这些配置都是默认开启的。

android {
    ......
    defaultConfig {
        ......
    }
    buildTypes {
        release {
            minifyEnabled true      // 开启代码混淆
            zipAlignEnabled true    // 开启Zip压缩优化
            shrinkResources true    // 移除未被使用的资源
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//代码混淆的主配置文件
        }
    }
    ......
}

二、混淆规则

1.模板示例

模板可以直接使用,想要深入理解的可以继续向下看

# --------------------------------------------基本指令区--------------------------------------------#
-ignorewarning                                      # 忽略警告
-optimizationpasses 5                               # 指定代码的压缩级别(0~7之间,默认为5)
-dontusemixedcaseclassnames                         # 不使用大小写混合(windows大小写不敏感,建议加入)
-dontskipnonpubliclibraryclasses                    # 不混淆非公共的库的类
-dontskipnonpubliclibraryclassmembers               # 不混淆非公共的库的类的成员
-dontpreverify                                      # 混淆时不做预校验(Android不需要预校验,去掉可以加快混淆速度)
-verbose                                            # 混淆时记录日志(混淆后会生成映射文件)

#混淆时所采用的算法(谷歌推荐算法)
-optimizations !code/simplification/arithmetic,!field,!class/merging,!code/allocation/variable

#添加支持的jar(引入libs下的所有jar包)
-libraryjars libs(*.jar;)

#将文件来源重命名为“SourceFile”字符串
-renamesourcefileattribute SourceFile

#保持注解不被混淆
-keepattributes *Annotation*
-keep class * extends java.lang.annotation.Annotation {*;}

#保持泛型不被混淆
-keepattributes Signature
#保持反射不被混淆
-keepattributes EnclosingMethod
#保持异常不被混淆
-keepattributes Exceptions
#保持内部类不被混淆
-keepattributes Exceptions,InnerClasses
#抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable

#------------------------------------默认保留区--------------------------------------#
#保持四大组件不被混淆
-keep public class * extends android.app.Fragment
-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

#保持 Google 原生服务需要的类不被混淆
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService

# 保留support下的所有类及其内部类,AndroidX
-keep class android.support.** {*;}
-dontwarn android.support.**
-keep interface android.support.** { *; }
-keep class androidx.** {*;}
-keep interface androidx.** {*;}
-keep public class * extends androidx.**
-dontwarn androidx.**

# 保留继承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**
-keep class com.google.android.material.** {*;}
-dontwarn com.google.android.material.**
-dontnote com.google.android.material.**


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

# 保留我们自定义控件(继承自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);
}

#保留指定格式的构造方法不被混淆
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

#保留在Activity中的方法参数是view的方法(避免布局文件里面onClick被影响)
-keepclassmembers class * extends android.app.Activity {
    public void *(android.view.View);
}

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

#保持R(资源)下的所有类及其方法不能被混淆
-keep class **.R$* { *; }


#保持 Parcelable 序列化的类不被混淆(注:aidl文件不能去混淆)
-keep class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator *;
}

#需要序列化和反序列化的类不能被混淆(注:Java反射用到的类也不能被混淆)
-keepnames class * implements java.io.Serializable

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

#保持 BaseAdapter 类不被混淆
-keep public class * extends android.widget.BaseAdapter { *; }
#保持 CusorAdapter 类不被混淆
-keep public class * extends android.widget.CusorAdapter{ *; }

#-------------------------------------webView区---------------------------------------#

#保护代码中的jsinterface注解不被混淆
-keepattributes *JavascriptInterface*

#WebView处理,项目中没有使用到webView忽略即可
#保持AndroidJavaScript进行交互的类不被混淆
-keep class **.AndroidJavaScript { *; }
-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.WebChromeClient {
     public void *(android.webkit.WebView,java.lang.String);
}

#网络请求相关
-keep public class android.net.http.SslError

#-------------------------------------删除代码区(可不配置)--------------------------------------#
删除代码中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(...);
}

#---------------------------------1.实体类---------------------------------
#--------------------------------------------------------------------------
#---------------------------------2.与JS交互的类-----------------------------
#--------------------------------------------------------------------------
#---------------------------------3.反射相关的类和方法-----------------------
#--------------------------------------------------------------------------
#---------------------------------4.内部类--------------------------------
#--------------------------------------------------------------------------
#---------------------------------5.第三方依赖----------------------------------------

2.重点问题注意

(1)混淆后webview无法使用或是JSBridge接口无法使用

注意,查看是否配置了webview的免混淆

#保护代码中的jsinterface注解不被混淆
-keepattributes *JavascriptInterface*

#WebView处理,项目中没有使用到webView忽略即可
#保持AndroidJavaScript进行交互的类不被混淆
-keep class **.AndroidJavaScript { *; }
-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.WebChromeClient {
     public void *(android.webkit.WebView,java.lang.String);
}

(2)AIDL接口无法调用

所有的aidl文件都需要免混淆

-keep class "你的aidl文件类名"{*;}

例如:

-keep class com.demo.superfan.testAidl{*;}

(3)内部类导致的错误

排查下是否有内部类,内部类需要单独配置,无论这个内部类所在的类是否免混淆,都需要配置

-keep class "内部类所在类的文件类名"$*{*;}

例如:

-keep class com.demo.DemoUtil$DemoInner{*;}-keep class com.demo.DemoUtil$*{*;}//保持DemoUtil中的所有内部类免混淆或移除

(4)实体类导致的问题

通常的实体类转json时,如果实体类混淆后,都会出现问题。 需要将所有实体类进行配置

(5)多个modle的混淆问题

多个modle的混淆有两种方式:

  • 一、直接把所有的混淆配置都写在主modle中;
  • 二、每个modle配置各自的混淆配置
    推荐使用对每个model进行各自的混淆配置,即使是各个modle被其他项目引用,混淆配置也会直接跟随。

但是,对每个modle进行配置时,需要注意:

  • 主modle的gradle中按上述方式进行配置;
  • 子modle的gradle中按以下方式进行配置:
plugins {
    id 'com.android.library'
}

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        ... ...
    }

    buildTypes {
        release {
            minifyEnabled true
            consumerProguardFiles 'proguard-rules.pro'
        }
        debug {
            minifyEnabled false
            consumerProguardFiles 'proguard-rules.pro'
        }
    }
    ... ...
}

子Model的混淆配置使用consumerProguardFiles 'proguard-rules.pro'

(6)混淆后打包,错误日志也是混淆后的,找不到类

混淆后,由于class的类名变成了abc,导致日志文件输出也变成了com.demo.a.b.c类似这种,对于排查问题造成了很大的困难。不过,不用担心,早在我们混淆时,编译器就为我们生成了一个混淆关系对应文件。在这里:
在这里插入图片描述
内容如下:

 com.catchai.superfan.proguardtestdemo.IAIDLCallback -> a.a.a.a.a:

即是,将com.catchai.superfan.proguardtestdemo.IAIDLCallback混淆为a.a.a.a.a
因此,如果是正式发包,最好打包时,将release包和mapping一起保存好,方便后期排查线上日志。

三、深入理解

1.混淆的输出文件

有心的童鞋可能会发现,开启了混淆的项目,在androidStudio打包时,在modle的build/outputs下有一个mapping文件夹,这里面便是混淆的输出文件。
一般有四个:configuration.txt、mapping.txt、seeds.txt、usage.txt

(1)configuration.txt

通常是混淆的配置文件,基本和modle下的proguard-rules.pro文件一致。

(2)mapping.txt

混淆打包后的关系对应文件,混淆的名字映射到原始代码的名字。此文件对于后期排查日志很重要。

(3)seed.txt

keep保持的内容,文件内是proguard-rules.pro配置文件中要保持的不被混淆的内容。此文件有助于排查我们的 proguard-rules.pro 配置文件中的配置内容是否生效。

(4)usage.txt

没有引用,被移除的代码


那么这四个文件是如何生成的呢?
在这里插入图片描述
其实简单来说就是:

  • 编译器首先读取proguard-rules.pro查看哪些是需要保持的(不需要混淆),生成seeds.txt文件;
  • 然后进行压缩,删减哪些没有被引用的类,生成usage.txt文件;
  • 接着开始混淆,把对应关系保存到mapping.txt文件中。

2.混淆的规则

关键字

在这里插入图片描述
理解:

  • 虽然keep是保留类和类中的成员不被混淆和移除。但是内部类不输入类和类成员的范畴。

通配符

在这里插入图片描述

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-07-31 16:45:30  更:2021-07-31 16:47:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/6 23:07:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码