Android App Bundle introduces Resource Not found crash in Android app
Asked Answered
A

8

80

By using Android's new Android App Bundle, I have received a Resource Not Found error in 2 of my Google Play Store apps.

Here is the stacktrace from fabric for one of the apps:

Unable to start activity ComponentInfo{/com.Lastyear.MainActivity}: android.content.res.Resources$NotFoundException: File res/drawable/abc_item_background_holo_dark.xml from drawable resource ID #0x7f08002c
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2377)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2429)
       at android.app.ActivityThread.access$800(ActivityThread.java:151)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1342)
       at android.os.Handler.dispatchMessage(Handler.java:110)
       at android.os.Looper.loop(Looper.java:193)
       at android.app.ActivityThread.main(ActivityThread.java:5363)
       at java.lang.reflect.Method.invokeNative(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:515)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:828)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:644)
       at dalvik.system.NativeStart.main(NativeStart.java)

build.gradle dependencies:

 dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
testImplementation 'junit:junit:4.12'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:customtabs:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'com.squareup.picasso:picasso:2.5.2'

implementation 'com.android.support:palette-v7:27.1.1'
implementation 'com.afollestad.material-dialogs:core:0.9.6.0'
implementation 'com.jakewharton:butterknife:8.8.1'
implementation 'com.github.bumptech.glide:glide:3.7.0'
implementation 'com.android.support:design:27.1.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
implementation 'com.github.hotchemi:android-rate:1.0.1'
implementation 'com.hannesdorfmann.smoothprogressbar:library:1.0.0'
implementation 'com.android.support:palette-v7:27.1.1'
implementation 'com.google.android.gms:play-services-ads:15.0.1'
implementation 'com.muddzdev:styleabletoast:1.0.9'
implementation 'com.github.GrenderG:Toasty:1.2.5'
implementation 'com.hannesdorfmann.smoothprogressbar:library:1.0.0'

implementation 'com.wang.avi:library:2.1.3'
implementation 'com.github.medyo:fancybuttons:1.8.4'
implementation 'com.irozon.sneaker:sneaker:1.0.1'
implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
implementation 'de.hdodenhof:circleimageview:2.2.0'
implementation 'com.github.barteksc:android-pdf-viewer:2.8.2'


implementation 'com.getkeepsafe.taptargetview:taptargetview:1.11.0'


implementation('com.crashlytics.sdk.android:crashlytics:2.6.8@aar') {
    transitive = true;
}


implementation 'petrov.kristiyan:colorpicker-library:1.1.8'}

One more thing, it is happening only on Android 4 operating system, not on newer versions of Android. I have found that other apps are having the same problem of Resource Not Found, which was not existing before using Android's app bundle. Is there some problem in the library or code or it is because of the beta version of Android's app bundle?

I have also found the resource drawable due to which it crashes:- Screenshot showing the highlighted drawable resource that causes the problem.

I think this question is also related to this one: Resource Not Found error res/drawable/abc_switch_thumb_material.xml after adding SwitchCompat in Android App Bundle

Annihilation answered 22/5, 2018 at 15:53 Comment(4)
You can try to reproduce the issue locally by using bundletool and an emulator with the specifications that matches the device which sees the crash.Adding some more context, such as dependencies and potential module structure makes it easier to see what's going on here.Bawcock
I have tried to reproduce the error by using bundletool but can't do it on any tried device . Meanwhile i have added the screenshot and dependencies.Annihilation
I know that this is a bit late now, but how did you manage to upload the aab file to firebase?Midweek
How to find the resources file with all the ids?Lu
S
60

This is almost certainly users sharing (sideloading) 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.

If you see this happening far more frequently on lower Android versions, this isn't probably due to a bug in lower Android versions. Instead, it is probably because in countries where users commonly P2P share apps (eg India) users also are far more likely to be on older version phones.

