LinkageError: метод onCreate переопределяет конечный метод

Generate Signed App APK раньше работало безупречно в моем приложении, пока... я не обновил Android Studio до 2024.1.1.

Он по-прежнему отлично компилируется и работает при создании debug APK. Однако, когда я пытаюсь сгенерировать release APK, он собирается успешно, но когда приложение запускается на смартфоне, оно сразу же вылетает с этим ФАТАЛЬНЫМ ИСКЛЮЧЕНИЕМ:

 java.lang.LinkageError:
 Method void com.me.koalawoes.MyAppActivity.onCreate(android.os.Bundle)
 overrides final method in class Lcom/me/mylib/core/MyActivity;
 (declaration of 'com.me.koalawoes.MyAppActivity'
  appears in /data/app/~~sHPI9ai93DWU6FOp_edr9A==/com.me.koalawoes-8LbG6dXPeAvMUDEvK-x8jQ==/base.apk)

Но... onCreate MyActivity вообще не объявлен окончательным:

    @Override
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);

Что мне могло не хватать?

stackoverflow.com/a/5463855/4807784 говорит, что «onCreate() — это специальный метод, вызываемый из ОС при создании вашего действия, поэтому он вызывается после конструктора действия. Вы должны назначить свои конечные поля перед onCreate( ) называется.". Вы проверили возможность того, что ваш onCreate попытается присвоить значение final?
ripopenid 30.06.2024 00:12

Спасибо @ripopenid. Я пробовал сделать нефинальными любые финалы, используемые в onCreate(...) (только для чтения), но это ничего не изменило. Интересно, что изменилось в Android Studio до версии 2024.1.1 (Koala), что сделало ее такой непредсказуемой?

ususer 30.06.2024 05:23
4
2
112
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вот как я решил проблему:

В proguard.cfg моей библиотеки (где com/me/mylib/core/MyActivity) я добавил следующее:

-keepnames class com.me.mylib.core.MyActivity {
    public void onCreate(android.os.Bundle);
}

Мне до сих пор интересно, что в моем процессе обновления (без изменения ни одной строки кода) заставило Generate Signed App APK полагаться на это -keepnames требование для onCreate(...). Раньше без этого работало.

На данный момент я могу только подозревать обновление AGP версии 8.4 до AGP версии 8.5, которое было вызвано обновлением до AS 2024.1.1. Известно, что R8 меняется при использовании AGP, как в случае android.enableR8.fullMode=false при переходе с AGP версии 7.0.

Кроме того, я не смог найти ничего связанного в Примечаниях к выпуску плагина Android Gradle 8.5 .

Компилируется ли com.me.mylib.core.MyActivity как отдельная библиотека с minifyEnabled true, которая затем используется приложением, имеющим com.me.koalawoes.MyAppActivity? Если библиотека компилируется отдельно, то известных подклассов com.me.mylib.core.MyActivity нет, и поэтому ее можно сделать final.

sgjesse 01.07.2024 09:34

@sgjesse Да, com.me.mylib.core.MyActivity компилируется как отдельная библиотека (модуль) с minifyEnabled true, которая затем используется приложением, имеющим com.me.koalawoes.MyAppActivity. Ни один из них не является окончательным, и вот что меня сбивает с толку: сообщение об ошибке вводит в заблуждение. Кроме того, это работало около 12 лет без необходимости исправления -keepnames, которое я добавил в proguard.cfg . Что в изменениях AS 2024.1.1 и Proguard 8.7 это побудило?

ususer 01.07.2024 14:23

Поскольку com.me.mylib.core.MyActivity компилируется без каких-либо подклассов и minifyEnabled true, тогда R8 может решить сделать метод финальным. Добавленное вами правило сохранения по сути помечает com.me.mylib.core.MyActivity как класс «API» для создания подклассов (возможно, вы захотите включить все методы private и protected). Также вам следует использовать -keep, а не -keepnames. Вышло обновление AGP 8.4, которое изменило работу с библиотеками (Issuetracker.google.com/338411137), но, как вы упомянули, это появилось в AGP 8.5, и это, вероятно, не ваша проблема.

sgjesse 29.07.2024 11:36

Чего вы можете упустить, так это того, что обновление Android Studio version может вызвать цепную реакцию в виде AGP version обновление > R8 version обновления.

Неясно, что произошло в вашем конкретном процессе обновления, но есть многочисленные отчеты, в которых простое обновление Android Studio привело к значительной потере времени в попытке создать неразрушаемый выпуск APK:

Изначально я подозревал, что значение по умолчанию в R8 android.enableR8.fullMode связано с этим, но...

Из Часто задаваемых вопросов по R8:

В несовместимом режиме, также называемом «полным режимом», R8 выполняет более агрессивную оптимизацию, а это означает, что могут потребоваться дополнительные правила конфигурации ProGuard.

Полный режим можно включить, добавив android.enableR8.fullMode=true в файл gradle.properties. Основные отличия от режима совместимости R8:

  • Конструктор по умолчанию (<init>()) не сохраняется неявно, когда класс сохраняется.
  • Конструктор по умолчанию (<init>()) не является неявным сохраняется для типов, которые используются только с ldc, instanceof или checkcast.
  • Включающие классы полей или методов, которым соответствует -keepclassmembers правило не считается неявно реализуемым. Классы, экземпляры которых создаются только с использованием отражения. следует явно сохранять с помощью правила -keep.
  • Методы по умолчанию не сохраняются неявно как абстрактные методы.
  • Атрибуты (например, подпись) а аннотации сохраняются только для классов, методов и полей, которые соответствуют правилам сохранения, даже если указан -keepattributes. самое слабое правило, которое сохранит аннотации и атрибуты, — это -keep[classmembers],allowshrinking,allowoptimization,allowobfuscation,allowaccessmodification спецификация класса Кроме того, для атрибутов, описывающих отношения, такие как InnerClass и EnclosingMethod, несовместимый режим требует сохранения обеих конечных точек.
  • При оптимизации или минимизации Атрибут SourceFile всегда будет перезаписан в SourceFile, если только -renamesourcefileattribute используется, и в этом случае используется предоставленное значение. Исходное имя исходного файла находится в файле сопоставления и при оптимизации или минимизации всегда создается файл сопоставления.

Примечание. android.enableR8.fullMode=true стало значением по умолчанию в AGP 8.0, а не в 8.5 и уж точно не в 7.0. Так что одним этим не объяснить то, что вы описали. Цитирование: https://developer.android.com/build/releases/past-releases/agp-8-0-0-release-notes#default-changes

Действительно, установка android.enableR8.fullMode=false в gradle.properties не решает ни одной из проблем, с которыми я столкнулся до сих пор. Должна быть другая первопричина. @sgjesse Есть идеи?

ususer 02.07.2024 23:28

Другие вопросы по теме