48

I'm experiencing this crash when using proguard after integrating the NavigationComponent (android.arch.navigation:navigation-fragment-ktx:1.0.0-alpha01) into my project with target and compile sdk of 27

    2018-05-16 12:13:14.044 24573-24573/com.mypackage.myapp.x E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.mypackage.myapp.x, PID: 24573
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mypackage.myapp.x/com.mypackage.myapp.MainActivity}: android.view.InflateException: Binary XML file line #16: Binary XML file line #16: Error inflating class fragment
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2925)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3060)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:110)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1800)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6649)
        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:826)
     Caused by: android.view.InflateException: Binary XML file line #16: Binary XML file line #16: Error inflating class fragment
     Caused by: android.view.InflateException: Binary XML file line #16: Error inflating class fragment
     Caused by: java.lang.RuntimeException: Exception inflating com.mypackage.myapp.x:navigation/nav_graph line 7
        at androidx.navigation.j.a(Unknown Source:124)
        at androidx.navigation.d.a(Unknown Source:4)
        at androidx.navigation.fragment.NavHostFragment.a(Unknown Source:88)
        at android.support.v4.app.Fragment.l(Unknown Source:15)
        at android.support.v4.app.m.a(Unknown Source:369)
        at android.support.v4.app.m.b(Unknown Source:7)
        at android.support.v4.app.m.a(Unknown Source:74)
        at android.support.v4.app.m.onCreateView(Unknown Source:216)
        at android.support.v4.app.j.a(Unknown Source:4)
        at android.support.v4.app.h.a(Unknown Source:2)
        at android.support.v4.app.d.onCreateView(Unknown Source:0)
        at android.support.v4.app.h.onCreateView(Unknown Source:0)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:780)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:866)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
        at android.support.v7.app.AppCompatDelegateImplV9.b(Unknown Source:23)
        at android.support.v7.app.d.setContentView(Unknown Source:4)
        at com.mypackage.myapp.MainActivity.onCreate(Unknown Source:12)
        at android.app.Activity.performCreate(Activity.java:7130)
        at android.app.Activity.performCreate(Activity.java:7121)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1262)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2905)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3060)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:110)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1800)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6649)
        at java.lang.reflect.Method.invoke(Native Method)
    2018-05-16 12:13:14.044 24573-24573/com.mypackage.myapp.x E/AndroidRuntime:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:826)
     Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: com.mypackage.myapp.fragments.MainFragment
        at androidx.navigation.fragment.b$a.a(Unknown Source:58)
        at androidx.navigation.fragment.b$a.a(Unknown Source:19)
        at androidx.navigation.j.a(Unknown Source:16)
        at androidx.navigation.j.a(Unknown Source:133)
        at androidx.navigation.j.a(Unknown Source:31)
            ... 38 more
     Caused by: java.lang.ClassNotFoundException: com.mypackage.myapp.fragments.MainFragment
        at java.lang.Class.classForName(Native Method)
        at java.lang.Class.forName(Class.java:453)
        at androidx.navigation.fragment.b$a.a(Unknown Source:45)
            ... 42 more
     Caused by: java.lang.ClassNotFoundException: Didn't find class "com.mypackage.myapp.fragments.MainFragment" on path: DexPathList[[zip file "/system/framework/org.apache.http.legacy.boot.jar", zip file "/data/app/com.mypackage.myapp.x-ysts055HQTtJTv5J2uej3g==/base.apk"],nativeLibraryDirectories=[/data/app/com.mypackage.myapp.x-ysts055HQTtJTv5J2uej3g==/lib/x86, /system/lib]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:125)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
            ... 45 more