Spiegel answered 31/10, 2018 at 11:28 Comment(8)
Is there a way to detect sideloading? I've had similar issues and I've resorted to distributing APKs instead of bundles. The crashes being reported (and the emails coming in regarding crashes) are time-consuming and disturbing. There's no way to easily figure out if the user is complaining because of a bug within the app or a bundle / sideload related issue. I would consider this a flaw in bundle design as they should have envisaged this and provided a built-in mechanism to detect this (and possibly auto-download the remaining APKs or display a nice error).Headley
See this SO question. #10809938Spiegel
No this is not. I have the same exact problem and I log the installer package, it is correctly set to 'com.android.vending'Orthographize
@NickFortescue I have confirmed this issue happens even for users that are NOT sideloading the application. I have reports especially from Vivo devices. I suspect Play is not generating APKs correctly. What steps can I take to help that?Mixtec
That seems super unlikely, but interesting. I don't work on Play any more, but the most useful thing would be a bug report from an affected device - see developer.android.com/studio/debug/bug-report. Then contact Play Developer Support through the Play console to route it to the appropriate team. Also verify the user installed the application direct from the Play StoreSpiegel
If you can't get a bug report, details of the gmail account used for Google Play on the affected phone, and the phone model would be super useful. That will help the Google Play developers attempt to reproduce, and know exactly what APK should be delivered. (Don't report these here for user privacy reasons. Instead send the info to Play developer support)Spiegel
Now Side loading dialog is not showing, does google changed something regarding this please help. It only showing App not installed after installation ,ThanksHula
are you sure about this one as well? because I've updated the app 3-4 times and it has this issue soon after update (based on Firebase Crashlytics), hard to believe that it was sideloaded so fast to the latest version - #73486511Worldling
D
34

This is a little late but Google has introduced new API for Sideloading crash prevention, which allows you to detect incomplete installation of apps that are built using an Android App Bundle.

For example, consider an app that uses Android App Bundles to optimize app download size using split APKs. When a user downloads the app from the Google Play store, it ensures that the device downloads and installs the complete set of split APKs required to run that app on that particular device. When you bypass Google Play to sideload an app, the platform does not have sufficient data to validate the app install, and proper functionality of the app is not guaranteed.

First off include the Play Core library 1.6.0 or higher in your project.

Include the following in your app project’s build.gradle file:

buildscript {
    dependencies {
        ...
        // Use bundletool 0.9.0 or higher when building with the
        // Android Gradle plugin.
        classpath 'com.android.tools.build:bundletool:0.9.0'
    }
}

You can use 1 of those 3 below methods

1) Register checks through the manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication" >
    <application
        ...
        android:name="com.google.android.play.core.missingsplits.MissingSplitsDetectingApplication" >
    </application>
    ...
</manifest>

2) Apply checks in a custom Application class

public class MyCustomApplication extends Application {
    @Override
    public void onCreate() {

        if (MissingSplitsManagerFactory.create(this).disableAppIfMissingRequiredSplits()) {
            // Skip app initialization.
            return;
        }

        super.onCreate();
        ...
    }
}

3) Apply checks to content providers

public class ExampleProvider extends ContentProvider {
    @Override
    public boolean onCreate() {

        if (MissingSplitsManagerFactory.create(getContext()).isMissingRequiredSplits()) {
            // Skip provider initialization.
            return false;
        }

        super.onCreate();
        ...
    }
}

Read More : https://developer.android.com/reference/com/google/android/play/core/release-notes?hl=en-419#1-6-0

Diacritical answered 14/6, 2019 at 10:7 Comment(9)
Have you tried implementing it by yourself? Did u find any issue with it? Because I tried and run though some different issue. Here is my problem explained. Please look in to it and if you have an answer please let me know. #56725915Cosmopolitan
Thank you so much! This should be the new accepted answer :DAmbrose
@NaveenTP, i am using it since they publish this API, everything is working OKDiacritical
@EAKTEAM Hi, Is missing_splits_activity customizable? Is anybody know something about that? At least can we change the language of dialog messageIrritate
Ensar, the activity is not modifiable. But abouy the language dont worry, Google will take care, only if you have not implemented 'resconfig' in your build.gradleDiacritical
@EAKTEAM Thank you for information. But when i tried with non-english phone, the dialog message still show in english. I didn't implement 'resconfig'. Should i do something else?Irritate
Caveat: Because these checks occur whenever a user opens your app, your app’s startup time might increase slightly. (Note written in developer.android.com/guide/app-bundle/sideload-check)Pollination
For what purpose do we need to include com.android.tools.build:bundletool:0.9.0 as a gradle plugin? We do not apply anything, does it make sense?Raama
MissingSplitsManagerFactory is now deprecated with comment: "the feature is now obsolete. Installs with missing splits are now blocked on devices which have Play Protect active or run on Android 10."Repress
E
20

