Android

Android App Bundle introduces Resource Not found crash in Android app

Пакет приложений Android вводит сбой ресурса, не найденного в приложении Android

При использовании нового пакета приложений для Android от Android я получил Resource Not Found ошибку в 2 моих приложениях Google Play Store.

Вот трассировка стека из fabric для одного из приложений:

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 {
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'}

Еще одна вещь, это происходит только в операционной системе Android 4, а не в более новых версиях Android. Я обнаружил, что другие приложения сталкиваются с той же проблемой Resource Not Found, которой не было до использования Android app bundle. Есть ли какая-то проблема в библиотеке или коде, или это из-за бета-версии Android app bundle?

Я также обнаружил, что ресурс можно извлекать, из-за чего он выходит из строя:- Скриншот, показывающий выделенный извлекаемый ресурс, который вызывает проблему.

Я думаю, что этот вопрос также связан с этим: Ошибка Resource Not Found res/drawable/abc_switch_thumb_material.xml после добавления SwitchCompat в Android App Bundle

Переведено автоматически
Ответ 1

Почти наверняка пользователи делятся (загружают приложение отдельно) либо через программы обмена P2P, либо загружают APK в Интернет, затем другие пользователи загружают и устанавливают из Интернета.

Люди, привыкшие иметь дело с приложениями, не относящимися к Android App Bundle, просто переносят и предоставляют общий доступ к основному APK. Но в вашем приложении App bundle есть множество "разделенных APK" для таких вещей, как ресурсы, именно так происходит экономия размера. Вы можете прочитать все об этом процессе на странице справки. Если пользователь устанавливает основной APK-файл без установки правильных разделенных APK-файлов, то при первой попытке приложения загрузить ресурс произойдет сбой "Ресурсы не найдены".

Если вы хотите поддержать пользователей, загружающих ваше приложение отдельно, и только основной APK, вы могли бы попытаться обнаружить эту ситуацию и отобразить пользователю сообщение (без использования каких-либо ресурсов) с надписью "Пожалуйста, установите из Google Play". Или вы могли бы просто решить, что не собираетесь поддерживать пользователей, которые делятся APK таким образом.

Я подозреваю, что в долгосрочной перспективе веб-сайты и программы обмена P2P улучшат возможность правильного обмена такими APK, поэтому я бы не стал слишком долго беспокоиться об этом.

Если вы видите, что это происходит гораздо чаще на более низких версиях Android, вероятно, это не связано с ошибкой в более низких версиях Android. Скорее всего, это связано с тем, что в странах, где пользователи обычно используют приложения для совместного использования P2P (например, в Индии), пользователи также с гораздо большей вероятностью будут пользоваться телефонами более старой версии.

Ответ 2

Немного поздно, но Google представила новый API для Sideloading crash prevention, который позволяет обнаруживать незавершенную установку приложений, созданных с использованием пакета приложений для Android.


Для примера рассмотрим приложение, которое использует пакеты приложений Android для оптимизации размера загружаемого приложения с помощью разделенных APK. Когда пользователь загружает приложение из магазина Google Play, это гарантирует, что устройство загрузит и установит полный набор разделенных APK-файлов, необходимых для запуска этого приложения на данном конкретном устройстве. Когда вы обходите Google Play для дополнительной загрузки приложения, платформа не располагает достаточными данными для подтверждения установки приложения, и надлежащая функциональность приложения не гарантируется.


Для начала включите в свой проект библиотеку Play Core версии 1.6.0 или выше.

Включите следующее в файл 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'
}
}

Вы можете использовать 1 из 3 приведенных ниже методов


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) Примените проверки в пользовательском классе приложения


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

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

super.onCreate();
...
}
}

3) Примените проверки к контент-провайдерам


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

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

super.onCreate();
...
}
}

Читать далее : https://developer.android.com/reference/com/google/android/play/core/release-notes ?hl=en-419#1-6-0

Ответ 3

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;
}
}
Ответ 4

Проблема, вероятно, заключается в том, что ваше приложение было загружено в стороннем режиме, т. Е. Установлено не через Play Store, а на эти устройства были вручную установлены несовместимые APK-файлы.

java android