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);
Что мне могло не хватать?
Спасибо @ripopenid. Я пробовал сделать нефинальными любые финалы, используемые в onCreate(...)
(только для чтения), но это ничего не изменило. Интересно, что изменилось в Android Studio до версии 2024.1.1 (Koala), что сделало ее такой непредсказуемой?
Вот как я решил проблему:
В 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 Да, com.me.mylib.core.MyActivity
компилируется как отдельная библиотека (модуль) с minifyEnabled
true, которая затем используется приложением, имеющим com.me.koalawoes.MyAppActivity
. Ни один из них не является окончательным, и вот что меня сбивает с толку: сообщение об ошибке вводит в заблуждение. Кроме того, это работало около 12 лет без необходимости исправления -keepnames
, которое я добавил в proguard.cfg
. Что в изменениях AS 2024.1.1 и Proguard 8.7 это побудило?
Поскольку 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, и это, вероятно, не ваша проблема.
Чего вы можете упустить, так это того, что обновление 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 Есть идеи?
onCreate
попытается присвоить значениеfinal
?