仅使用 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】:你的项目中有keep
Entity
类吗?
如果没有,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:-keepparameternames 仅适用于某些包
如何将 proguard 配置为仅删除 android 日志记录调用