Android App Bundle introduces Resource Not found crash in Android app

走远了吗. 提交于 2019-11-26 10:28:58

问题


By using android new Android App Bundle i have found Resource Not Found Crashes in 2 of my google play store apps :-

Here is the stacktrace from fabric for one of the app:-

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 new versions of Android .What i have found that other app is having the same problem of Resource Not Found which was not existing before using android app bundle . Is there some problem in library or code or it is because of beta version of Android app bundle ?

I have also found the resource drawable due to which it crashes:-

I think this Question is Also Related to this:- Error inflating class android.support.design.widget.NavigationView after adding SwitchCompat in Android App Bundle


回答1:


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.




回答2:


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




回答3:


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.




回答4:


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!

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;
    }
}



回答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.




回答6:


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




回答7:


https://ourcodeworld.com/articles/read/331/android-error-no-resource-found-that-matches-the-given-name-at-icon-with-value-drawable-icon

From the link above i learnt that icons used in the app should be in the drawable resource folder while launch icons should be in the mipmap resource folder. I transfered my icons and it worked for me.



来源:https://stackoverflow.com/questions/50471888/android-app-bundle-introduces-resource-not-found-crash-in-android-app

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!