The accepted answer is absolutely correct - root of this issue is sideloading of APK file.

Nevertheless, lot of people are still looking for workaround, asking how to correctly handle this case.

In my app I did the following:

  1. Create 1x1 image named pixel.png and put it to all of the following folders: drawable-mdpi, drawable-hdpi, drawable-xhdpi, drawable-xxhdpi, drawable-xxxhdpi.

  2. Create simple Activity which shows static message, e.g.

    This copy of app is corrupted and can't be launched.

    Please, install original version from Google Play

  3. Then simply call getDrawable(R.drawable.pixel) from Activity.onCreate() wrapped in try/catch clause.

  4. If the exception was caught, just finish current Activity and start another one from step #2.

Done!

Screenshot

This solution works well, now I even have data from Firebase Analytics confirming this.

From the 46k of new users (event first_open) 266 users got this error (which was caught) and 221 users clicked button which leads to Google Play.

Here is my source code (also available on GitHub):

DrawablesValidator.java

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Space;
import android.widget.TextView;
import android.widget.Toast;

public class DrawablesValidator extends Activity {
    public static void ensureDrawablesValid(@NonNull Activity activity) {
        try {
            // IMPORTANT create 1x1 image named pixel.png and put it to all folders
            //           drawable-mdpi
            //           drawable-hdpi
            //           drawable-xhdpi
            //           drawable-xxhdpi
            //           drawable-xxxhdpi
            activity.getDrawable(R.drawable.pixel);
        } catch (Resources.NotFoundException ex) {
            // NOTE optionally, report exception to Crashlytics or just an event to Analytics

            activity.finish();
            activity.startActivity(new Intent(activity, DrawablesValidator.class));
        }
    }

    // NOTE don't care about translations of text messages here, don't put them to strings.xml
    //      we assume, that if user is smart enough to get APK from outside and install it,
    //      then user will definitely understand few messages in English :)
    @SuppressLint("SetTextI18n")
    @Override
    protected void onCreate(Bundle state) {
        super.onCreate(state);

        int dp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
        int dp8 = dp * 8;
        int dp16 = dp * 16;
        int dp80 = dp * 80;

        LinearLayout root = new LinearLayout(this);
        root.setOrientation(LinearLayout.VERTICAL);
        root.setGravity(Gravity.CENTER_HORIZONTAL);
        root.setPadding(dp80, dp16, dp80, dp16);

        Space spaceTop = new Space(this);

        TextView title = new TextView(this);
        title.setPadding(0, dp8, 0, dp8);
        title.setTextSize(20);
        title.setText("Re-install app");

        TextView message = new TextView(this);
        message.setPadding(0, dp8, 0, dp8);
        message.setTextSize(16);
        message.setText("This copy of app is corrupted and can't be launched." +
                "\n\n" +
                "Please, install original version from Google Play");

        Button button = new Button(this);
        button.setPadding(dp16, dp8, dp16, dp8);
        button.setText("Continue");
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + getPackageName())));
                } catch (Exception ex) {
                    Toast.makeText(getApplicationContext(), "Can't open Google Play", Toast.LENGTH_SHORT).show();
                }
            }
        });

        Space spaceBottom = new Space(this);

        int wc = ViewGroup.LayoutParams.WRAP_CONTENT;
        int mp = ViewGroup.LayoutParams.MATCH_PARENT;

        root.addView(spaceTop, lp(0, 0, 1, -1));
        root.addView(title, lp(wc, wc, 0, -1));
        root.addView(message, lp(mp, wc, 0, -1));
        root.addView(button, lp(wc, wc, 0, Gravity.END));
        root.addView(spaceBottom, lp(mp, wc, 1, -1));

        setContentView(root);
    }

    private LinearLayout.LayoutParams lp(int width, int height, int weight, int gravity) {
        LinearLayout.LayoutParams result = new LinearLayout.LayoutParams(width, height);
        result.weight = weight;
        result.gravity = gravity;
        return result;
    }
}
Eldoneldora answered 16/4, 2019 at 9:57 Comment(0)
I
16

