Generate Signed App APK
used to work flawlessly for an app of mine until… I upgraded Android Studio to 2024.1.1.
It still builds and runs perfectly when generating debug
APK. However, when I attempt to generate a release
APK, it builds successfully, but when the app is launched on the smartphone, it crashes immediately with this FATAL EXCEPTION:
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)
But…MyActivity’s onCreate
is not declared final at all:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
What could I be missing?
2
Answers
Here is how I solved the issue:
In the
proguard.cfg
of my library (wherecom/me/mylib/core/MyActivity
is), I added the following:I still wonder what in my upgrade process (without changing a single line of code) made
Generate Signed App APK
rely on this-keepnames
requirement foronCreate(...)
. It used to work without this.At this point, I can only suspect the update from AGP version 8.4 to AGP version 8.5 which was prompted by the upgrade to AS 2024.1.1.
R8
is known to change with AGP, as in theandroid.enableR8.fullMode=false
case when migrating from AGP version 7.0.Also, I couldn't find anything related in Android Gradle plugin 8.5 release notes.
What you could be missing is that an
Android Studio version
upgrade may trigger a chain reaction in the form ofAGP version
update >R8 version
update.It is unclear what happened in your specific upgrade process but there are numerous reports in which a naive Android Studio upgrade led to significant time waste in an attempt to generate a non-crushable release APK:
I suspect R8’s default value of android.enableR8.fullMode has to do with this.
From the R8 FAQ:
In non-compat mode, also called “full mode”, R8 performs more aggressive optimizations, meaning additional ProGuard configuration rules may be required.
Full mode can be enabled by adding android.enableR8.fullMode=true in the gradle.properties file. The main differences compared to R8 compatibility mode are:
<init>()
) is not implicitly kept when aclass is kept.
<init>()
) is not implicitlykept for types which are only used with
ldc
,instanceof
orcheckcast
.-keepclassmembers
rule are not implicitly considered to be instantiated. Classes that are only instantiated using reflectionshould be kept explicitly with a
-keep
rule.and annotations are only kept for classes, methods and fields which
are matched by keep rules even when
-keepattributes
is specified. Theweakest rule that will keep annotations and attributes is
-keep[classmembers],allowshrinking,allowoptimization,allowobfuscation,allowaccessmodification
class-specification Additionally, for attributes describing a
relationship such as
InnerClass
andEnclosingMethod
, non-compat moderequires both endpoints being kept.
SourceFile
attribute will always be rewritten to SourceFile unless-renamesourcefileattribute
is used in which case the provided value is used. The original source file name is in the mapping file andwhen optimizing or minifying a mapping file is always produced.
Note:
android.enableR8.fullMode=true
became default in AGP 8.0, not 8.5 and certainly not in 7.0. So this alone cannot explain what you described. Citation: https://developer.android.com/build/releases/past-releases/agp-8-0-0-release-notes#default-changes