Пакет приложений Android представляет сбой Resource Not found в приложении Android
Используя Android Android Bundle, я обнаружил, что Ресурсы не найдены в 2 приложениях моего магазина Google Play:-
Вот трассировка стека от ткани для одного из приложений:-
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 . Есть ли какая-то проблема в библиотеке или коде, или это из-за бета-версии пакета приложений для Android?
Я также нашел ресурс, доступный для рисования, из-за которого он падает:
Я думаю, что этот вопрос также связан с этим:- Ошибка надувания класса android.support.design.widget.NavigationView после добавления SwitchCompat в Android App Bundle
3 ответа
Поскольку это происходит только на устройствах Android 4 после перехода на Android App Bundle, я нашел способ сделать это после добавления:-
public class App extends Application {
static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); }
И в build.gradle:-
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
как объяснено в этом посте:- Использование векторной графики Android на момент крушения Lollipop.
По второму вопросу:- Resource Not Found ошибка res/drawable/abc_switch_thumb_material.xml после добавления SwitchCompat в комплект приложений Android
Как это происходит на всех версиях Android. Я загрузил Apk и смог воспроизвести ту же ошибку в logcat, так что это можно исправить, только удалив SwitchCompat из моего проекта, я знаю, что это временное исправление, и Google, безусловно, должен что-то с этим сделать, чтобы, по крайней мере, не происходил сбой после боковой загрузки apk, возможно, лучшим вариантом будет перенаправление в магазин воспроизведения. Но сбой приложения после перехода на Android App Bundle определенно влияет на стабильность приложения, так как многие пользователи делают это регулярно.
Это почти наверняка пользователи, разделяющие (загружающие) приложение, либо через программы обмена P2P, либо загружающие APK в Интернет, чем другие пользователи, загружающие и устанавливающие из Интернета.
Люди, привыкшие иметь дело с приложениями, не относящимися к Android App Bundle, просто передают и делятся основным APK. Но в вашем приложении есть множество "разделенных APK" для таких вещей, как ресурсы, именно так происходит экономия размера. Вы можете прочитать все об этом процессе на странице помощи. Если пользователь устанавливает основной APK без установки правильных разделенных APK, то при первой попытке приложения загрузить ресурс произойдет сбой "Ресурсы не найдены".
Если вы хотите, чтобы пользователи загружали ваше приложение и только основной APK, вы можете попытаться обнаружить эту ситуацию и показать пользователю (без использования каких-либо ресурсов) сообщение "Пожалуйста, установите из Google Play". Или вы можете просто решить, что не собираетесь поддерживать пользователей, которые делятся APK-файлами таким образом.
Я подозреваю, что в конечном итоге веб-сайты и программы обмена P2P станут лучше и лучше поделятся такими APK, поэтому я бы не стал слишком долго об этом беспокоиться.
Если вы видите, что это происходит гораздо чаще в более низких версиях Android, это, вероятно, не из-за ошибки в более низких версиях Android. Наоборот, это возможно потому, что в странах, где пользователи обычно используют P2P-приложения (например, в Индии), пользователи также гораздо чаще используют телефоны более старых версий.
Это немного поздно, но Google представил новый API для Sideloading crash prevention
, что позволяет обнаруживать неполную установку приложений, созданных с помощью Android App Bundle.
Например, рассмотрим приложение, которое использует комплекты 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
Принятый ответ является абсолютно правильным - корень этой проблемы - боковая загрузка APK-файла.
Тем не менее, многие люди все еще ищут обходной путь, спрашивая, как правильно справиться с этим делом.
В моем приложении я сделал следующее:
Создать изображение 1x1 с именем
pixel.png
и поместите его во все следующие папки:drawable-mdpi
,drawable-hdpi
,drawable-xhdpi
,drawable-xxhdpi
,drawable-xxxhdpi
,Создать простой
Activity
который показывает статическое сообщение, напримерЭта копия приложения повреждена и не может быть запущена.
Пожалуйста, установите оригинальную версию из Google Play
Тогда просто позвони
getDrawable(R.drawable.pixel)
отActivity.onCreate()
завернут вtry/catch
пункт.Если исключение было обнаружено, просто завершите текущий
Activity
и начните еще один с шага № 2.
Готово!
Это решение работает хорошо, теперь у меня даже есть данные из Firebase Analytics, подтверждающие это.
Из 46 тысяч новых пользователей (событие 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;
}
}
Вероятно, проблема заключается в том, что ваше приложение было загружено, то есть не установлено через Play Store, и несовместимые APK были установлены на этих устройствах вручную.
Вы можете проверить пользователей, разделяющих (загружающих) приложение из игровой консоли. Войдите в игровую консоль и выберите свое приложение, в котором вы публикуете пакет приложений вместо apk.
Выберите Android Vital -> ANRs & crash и нажмите на вкладку crashes.
выберите установить из игры
Для внутреннего тестирования мы не можем загружать файлы aab apks. Есть только два способа предоставить пользователю apk перед выпуском в производство.
1) мы должны указать цель проверки файла universal.apk
java -jar bundletool-all-0.12.0.jar build-apks --bundle=(путь сборки)debug.aab --output=(путь вывода)debug.apks --mode= универсальный
2) мы должны загрузить файл aab в игровой магазин, а затем сначала выпустить его для внутреннего тестирования, если все работает нормально, затем выпустить его в производство.
Из ссылки выше я узнал, что значки, используемые в приложении, должны находиться в папке ресурсов для рисования, а значки запуска должны находиться в папке ресурсов mipmap. Я передал свои иконки, и это сработало для меня.
Я столкнулся с той же проблемой, что и мое приложение вылетало, когда ему не удавалось найти шрифты и аудиофайлы из ресурсов. проблема заключалась в том, что я обновил URL-адрес Gradle с 4.10.1 до 5.6.4 в Gradle-wrapper.properties, но не обновил библиотеки. когда я вернулся к 4.10.1, он начал нормально работать.