【问题标题】:Hardcoded app:fragment string in Preference crashes in Release硬编码的应用程序:Preference 中的片段字符串在 Release 中崩溃
【发布时间】:2020-10-29 05:05:46
【问题描述】:

以下是我的设置屏幕的 xml 文件的简化版本。

<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!--hardcoded app:fragment crashes in release because of ClassNameNotFound -->
    <Preference
        app:allowDividerAbove="true"
        app:fragment="com.flamyoad.tsukiviewer.ui.settings.preferences.ClearDataPreferences"
        app:icon="@drawable/ic_delete_settings_24dp"
        app:title="Clear data" />

</androidx.preference.PreferenceScreen>

它在调试版本中运行良好。但是当我点击发布 apk 上的首选项时,它会因为ClassNotFoundException 而崩溃。

这里是堆栈跟踪

Process: com.flamyoad.tsukiviewer, PID: 13647
    androidx.fragment.app.Fragment$c: Unable to instantiate fragment com.flamyoad.tsukiviewer.ui.settings.preferences.ClearDataPreferences: make sure class name exists
        at i.l.d.n.d()
        at androidx.fragment.app.Fragment.a()
        at i.l.d.r$c.a(:2)
        at com.flamyoad.tsukiviewer.ui.settings.SettingsActivity.a(:2)
        at i.s.f.b(:29)
        at androidx.preference.Preference.a(:23)
        at androidx.preference.Preference$a.onClick()
        at android.view.View.performClick(View.java:4757)
        at android.view.View$PerformClick.run(View.java:19769)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5289)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
     Caused by: java.lang.ClassNotFoundException: com.flamyoad.tsukiviewer.ui.settings.preferences.ClearDataPreferences
        at java.lang.Class.classForName(Native Method)
        at java.lang.Class.forName(Class.java:308)
        at i.l.d.n.c(:2)
        at i.l.d.n.d() 
        at androidx.fragment.app.Fragment.a() 
        at i.l.d.r$c.a(:2) 
        at com.flamyoad.tsukiviewer.ui.settings.SettingsActivity.a(:2) 
        at i.s.f.b(:29) 
        at androidx.preference.Preference.a(:23) 
        at androidx.preference.Preference$a.onClick() 
        at android.view.View.performClick(View.java:4757) 
        at android.view.View$PerformClick.run(View.java:19769) 
        at android.os.Handler.handleCallback(Handler.java:739) 
        at android.os.Handler.dispatchMessage(Handler.java:95) 
        at android.os.Looper.loop(Looper.java:135) 
        at android.app.ActivityThread.main(ActivityThread.java:5289) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:372) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694) 
     Caused by: java.lang.ClassNotFoundException: Didn't find class "com.flamyoad.tsukiviewer.ui.settings.preferences.ClearDataPreferences" on path: DexPathList[[zip file "/data/app/com.flamyoad.tsukiviewer-1/base.apk"],nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
        at java.lang.Class.classForName(Native Method) 
        at java.lang.Class.forName(Class.java:308) 
        at i.l.d.n.c(:2) 
        at i.l.d.n.d() 
        at androidx.fragment.app.Fragment.a() 
        at i.l.d.r$c.a(:2) 
        at com.flamyoad.tsukiviewer.ui.settings.SettingsActivity.a(:2) 
        at i.s.f.b(:29) 
        at androidx.preference.Preference.a(:23) 
        at androidx.preference.Preference$a.onClick() 
        at android.view.View.performClick(View.java:4757) 
        at android.view.View$PerformClick.run(View.java:19769) 
        at android.os.Handler.handleCallback(Handler.java:739) 
        at android.os.Handler.dispatchMessage(Handler.java:95) 
        at android.os.Looper.loop(Looper.java:135) 
        at android.app.ActivityThread.main(ActivityThread.java:5289) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:372) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694) 
        Suppressed: java.lang.ClassNotFoundException: com.flamyoad.tsukiviewer.ui.settings.preferences.ClearDataPreferences
        at java.lang.Class.classForName(Native Method)
        at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
        at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
                ... 21 more
     Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available

对我来说,原因似乎是 apk 被缩小并且类名被替换为更短的字符串。在这种情况下我能做什么?将app:fragment 替换为Activity 中的函数调用是最佳实践吗?或者有没有其他方法?

我在我的应用程序中使用PreferenceFragmentCompat

【问题讨论】:

    标签: android xml kotlin jvm


    【解决方案1】:

    aapt2 generated proguard rules for preferences 专门寻找android:fragment 属性,而不是app:fragment。您可能想使用android:fragment 自动保留偏好片段。

    【讨论】:

    • 即使我从app:fragment 更改为android:fragment,它仍然崩溃
    【解决方案2】:

    我将这些行添加到我的 proguard-rules.pro 并停止崩溃。

    -keep public class * extends androidx.preference.Preference
    -keep public class * extends androidx.preference.PreferenceFragmentCompat
    

    【讨论】:

      猜你喜欢
      • 2020-07-10
      • 2011-05-18
      • 1970-01-01
      • 1970-01-01
      • 2016-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-04
      相关资源
      最近更新 更多