Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

App sometimes crashes with Resources$NotFoundException after switching to android app bundle distribution

App has over 20000 monthly active users. It's been available on google play for months. After I've recently switched from distribution with .apk to distribution with .aab, I've started receiving random crashes on crashlytics and google play store. No other significant changes were made in the build that introduced the crashes.

The crash happens on the very first screen of the app, while inflating xml layout. The xml layout in question is a simple splash screen that only contains one image view and one textview. The imageview is android.widget.ImageView, not compat version, and it displays png image, not a vector image. The image is present in all drawable folder variations: drawable, drawable-mdpi, ..., drawable-xxxhdpi.

Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.company/com.company.ui.splash.SplashActivity}: android.view.InflateException: Binary XML file line #14: Binary XML file line #14: Error inflating class ImageView           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(Method.java)           at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:495)           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)     Caused by android.view.InflateException: Binary XML file line #14: Binary XML file line #14: Error inflating class ImageView      Caused by android.view.InflateException: Binary XML file line #14: Error inflating class ImageView      Caused by android.content.res.Resources$NotFoundException: Drawable (missing name) with resource ID #0x7f0800b2      Caused by android.content.res.Resources$NotFoundException: Unable to find resource ID #0x7f0800b2           at android.content.res.ResourcesImpl.getResourceName(ResourcesImpl.java:255)           at android.content.res.ResourcesImpl.loadDrawableForCookie(ResourcesImpl.java:785)           at android.content.res.ResourcesImpl.loadDrawable(ResourcesImpl.java:631)           at android.content.res.Resources.loadDrawable(Resources.java:897)           at android.content.res.TypedArray.getDrawableForDensity(TypedArray.java:955)           at android.content.res.TypedArray.getDrawable(TypedArray.java:930)           at android.widget.ImageView.<init>(ImageView.java:189)           at android.widget.ImageView.<init>(ImageView.java:172)           at android.support.v7.widget.AppCompatImageView.<init>(AppCompatImageView.java:71)           at android.support.v7.widget.AppCompatImageView.<init>(AppCompatImageView.java:67)           at android.support.v7.app.AppCompatViewInflater.createImageView(AppCompatViewInflater.java:181)           at android.support.v7.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:105)           at android.support.v7.app.AppCompatDelegateImplV9.createView(AppCompatDelegateImplV9.java:1035)           at android.support.v7.app.AppCompatDelegateImplV9.onCreateView(AppCompatDelegateImplV9.java:1092)           at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:772)           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.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.setContentView(AppCompatDelegateImplV9.java:287)           at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:139)           at com.company.ui.splash.SplashActivity.onCreate(SplashActivity.java:58)           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(Method.java)           at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:495)           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 

Part of xml file that causes the crash:

<ImageView     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_above="@id/center"     android:layout_centerHorizontal="true"     android:src="@drawable/logo" /> 

The crash happens on all android versions, from 4.1.2 up to 9.0.

Aside from other devices, I've also received crashes from Google Pixel and Nexus 5X, both non-rooted. I happen to own both devices. I've tried installing my app on them from google play and from sideloading services such as pureapk, but I wasn't able to reproduce the crash.

The question is similar to Android App Bundle introduces Resource Not found crash in Android app , but in that question, author was able to solve his problems by using vector drawable compat. This is not my case.

It appears that the entire resource folder is missing from the apk somehow, although testing this assumption is hard. I cannot reproduce the issue so I'll have o re-destribute the app and wait for a couple of days to see how the crash has changed, and I'd rather not do testing on live users.

When this bug happens, it usually happens several times in the row for the same devices, which leads me to believe that users who get this bug cannot ever launch the app. Also, I know that some of the users who previously used the app cannot use it anymore.

So, to sum this up:
1. Crash started to appear right after switching to android application bundle distribution on google play
2. App crashes on its first attempt to recover drawable resource - a simple png image
3. The crash is not android-version specific; it happens on both rooted and non-rooted devices
4. If the user gets this bug, he's probably stuck forever

What is causing this crash? Is there a workaround?

==========

Update: After reading the answer below I've concluded that the only workaround is to detect sideload installation and then open activity without any drawable resources or styles with links to Google Play and official site with old-school apk file. The user can then re-download app from another source.