It might be because AAPT is not yet producing keep rules for the navigation component?

ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
Kayvan N
  • 8,108
  • 6
  • 29
  • 38
  • 2
    This is a known issue, but it would be helpful if you could [file a bug](https://issuetracker.google.com/issues/new?component=197448) to make sure it is tracked in a user visible location – ianhanniballake May 16 '18 at 19:58
  • @ianhanniballake here is the bug report for it with a sample project to reproduce the issue https://issuetracker.google.com/issues/79874119 – Kayvan N May 16 '18 at 20:42

5 Answers5

82

I know that Proguard and R8 should be keeping all the children of library classes but in this case, the fragment class seems to be missing. This keep rule solved my issue but technically we should not need this rule at all!

-keep class * extends android.support.v4.app.Fragment{}

If you are using AndroidX, then use this rule: -keep class * extends androidx.fragment.app.Fragment{}

If you use argType in your navigation XML, you also need a rule for the referenced classes, for example: -keep class com.example.model.MyModel. Or even better, exclude parcelable and serializable classes from being renamed, as recommended by the official documentation. -keepnames class * extends android.os.Parcelable -keepnames class * extends java.io.Serializable

heyheyhey
  • 1,216
  • 8
  • 12
Kayvan N
  • 8,108
  • 6
  • 29
  • 38
  • 2
    Thanks Kayvan! I've been struggling with that for a little bit :/. I modified my proguard to look like this `-keep class com.example.myapp.** extends android.support.v4.app.Fragment{}` to be a little more specific – Gregriggins36 May 21 '18 at 19:35
  • 4
    This is actually very bad choice to keep children of Fragment class from ProGuard obfuscation. Instead, look at data types/models which is needed by your fragment and never try to serialize whole fragments, cuz' it's lifecycle-bounded and can have a lot of different states, but states of current view(fragment, for example) must be stored and handled by separate classes like ViewModel-s – android51130 Jun 10 '19 at 06:02
  • Thank you for answer. I try to keep only navigation frgaments, but it does not work. Do you know maybe i need to keep some dependent fragments? I do not want keep all extends of fragments. – mindw0rk Oct 10 '19 at 12:45
  • isn't this too much? just add `-keepnames class androidx.navigation.fragment.NavHostFragment` – user924 Sep 04 '20 at 20:46
  • 1
    I had runtimeException and by just adding `-keepnames class * extends android.os.Parcelable` and `-keepnames class * extends java.io.Serializable` It was fixed. – Mostafa Arian Nejad Dec 17 '20 at 06:44
  • `-keep class * extends android.support.v4.app.Fragment{}` This just makes no sense. Obfuscation is meant to remove all this junk but you force rules to keep it. It's not solution but a nasty workaround which Google should have resolved – Farid Dec 23 '20 at 17:46
  • Thanks, just your 3 lines of code fixed my problem :) – Venkat Oct 15 '21 at 13:58
50

My issue was that I was using the fragment name on the layout. After R8, the names are obfuscated causing the issue.

<androidx.fragment.app.FragmentContainerView
    android:id="@+id/nav_host_fragment"                
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent""
    app:defaultNavHost="true"
    app:navGraph="@navigation/navigation_home" />

In my case, the solution was to keep only the name in the Proguard file, as such:

#-------------------------------------------------
# JetPack Navigation
# This fixes: Caused by: androidx.fragment.app.Fragment$InstantiationException: Unable to instantiate fragment androidx.navigation.fragment.NavHostFragment: make sure class name exists
#-------------------------------------------------
-keepnames class androidx.navigation.fragment.NavHostFragment
  • 1
    Saved me a lot of time when I tried testing a release build – Mitch Apr 24 '20 at 20:03
  • 1
    Thanks @rodrigo.lourenco! Keeping all Fragment classes as other answers suggests seemed too hardcore to me, and with this small keep rule it works fine. You deserve more upvotes. – YawaraNes May 03 '20 at 20:05
  • Can this be tested in Debug builds? – IgorGanapolsky Sep 10 '20 at 18:49
  • @IgorGanapolsky I think so, you can have an obfuscated debug version. However, get ready if you are actually trying to debug because step-by-step is going to be all over the place. – rodrigo.lourenco Oct 19 '20 at 09:11
7

Did face the same issue. The answer above gave me the correct direction to look into. According to navigation docs

-keep class * extends android.support.v4.app.Fragment{} <-this is not needed 

All you need to do is keep names for data classes which are passed via safe args e.g

-keepnames class com.your.package.models.*
  • Please provide proper tags when asking questions. Tag is a keyword or label that categorizes your question with other, similar questions. Using the right tags makes it easier for others to find and answer your question. – Chandralal Nov 28 '19 at 14:35
  • What if I'm passing a Boolean via Args? – IgorGanapolsky Sep 10 '20 at 18:49
3

This is fixed since Android Gradle Plugin 4.1.

No need to define Proguard rules for fragments defined in the android:name attribute.

See https://issuetracker.google.com/issues/142601969

Antimonit
  • 2,846
  • 23
  • 34
0

Same answer as @Antimonit at SO answer. This has been fixed after AGP(Android Gradle Plugin) plugin version 4.1 and onwards.

I also faced similar issue at AGP version 7.2.0 with the similar error message Error inflating class androidx.fragment.app.FragmentContainerView. But in my case there was one data model class which I was using as below which was not kept under the proguard keep flag

<fragment
    android:id="@+id/fragment_id"
    android:name="com.fragment.FragmentClassName"
    android:label="@string/fragment_title"
    tools:layout="@layout/fragment_layout">
    <argument
        android:name="argName"
        android:defaultValue="@null"
        app:argType="com.model.ArgClass"
        app:nullable="true" />
    <action
        android:id="@+id/action_fragment_id_to_fragment_2_id"
        app:destination="@id/fragment_2"
        app:popUpTo="@id/fragment_2"
        app:popUpToInclusive="true" />
</fragment>

In my case, after application of R8 my class ArgClass was getting renamed and hence my NavHostFragment was crashing

Adding @Keep annotation like below fixed the issue in my case

import androidx.annotation.Keep

@Keep data class ArgClass(val id: String)

This is also documented in Android official doc

AndroidEngineX
  • 975
  • 1
  • 9
  • 22