AndroidX Navigation and Proguard
Recently I can across an odd problem with AndroidX navigation and Proguard. It was odd because the code worked fine in a debug build but the release variant crashed. There is very little difference between the debug and release variants, as you would expect, the main one is proguard. I am not a big fan of proguard, for this exact reason, however it was a requirement from the client.
with the following error
E/AndroidRuntime: FATAL EXCEPTION: main
Process: myapp, PID: 21212
java.lang.RuntimeException: Unable to start activity ComponentInfo{myapp/mydomain.HostActivity}: java.lang.RuntimeException: Exception inflating myapp:navigation/nav_graph line 14
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.RuntimeException: Exception inflating myapp:navigation/nav_graph line 14
at androidx.navigation.NavInflater.inflate(SourceFile:14)
at androidx.navigation.NavController.setGraph(SourceFile:2)
at mydomain.HostActivity.onCreate(SourceFile:5)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: mydomain.models.ControlDTO
at androidx.navigation.NavType.fromArgType(SourceFile:30)
at androidx.navigation.NavInflater.inflateArgument(SourceFile:7)
at androidx.navigation.NavInflater.inflateArgumentForDestination(SourceFile:3)
at androidx.navigation.NavInflater.inflate(SourceFile:25)
at androidx.navigation.NavInflater.inflate(SourceFile:36)
at androidx.navigation.NavInflater.inflate(SourceFile:6)
at androidx.navigation.NavController.setGraph(SourceFile:2)
at mydomain.HostActivity.onCreate(SourceFile:5)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.ClassNotFoundException: mydomain.models.ControlDTO
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:453)
at java.lang.Class.forName(Class.java:378)
at androidx.navigation.NavType.fromArgType(SourceFile:22)
at androidx.navigation.NavInflater.inflateArgument(SourceFile:7)
at androidx.navigation.NavInflater.inflateArgumentForDestination(SourceFile:3)
at androidx.navigation.NavInflater.inflate(SourceFile:25)
at androidx.navigation.NavInflater.inflate(SourceFile:36)
at androidx.navigation.NavInflater.inflate(SourceFile:6)
at androidx.navigation.NavController.setGraph(SourceFile:2)
at mydomain.HostActivity.onCreate(SourceFile:5)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.ClassNotFoundException: Didn't find class "mydomain.models.ControlDTO" on path: DexPathList[[zip file "/system/framework/org.apache.http.legacy.boot.jar", zip file "/data/app/myapp.debug-4feQETSdKRijsMAIofJKRQ==/base.apk"],nativeLibraryDirectories=[/data/app/myapp.debug-4feQETSdKRijsMAIofJKRQ==/lib/x86, /system/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:453)
at java.lang.Class.forName(Class.java:378)
at androidx.navigation.NavType.fromArgType(SourceFile:22)
at androidx.navigation.NavInflater.inflateArgument(SourceFile:7)
at androidx.navigation.NavInflater.inflateArgumentForDestination(SourceFile:3)
at androidx.navigation.NavInflater.inflate(SourceFile:25)
at androidx.navigation.NavInflater.inflate(SourceFile:36)
at androidx.navigation.NavInflater.inflate(SourceFile:6)
at androidx.navigation.NavController.setGraph(SourceFile:2)
at mydomain.HostActivity.onCreate(SourceFile:5)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
The core of the problem seemed to be
Caused by: java.lang.RuntimeException: Exception inflating myapp:navigation/nav_graph line 14
at androidx.navigation.NavInflater.inflate(SourceFile:14)
at androidx.navigation.NavController.setGraph(SourceFile:2)
at mydomain.HostActivity.onCreate(SourceFile:5)
...
Caused by: java.lang.ClassNotFoundException: Didn't find class "mydomain.models.ControlDTO"
The method that caused the crash is onCreate
The crash happens on the navController.setGraph()
line, the top of the R.navigation.nav_graph
XML looked like this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nav_graph"
app:startDestination="@id/detailsFragment">
<fragment
android:id="@+id/detailsFragment"
android:name="mydomain.DetailsFragment"
tools:layout="@layout/details_fragment">
<argument
android:name="dto"
app:argType="mydomain.models.ControlDTO" />
<argument
Given that it worked fine in a debug build and only crashed in a release build, Proguard handling of the androidx arguments would seem to be the problem. I added this to the proguard file and the crash was fixed
# NavGraph SafeArgs
-keep class mydomain.models.ControlDTO
It turns out that every argument mentioned in the navigation graph needs to be excluded from proguard like this. So to stop this happening again I excluded the whole namespace and put all the navigation graph arguments in that namespace, like this
# NavGraph SafeArgs
-keep class mydomain.models.** { *; }