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

Posted

技术标签:

【中文标题】仅使用 Proguard:无法初始化 DaoConfig => ArrayIndexOutOfBoundsException【英文标题】:Only using Proguard: Could not init DaoConfig => ArrayIndexOutOfBoundsException 【发布时间】:2017-06-20 19:01:33 【问题描述】:

我正在使用以下 ProGuard 规则:

-keepclassmembers 类 * 扩展 org.greenrobot.greendao.AbstractDao *; -保持类**$属性 -保留类 org.greenrobot.greendao.** -keepclassmembers 类 org.greenrobot.greendao.** *; # 如果不使用 SQLCipher: -dontwarn org.greenrobot.greendao.database.** # 如果你不使用 RxJava: -dontwarn rx.**

启动应用程序时,我收到以下崩溃日志:

java.lang.RuntimeException:无法创建应用程序 my.app.package.MyApplication:org.greenrobot.greendao.DaoException:无法初始化 DAOConfig 在 android.app.ActivityThread.handleBindApplication(ActivityThread.java:4569) 在 android.app.ActivityThread.access$1500(ActivityThread.java:148) 在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 在 android.os.Handler.dispatchMessage(Handler.java:102) 在 android.os.Looper.loop(Looper.java:135) 在 android.app.ActivityThread.main(ActivityThread.java:5272) 在 java.lang.reflect.Method.invoke(本机方法) 在 java.lang.reflect.Method.invoke(Method.java:372) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:909) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:704) 原因:org.greenrobot.greendao.DaoException:无法初始化 DAOConfig 在 org.greenrobot.greendao.internal.DaoConfig.(未知来源) 在 org.greenrobot.greendao.AbstractDaoMaster.registerDaoClass(未知来源) 在 my.app.package.database.model.DaoMaster.(​​未知来源) 在 my.app.package.database.model.DaoMaster.(​​未知来源) 在 my.app.package.ZamgApplication.onCreate(未知来源) 在 android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1011) 在 android.app.ActivityThread.handleBindApplication(ActivityThread.java:4566) 在 android.app.ActivityThread.access$1500(ActivityThread.java:148) 在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 在 android.os.Handler.dispatchMessage(Handler.java:102) 在 android.os.Looper.loop(Looper.java:135) 在 android.app.ActivityThread.main(ActivityThread.java:5272) 在 java.lang.reflect.Method.invoke(本机方法) 在 java.lang.reflect.Method.invoke(Method.java:372) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:909) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:704) 引起:java.lang.ArrayIndexOutOfBoundsException: length=5;索引=6 在 org.greenrobot.greendao.internal.DaoConfig.reflectProperties(未知来源) 在 org.greenrobot.greendao.internal.DaoConfig.(未知来源) 在 org.greenrobot.greendao.AbstractDaoMaster.registerDaoClass(未知来源) 在 my.app.package.database.model.DaoMaster.(​​未知来源) 在 my.app.package.database.model.DaoMaster.(​​未知来源) 在 my.app.package.ZamgApplication.onCreate(未知来源) 在 android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1011) 在 android.app.ActivityThread.handleBindApplication(ActivityThread.java:4566) 在 android.app.ActivityThread.access$1500(ActivityThread.java:148) 在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 在 android.os.Handler.dispatchMessage(Handler.java:102) 在 android.os.Looper.loop(Looper.java:135) 在 android.app.ActivityThread.main(ActivityThread.java:5272) 在 java.lang.reflect.Method.invoke(本机方法) 在 java.lang.reflect.Method.invoke(Method.java:372) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:909) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:704)

在没有 ProGuard 的情况下编译应用程序时,一切正常。

我在这里缺少任何配置吗?我在 Google 上找不到任何内容...

【问题讨论】:

fwiw:又挖了 2 天,我决定将数据库切换到 realm.io 【参考方案1】:

你的项目中有keepEntity 类吗? 如果没有,keep 你把你的Entity 类的包 像这样-keep class com.xxx.xxx.model.* *;

【讨论】:

是的,我愿意。出于测试目的,我什至没有混淆我的整个数据库包,但无济于事。由于经过一周的尝试和搜索后无法解决此问题,我切换到了 realm.io。他们在 lib 中拥有所有 proguard 规则,开发人员无事可做。 完美解决了我的问题!这个proguard规则应该加到greendao官方文档推荐的proguard规则中。greenrobot.org/greendao/documentation/…【参考方案2】:

我遇到了同样的问题

看来-keep class只保证类本身被保留,但其成员仍有可能被移除

在我的情况下,CustomDao$Properties 类的一些静态最终字段被删除,最终导致索引越界异常

替换

-keep class **$Properties

-keep class **$Properties  *; 

解决了我的问题

【讨论】:

在使用 R8 时,我的应用程序开始因此问题而崩溃。这解决了它。谢谢! ? 正如@mrstif 所说,这个问题在R8 发布后开始意外发生(尽管我不知道它是否被使用),这是解决它的唯一方法。而且我相信它适用于更多的案例,而不仅仅是这个特定的 GreenDao 问题。【参考方案3】:

好像是指令:

-keep class org.greenrobot.greendao.**

没有被应用。正如您在日志中看到的那样,如下行:

at org.greenrobot.a.c.a.a(Unknown Source)
at org.greenrobot.a.c.a.(Unknown Source) 
at org.greenrobot.a.b.a(Unknown Source) 

显示org.greenrobot.greendao 下的类在您的 ProGuard 指令告诉(或应该告诉)ProGuard 保持不变时被混淆。要解决此问题,请确保在您的 Android 配置的 proguardFiles 部分中正确引用了定义此内容的 ProGuard 规则文件:

proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

并且您的发布配置使用相同的proguard-rules.pro 文件。

【讨论】:

谢谢,我更新了我的规则集,几乎所有东西都来自 greendao。日志文件现在有点冗长,但错误不断发生。我用新的日志和规则更新了我的问题。【参考方案4】:

你可以试试这个

-dontwarn org.greenrobot.greendao.**
-keepclassmembers class * extends de.greenrobot.dao.AbstractDao 


-keep class **$Properties

使用更新版本

apply plugin: 'org.greenrobot.greendao'

compile 'org.greenrobot:greendao:3.2.0'

在Here 和 here 和*** 上列出了相同的问题

【讨论】:

【参考方案5】:
// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
/** 
 * DAO for table "addresses".
*/
public class DbAddressDao extends AbstractDao<DbAddress, Long> 

    public static final String TABLENAME = "addresses";

    /**
     * Properties of entity DbAddress.<br/>
     * Can be used for QueryBuilder and for referencing column names.
    */
    public static class Properties 
        public final static Property Id = new Property(0, long.class, "id", true, "_id");
        public final static Property AddressLine = new Property(3, String.class, "addressLine", false, "ADDRESS_LINE");
    

如果您查看 GreenDao 库自动生成的 Dao 类 您会注意到它创建了一个名为 Properties 的内部类,其中包含您在数据库表中的每个字段,如上面的示例。

您注意这些字段,您会注意到代码的任何部分都没有使用它们,因为 GreenDao 通过 DaoConfig 类使用反射来获取这些字段。在 DaoConfig 中查看 reflectProperties 方法。

问题是,当您启用 Proguard 时,它知道 Properties 中的所有这些字段都没有在任何地方使用,因此 Proguard 将其删除。

因此,为避免这种情况发生,请在您的 Proguard 文件中添加以下行:

-keep class **$Properties
-keepclassmembers class **$Properties 
    public static <fields>;

这应该可以解决问题。

【讨论】:

【参考方案6】:

在 proguard-rules.pro 中添加的以下行为我解决了这个问题。

-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao 
public static java.lang.String TABLENAME;

-keep class **$Properties

感谢@mgpx

【讨论】:

以上是关于仅使用 Proguard:无法初始化 DaoConfig => ArrayIndexOutOfBoundsException的主要内容,如果未能解决你的问题,请参考以下文章

将 ProGuard 设置为仅混淆我的应用程序包

Proguard:-keepparameternames 仅适用于某些包

如何将 proguard 配置为仅删除 android 日志记录调用

如何仅混淆 com.foo.* 和 com.bar.* (ProGuard)?

无法使用 proguard 构建发布 apk

无法使用 ProGuard 实例化 AndroidPlatform 类