This is the code I use to detect if app was sideloaded (you might need to remove nativeLibrariesPresent part if there are no native libraries in your app):

private fun isValidInstallation(): Boolean {     var resourcesPresent: Boolean     try {         // Any drawable id will suffice         val logo = ResourcesCompat.getDrawable(resources, R.drawable.logo_white, null)         resourcesPresent = logo != null     } catch (e: Exception) {         resourcesPresent = false     }      if (!resourcesPresent) {         Timber.e("No drawable resources detected inside app")     }      var nativeLibrariesPresent: Boolean     try {         val nativeLibraryDir = File(applicationInfo.nativeLibraryDir)         val primaryNativeLibraries = nativeLibraryDir.list()         nativeLibrariesPresent = primaryNativeLibraries.isNotEmpty()     } catch (e: Exception) {         nativeLibrariesPresent = false     }      if (!nativeLibrariesPresent) {         Timber.e("No native libraries detected inside app")     }      return resourcesPresent && nativeLibrariesPresent } 

You'll want to start alternative activity before you do anything inside your main activity:

override fun onCreate(savedInstanceState: Bundle?) {     super.onCreate(savedInstanceState)      if (!isValidInstallation()) {         val intent = Intent(this, InvalidInstallationActivity::class.java)         startActivity(intent)         finish()         return     }      setContentView(R.layout.activity_main)     ... 

InvalidInstallationActivity can use xml layout and it can use string resources if you don't split your aab by language (language { enableSplit = false }), but it cannot use any drawable resources.

like image 628
Alexey Avatar asked Sep 23 '18 20:09

Alexey


People also ask

What is the difference between APK and app bundle?

App bundles are publishing format, whereas APK (Android application Package) is the packaging format which eventually will be installed on device. Google uses app bundle to generate and serve optimized APKs for each user's device configuration, so they download only the code and resources they need to run your app.

Is Android App Bundle mandatory?

Android App Bundle requirement for new apps and gamesAfter August 2021, all new apps and games will be required to publish with the Android App Bundle format. New apps and games must use Play Asset Delivery or Play Feature Delivery to deliver assets or features that exceed a download size of 150MB.

How do you troubleshoot the Android application which is crashing frequently in Android Studio?

The easiest way to fix an app that keeps crashing on your Android smartphone is to simply force stop it and open it again. To do this, go to Settings -> Apps and select the app that keeps crashing. Tap on the app's name and then tap on 'Force stop'. Now try opening the app again and see if it works well.

How do I find out why an app is crashing Android?

Select an app. On the left menu, select Quality > Android vitals > Crashes and ANRs. Near the center of your screen, use the filters to help you find and diagnose issues. Alternatively, select a cluster to get more details about a specific crash or ANR error.


2 Answers

This is almost certainly users sharing the app, either via P2P sharing programs, or uploading the APK to the web then other users downloading and installing from the web.

People used to dealing with non Android App Bundle apps just transfer and share the main APK. But your App bundle app has lots of "split APKs" for things like the resources, that is how the size saving happens. You can read all about this process on the help page. If a user installs the main APK without installing the right split APKs, then a "Resources Not found" crash will occur the first time the app tries to load a resource.

If you want to support users sideloading your app and just the main APK you could try to detect this situation and display a message to the user (without using any resources) that says "Please install from Google Play". Or you could just decide you aren't going to support users who share APKs in this way.

I suspect in the long run the websites and P2P sharing programs will get better at sharing such APKs properly, so I wouldn't spend too long worrying about it.

like image 166
Nick Fortescue Avatar answered Oct 02 '22 15:10

Nick Fortescue


You can solve this by either using com.google.android.play.core.missingsplits.MissingSplitsDetectingApplication as your application or by doing this in your own application:

class MyApplication : Application() {     override fun onCreate() {         if (MissingSplitsManagerFactory.create(this).disableAppIfMissingRequiredSplits()) {             // Skip app initialization when the app is missing required splits.             return         }         super.onCreate()         // ...     } } 

You need the google play core dependency for this. FYI: it's already deprecated: missing required splits is already automatically caught with Google Play protect and on devices with Android 10 or higher.

like image 36
Cristan Avatar answered Oct 02 '22 14:10

Cristan