Java Android App Bundle 在 Android 应用程序中引入了 Resource Not found 崩溃

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/50471888/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 23:38:21  来源:igfitidea点击:

Android App Bundle introduces Resource Not found crash in Android app

javaandroidcrashandroid-app-bundle

提问by gautam kumar

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

通过使用 android 新的 Android App Bundle,我发现 Resource Not Found Crashes 在我的 2 个 Google Play 商店应用程序中:-

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.access0(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 :-

build.gradle 依赖项:-

 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 ?

还有一件事只发生在 Android 4 操作系统上,而不是在新版本的 Android 上。我发现其他应用程序存在相同的资源未找到问题,这在使用 android 应用程序包之前不存在。库或代码中是否存在问题,或者是因为 Android 应用程序包的测试版?

enter image description here

在此处输入图片说明

I have also found the resource drawable due to which it crashes:- enter image description here

我还发现资源可绘制,因为它崩溃了:- 在此处输入图片说明

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

我认为这个问题也与此相关:- 在 Android App Bundle 中添加 SwitchCompat 后错误膨胀类 android.support.design.widget.NavigationView

采纳答案by Nick Fortescue

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.

这几乎可以肯定是用户通过 P2P 共享程序共享(旁加载)应用程序,或者将 APK 上传到网络,然后其他用户从网络下载和安装。

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.

人们习惯于处理非 Android App Bundle 应用程序只是传输和共享主 APK。但是您的 App bundle 应用程序有很多“拆分 APK”,用于资源等内容,这就是节省大小的方式。您可以在帮助页面上阅读有关此过程的所有信息。如果用户在没有安装正确拆分的 APK 的情况下安装主 APK,则应用首次尝试加载资源时将发生“Resources Not found”崩溃。

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.

如果您想支持用户侧载您的应用程序和主 APK,您可以尝试检测这种情况并向用户显示一条消息(不使用任何资源),内容为“请从 Google Play 安装”。或者,您可以决定不支持以这种方式共享 APK 的用户。

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.

我怀疑从长远来看,网站和 P2P 共享程序会更好地正确共享此类 APK,因此我不会花太长时间担心。

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.

如果您在较低的 Android 版本上看到这种情况发生得更频繁,这可能不是由于较低的 Android 版本中的错误造成的。相反,这可能是因为在用户通常使用 P2P 共享应用程序的国家(例如印度),用户也更有可能使用旧版本的手机。

回答by Pierre

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.

问题很可能是您的应用程序被侧载,即未通过 Play 商店安装,并且在这些设备上手动安装了不兼容的 APK。

回答by gautam kumar

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

由于这仅在迁移到 Android App Bundle 后发生在 Android 4 设备上,因此我在添加以下内容后发现了一种方法:-

public class App extends Application {

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); }

And in build.gradle:-

在 build.gradle 中:-

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

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

如本文所述:- 在 Lollipop 崩溃前使用 android vector Drawables

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

关于第二个问题:- 在 Android App Bundle 中添加 SwitchCompat 后,资源未找到错误 res/drawable/abc_switch_thumb_material.xml

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.

因为这发生在所有 Android 版本上。我侧载了 Apk 并能够在 logcat 中重现相同的错误,所以这只能通过从我的项目中删除 SwitchCompat 来解决,我知道这是一个临时修复,谷歌肯定应该对此做些什么,这样至少不会发生崩溃在侧载 apk 后,也许重定向到 Play 商店会是更好的选择。但是迁移到 Android App Bundle 后应用程序崩溃肯定会影响应用程序的稳定性,因为许多用户经常这样做。

回答by Oleksii K.

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

接受的答案是绝对正确的 -这个问题的根源是 APK 文件的旁加载。

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.pngand put it to all of the following folders: drawable-mdpi, drawable-hdpi, drawable-xhdpi, drawable-xxhdpi, drawable-xxxhdpi.

  2. Create simple Activitywhich 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/catchclause.

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

  1. 创建名为 1x1 的图像pixel.png并将其放入以下所有文件夹:drawable-mdpidrawable-hdpidrawable-xhdpidrawable-xxhdpidrawable-xxxhdpi

  2. 创建Activity显示静态消息的简单,例如

    此应用程序副本已损坏,无法启动。

    请从 Google Play 安装原始版本

  3. 然后简单地getDrawable(R.drawable.pixel)Activity.onCreate()包裹在try/catch子句中调用。

  4. 如果异常被捕获,只需完成当前Activity并从第 2 步开始另一个。

Done!

完毕!

Screenshot

截屏

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

这个解决方案运行良好,现在我什至有来自 Firebase Analytics 的数据证实了这一点。

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.

从 46k 的新用户(事件first_open)中,266 名用户收到此错误(已被捕获),221 名用户单击了导致 Google Play 的按钮。

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

这是我的源代码(也可以在 GitHub 上找到):

DrawablesValidator.java

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

回答by Ashish Singh

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

您可以检查用户播放控制台共享(旁加载)应用程序 登录播放控制台选择您发布应用程序包而不是 apk 的应用程序。

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

选择Android Vital -> ANRs & crashes并点击 crashes 标签。

select install from play

选择从播放安装

enter image description here

在此处输入图片说明

回答by EAK TEAM

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.

这有点晚了,但谷歌已经为 引入了新的 API Sideloading crash prevention,它允许您检测使用 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.

例如,考虑一个使用 Android App Bundle 使用拆分 APK 优化应用下载大小的应用。当用户从 Google Play 商店下载应用程序时,它会确保设备下载并安装在该特定设备上运行该应用程序所需的完整拆分 APK 集。当您绕过 Google Play 旁加载应用程序时,平台没有足够的数据来验证应用程序安装,并且无法保证应用程序的正常功能。

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

首先在您的项目中包含 Play Core 库 1.6.0 或更高版本。

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

在您的应用项目的 build.gradle 文件中包含以下内容:

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

您可以使用以下 3 种方法中的一种

1) Register checks through the manifest

1)通过清单注册支票

<?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

2) 在自定义 Application 类中应用检查

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

3) 对内容提供者进行检查

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

阅读更多:https: //developer.android.com/reference/com/google/android/play/core/release-notes?hl=en-419#1-6-0

回答by Yugandhar Vadlamudi

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

对于内部测试,我们无法加载 aab 文件 apks。在发布到生产环境之前,只有两种方式为用户提供 apk。

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

1)我们必须提供universal.apk文件检查的目的

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

java -jar bundletool-all-0.12.0.jar build-apks --bundle=(构建路径)debug.aab --output=(输出路径)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.

2)我们必须将 aab 文件上传到 Playstore,然后首先发布进行内部测试,如果一切正常,然后发布生产。

回答by Ali Mehdi

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.

我遇到了同样的问题,我的应用程序崩溃,无法从资源中找到字体和音频文件。问题是我在 Gradle-wrapper.properties 中将 Gradle URL 从 4.10.1 更新到 5.6.4,但没有更新库。当我恢复到 4.10.1 时,它开始正常工作。