Proguard 删除成员字段初始化

Posted

技术标签:

【中文标题】Proguard 删除成员字段初始化【英文标题】:Proguard removing member field initialization 【发布时间】:2015-12-12 06:44:37 【问题描述】:

我的 Proguard 发布版本正在剥离我的成员字段的初始化值。这导致我的默认值丢失,导致我的调试和发布版本之间的行为不同。我怎样才能阻止这种情况发生?

这是我的源代码

public class MyClass implements Serializable 
    private static final long serialVersionUID = 1L;

    @SerializedName("myField")
    private boolean myFieldEnabled = true;

    public boolean isMyFieldEnabled() 
        return myFieldEnabled;
    

    public void setMyFieldEnabled(boolean myFieldEnabled) 
        this.myFieldEnabled = myFieldEnabled;
    

    ...

混淆后的代码如下所示(移除了 setter 和 getter):

public final class ai implements Serializable

    private static final long serialVersionUID = 1L;
    @z(x="myField")
    public boolean myFieldEnabled;

这是我的 build.gradle 中的一个 sn-p:

release 
    minifyEnabled true
    shrinkResources false
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'custom-proguard-rules-optimize.pro'

以下是我的自定义规则(来自 custom-proguard-rules-optimize.pro)中的关键 Proguard 优化规则:

# Disable the "code/allocation/variable" optimizations to workaround a
# Proguard bug.  Source: http://***.com/a/7587680/112705
-optimizations !code/simplification/arithmetic,field/removal/writeonly,!class/merging/*,!code/allocation/variable
-allowaccessmodification

以下是我们正在使用的 Android 默认规则中的关键 Proguard 优化规则(来自 proguard-android-optimize.txt):

-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
-optimizationpasses 5

我检查了the Proguard optimizations documentation,但没有看到涵盖此问题的优化或混淆选项。

更新

!field/* 添加到我们的优化中并没有帮助 - 该字段似乎仍然没有被初始化。希望这种优化已经从 Android 默认的 Proguard 规则中得到了体现... 删除 field/removal/writeonly 没有帮助。 添加 !code/simplification/field 没有帮助。

【问题讨论】:

首先使用“proguard-android.txt”而不是“proguard-android-optimize.txt”。文件中甚至说dex自己做了一些优化,不符合优化的proguard规则。 我想继续使用 Proguard 优化。 正如我所说,dex 无论如何都会进行一些优化。我建议您尝试使用未优化的 proguard 规则版本,如果它从那里产生正确的构建工作。 |||原来优化的规则里面有!field/*,你的规则是不是少了一个感叹号? 尝试为 Gson 添加这个 proguard sn-p。 github.com/krschultz/android-proguard-snippets/blob/master/… 由于proguard对类文件进行了混淆,你如何看待混淆后的代码? 【参考方案1】:

我试图混淆一个可序列化的类,但我没有得到你的问题。我已经使用了默认的proguard-android-optimize.txt和你的优化版本,一切都很好。

原班

public class TestSerializable implements Serializable 
    private static final long serialVersionUID = 1L;

    @SerializedName("myField")
    private boolean myFieldEnabled = true;

    public boolean isMyFieldEnabled() 
        return myFieldEnabled;
    

    public void setMyFieldEnabled(boolean myFieldEnabled) 
        this.myFieldEnabled = myFieldEnabled;
    

在proguard之后

public final class p implements Serializable

    @c(a="myField")
    private boolean a = true;

    public final boolean a()
    
        return this.a;
    

    public final void b()
    
        this.a = false;
    

我有三个建议

尝试将-keep class * implements java.io.Serializable 添加到您的 proguard 文件中,看看会发生什么 在您的代码中验证方法setMyFieldEnabled(false) 不是在每个new MyClass 之后立即调用,否则优化可以决定删除默认值 查看混淆后的序列化类:myFieldEnabled 字段是公开的;所以它可以从任何地方访问。如果 proguard 将代码替换为类似于 ai a = new ai(); ai.myFieldEnabled = true; 的代码,请检查使用 MyClass 的混淆类

【讨论】:

【参考方案2】:

尝试为实现 Serializable 的类声明默认构造函数

public class MyClass implements Serializable 
    private static final long serialVersionUID = 1L;

    @SerializedName("myField")
    private boolean myFieldEnabled;

    private MyClass() 
        myFieldEnabled = true; 
      

    public boolean isMyFieldEnabled() 
        return myFieldEnabled;
    

    public void setMyFieldEnabled(boolean myFieldEnabled) 
        this.myFieldEnabled = myFieldEnabled;
    

对于带有 serailisable 的默认 ProGaurd 配置,请参阅 http://proguard.sourceforge.net/manual/examples.html#serializable

【讨论】:

以上是关于Proguard 删除成员字段初始化的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能访问派生构造函数的成员初始化列表中继承的受保护字段?

C++ 未初始化的结构成员 - 字段不存在

Kotlin类的初始化 ① ( 成员属性 | Kotlin 自动为成员字段生成 getter 和 setter 方法 | 手动设置成员的 getter 和 setter 方法 | 计算属性 )

仅使用 Proguard:无法初始化 DaoConfig => ArrayIndexOutOfBoundsException

go语言学习笔记 — 基础 — 高级数据类型 — 结构体:初始化结构体的成员变量

结构体——内嵌,初始化内嵌结构体,内嵌结构体成员名字冲突