The issue is likely to be that your app has been sideloaded, i.e. not installed via the Play Store, and incompatible APKs have been manually installed on those devices.

Inquisitorial answered 30/5, 2018 at 12:7 Comment(16)
No this is not likely the issue as this is only happening in Android 4.Annihilation
Then @keboardsurfer recommendation is best to attempt at reproducing it.Inquisitorial
I am trying to reproduce it by bundletool but it gives error of Cannot install split APKs on device with API level < 21 .Annihilation
It's a bug in bundletool that'll be fixed in the next release. As a temporary workaround, use the extract-apks command to get the APK for the device, then install it using adb install /path/to/app.apkInquisitorial
Thank you so much i followed your instruction and installed the apk on 3 Android devices on Android 4 versions but could not reproduce the the same error in it .Annihilation
Please see the image attached of crash which is happening after adding android aap bundle .Annihilation
Is it SDK 4 as in "4.0" for ICS, or API Level 4 for Donut?Inquisitorial
Its happening in all versions of Android 4 os from 4.1.2 to 4.4.4 versionsAnnihilation
+Pierre The issue still exist with new version of build tool buildToolsVersion '28.0.3'Mader
@Mader As I mentioned, the issue is likely related to the app being sideloaded with only the base APK being installed, nothing indicates it has anything to do with tool versions.Inquisitorial
@Inquisitorial android.content.res.Resources$NotFoundException: File res/drawable/abc_item_background_holo_dark.xml still troubling me very much on all apks , i have tried different codes but still same problem, please help , i think there is something more than being sideloaded as it is only on android 4 versions and there are many phones on android 4 , can't increase the api level now . And if its not possible then please provide some solution like redirecting to play store if this bug happens , thank you so much.)Annihilation
Hello @Inquisitorial is there any work around or hack to avoid this crash i use buildToolsVersion '28.0.3' but it still happens randomly in wide range of devices and operating systems.Overseas
There will be very shortly. I'll update my answer in a week or two once the solution is widely available.Inquisitorial
I have the same problem and can confirm that the installer package is 'com.android.vending' so not due to sideloading. Any update @Pierre?Orthographize
1 year later, still not fixedSpaghetti
Incomplete set of APKs can no longer be installed on Android.Inquisitorial
A
5

As this is happening only on Android 4 devices after migrating to Android App Bundle, i found out a way of this after adding:-

public class App extends Application {

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); }

And in build.gradle:-

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

as explained in this post:- Using android vector Drawables on pre Lollipop crash

Regarding the second question :- Resource Not Found error res/drawable/abc_switch_thumb_material.xml after adding SwitchCompat in Android App Bundle

As this is happening on all Android versions. I Sideloaded the Apk and able to reproduce the same error in logcat , So this can only be fixed by removing the SwitchCompat from my project , i know its a temporary fix and Google should surely do something about it so that at least crash does not happen after sideloading the apk, maybe redirect to play store would be the better option. But crashing of the app after migrating to Android App Bundle is definitely affects the stability of the app as many users do it on regular basis.

Annihilation answered 16/7, 2018 at 5:54 Comment(0)
R
4

You can check users sharing (sideloading) the app from play console Login play console select your app on which you publish app bundle instead of apk.

Select Android Vital -> ANRs & crashes and click on crashes tab.

select install from play

enter image description here

Rafaellle answered 18/5, 2019 at 11:51 Comment(1)
this helped me, if I filter "installed from play" the crashes related to resource not found does not show.Snick
A
1

For Internal testing we cant side load the aab file apks. There only two ways give apk for user before releasing to production.

1) we have to give universal.apk file checking purpose

java -jar bundletool-all-0.12.0.jar build-apks --bundle=(build path)debug.aab --output=(output path)debug.apks --mode=universal

2) we have to upload aab file to playstore then first release for internal testing if every thing works fine then release it production.

Administration answered 23/1, 2020 at 10:31 Comment(0)
M
0

I faced the same issue my app was getting crashes where it was unable to locate fonts and audio files from resources. the issue was that I updated the Gradle URL from 4.10.1 to 5.6.4 in Gradle-wrapper.properties but didn't update the libraries. when I reverted back to 4.10.1 it started working normally.

Mcmanus answered 26/5, 2020 at 12:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.