快速搞定 Android Library 工程混淆问题

最近公司项目的库需要发布给第三方使用,代码安全的问题就暴露出来,原来都是交由内部的其他安卓团队处理,但是处理方式非常暴力就是直接不混淆我们的库工程,这样造成代码很容易就被反编译了。我只好硬上研究了一波。

本文记录如何进行安卓Libray工程混淆经验。安卓混淆上的肯定是大名鼎鼎的 ProGuard, 那我们开始吧。

1. ProGuard基础

1.1 ProGuard基本配置

网上关于混淆的学习记录文章已经很多了,这边我整理出了一些基本的配置选项

# 指定代码的压缩级别,值在0-7之间。一般设置5足矣
-optimizationpasses 5

# 打印混淆信息
-verbose

# 代码优化选项,不加该行会将没有用到的类删除,发布的是代码库这个选项需要
# 在做混淆之前最开始会默认对代码进行压缩,为了增加反编译的难度可以选择不压缩 
-dontshrink

# 保留参数的名称和方法,该选项可以保留调试级别的属性。
-keepparameternames

# 过滤泛型,出现类型转换错误时再启用这个。目前的项目暂时无泛型类型,我先注释了
#-keepattributes Signature

# 保护代码中的Annotation不被混淆
-keepattributes *Annotation*

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

# 指定不去忽略非公共的库类(不跳过library中的非public的类)
-dontskipnonpubliclibraryclasses

如果有不合理或更好的选项记得告诉我哟😄非常感谢

1.2 Proguard 关于Keep的关键字

关键字 描述
keep 保留类和类中的成员,防止被混淆或移除
keepnames 保留类和类中的成员,防止被混淆,成员没有被引用会被移除
keepclassmembers 只保留类中的成员,防止被混淆或移除
keepclassmembernames 只保留类中的成员,防止被混淆,成员没有引用会被移除
keepclasseswithmembers 保留类和类中的成员,防止被混淆或移除,保留指明的成员
keepclasseswithmembernames 保留类和类中的成员,防止被混淆,保留指明的成员,成员没有引用会被移除

这边值得注意的是第一种关键字 keep

如果你只想保留类的名字我们可以直接配置如下:

# 如下配置只保留了类的名字MyClass,类的所有成员依然会被混淆
-keep class com.your.class.name.MyClass

# 只有写明具体类成员的匹配规则才能让身体里面的混淆规则生效。
-keep class com.your.class.name.MyClass {*;}

# 举个🌰(例子)如下配置是我用来处理库工程类,期望所有public方法都开放出来,不希望被混淆的配置
-keep class com.your.class.name.MyClass {
      public <fields>;
    public <methods>;
    public static final <fields>;
}

1.3 Proguard通配符

通配符 描述
<field> 匹配类中的所有字段
<method> 匹配类中所有的方法
<init> 匹配类中所有的构造函数
* 匹配任意长度字符,不包含包名分隔符(.)
** 匹配任意长度字符,包含包名分隔符(.)
*** 匹配任意参数类型
... 其他

1.4 Android 特有的 @Keep 标签

默认情况下就算写了@Keep还是会被混淆的,因为默认情况下 Android Studio 并没有开启该选项
在混淆的配置文件 proguard-rules.pro 中加入以下配置:

-keep class android.support.annotation.Keep

-keep @android.support.annotation.Keep class *

-keepclasseswithmembers class * {
    @android.support.annotation.Keep <methods>;
}

-keepclasseswithmembers class * {
    @android.support.annotation.Keep <fields>;
}

-keepclasseswithmembers class * {
    @android.support.annotation.Keep <init>(...);
}

⚠️注意:
目前从网上的一些资料显示如果将 @Keep 添加到类上逻辑上是只不混淆类的名称,但是从实际使用结果上看,如果@Keep 添加到类名上,则整个类无法被混淆。

1.5 保留Native方法

JNI层相关的方法理论上就算没有调用到,也是不可以混淆后直接被移除的,否则 NDK 中采用注册模式的JNI方法的时候会出现注册失败的问题。

-keepclasseswithmembers class * {
    native <methods>;
}

结合Keep关键字说明,通过以上配置可以保留类和类中被指名的native方法成员函数。

1.6 保留Library工程的UI相关类

二次封装的库工程不免有些UI相关的工具类,这部分如果被混淆了,引入方就变成无法正常使用。我们需要对这部分也进行不混淆的控制。

-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
-keepclassmembers class * extends android.app.Activity{
    public void *(android.view.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);
}
# 不混淆资源部分的配置
-keep class **.R$* {*;}

2. 启用混淆

默认在Android Studio的配置下是没有启用的我们需要手动开启。

android {
        ...
    buildTypes {
        release {
            minifyEnabled true // open ProGuard
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

但是这个只有在每次Release打包之后才生效,我们有时候需要在Debug的时候就进行混淆测试,这时我们可以添加一个新的buildType

android {
        ...
    buildTypes {
        release {
            minifyEnabled true // open ProGuard
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debugMini {
            initWith debug
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            matchingFallbacks = ['debug']
        }

    }
}

这样我们就可以在默认Run的时候选择buildVariants指定我们刚刚新加入的debugMini

3. 总结

这篇短短的文章应该可以帮助不少小伙伴跳出深坑,但是更多使用还是需要在工作中去积累。一些小小的体会不求一条混淆命令吃了全部的混淆配置,我们需要精细的配置,通用的配置总会有些不如意地方,那我们就针对单个Class进行一对一的配置,我相信可以得到更好的混淆结果。

本次的分享大概就这些内容了欢迎大家留言一起讨论学习与进步。

谢谢大家。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容