Android App Bundle在Android应用中引入了资源未找到崩溃

gau*_*mar 44 java crash android android-app-bundle

通过使用Android新Android应用程序包我发现我的2个谷歌游戏商店应用程序中找不到资源崩溃: -

这是应用程序之一的面料堆栈跟踪: -

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)
Run Code Online (Sandbox Code Playgroud)

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'}
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述

我还发现了由于崩溃导致的资源可绘制: - 在此输入图像描述

我认为这个问题也与此有关: - 在Android应用程序包中添加SwitchCompat后错误输出类android.support.design.widget.NavigationView

Nic*_*cue 34

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

过去常常处理非Android App Bundle应用的用户只需转移并共享主APK.但是你的应用程序包应用程序有很多"拆分APK"用于资源等事情,这就是节省大小的方式.您可以在帮助页面上阅读有关此过程的所有信息.如果用户在未安装正确拆分APK的情况下安装主APK,则在应用首次尝试加载资源时将发生"未找到资源"崩溃.

如果您想支持用户侧载您的应用程序而只支持主APK,您可以尝试检测此情况并向用户显示消息(不使用任何资源),并显示"请从Google Play安装".或者您可能只是决定不支持以这种方式共享APK的用户.

我怀疑从长远来看,网站和P2P共享程序将更好地分享这些APK,所以我不会花太多时间担心它.

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

  • @NickFortescue 我已经确认即使对于不旁加载应用程序的用户也会发生此问题。我有特别来自 Vivo 设备的报告。我怀疑 Play 没有正确生成 APK。我可以采取什么措施来帮助解决这个问题? (2认同)

EAK*_*EAM 14

这有点晚了,但是Google引入了的新API Sideloading crash prevention,该API 可让您检测使用Android App Bundle构建的应用程序的安装不完整。

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

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

在您的应用程序项目的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'
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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>
Run Code Online (Sandbox Code Playgroud)

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

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

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

        super.onCreate();
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

3)将检查应用于内容提供商

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

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

        super.onCreate();
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • MissingSplitsManagerFactory 现已弃用,并附有评论:“该功能现已过时。在启用 Play Protect 或在 Android 10 上运行的设备上,现在会阻止缺少拆分的安装。” (2认同)

Pie*_*rre 11

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

  • 这是bundletool中的一个错误,将在下一个版本中修复.作为临时解决方法,使用`extract-apks`命令获取设备的APK,然后使用`adb install/path/to/app.apk'安装它. (2认同)
  • + Pierre这个问题对于新版本的构建工具buildToolsVersion '28 .0.3'仍然存在 (2认同)

Ole*_* K. 7

接受的答案是绝对正确的- 此问题的根源是侧面加载APK文件。

但是,许多人仍在寻找解决方法,询问如何正确处理此案。

在我的应用程序中,我执行了以下操作:

  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开始另一个。

做完了!

屏幕截图

该解决方案效果很好,现在我什至从Firebase Analytics获得数据也证实了这一点。

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

这是我的源代码(也可以在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;
    }
}
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

7647 次

最近记录:

6 年,2 月 前