通过使用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)
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上。我发现其他应用程序遇到了与使用Android应用程序包之前不存在的资源未找到相同的问题。库或代码中是否存在问题,或者是因为Android应用程序包的测试版?
我认为这个问题也与此有关: - Error inflating class android.support.design.widget.NavigationView after adding SwitchCompat in Android App Bundle
这几乎可以肯定是用户通过P2P共享程序共享(加载)应用程序,或者将APK上传到网络,然后将其他用户从网上下载和安装。
过去常常处理非Android App Bundle应用的用户只需转移并共享主APK。但是你的应用程序包应用程序有很多“拆分APK”用于资源等事情,这就是节省大小的方式。你可以阅读有关这个过程on the help page的所有信息。如果用户在未安装正确拆分APK的情况下安装主APK,则在应用首次尝试加载资源时将发生“未找到资源”崩溃。
如果您想支持用户侧载您的应用程序而只支持主APK,您可以尝试检测此情况并向用户显示消息(不使用任何资源),并显示“请从Google Play安装”。或者您可能只是决定不支持以这种方式共享APK的用户。
我怀疑从长远来看,网站和P2P共享程序将更好地分享这些APK,所以我不会花太多时间担心它。
如果你在较低的Android版本上看到这种情况发生得更频繁,这可能不是因为较低Android版本中的错误。相反,可能是因为在用户通常P2P共享应用程序的国家(例如印度),用户也更有可能使用旧版手机。
问题可能是您的应用程序已被侧载,即未通过Play商店安装,并且已在这些设备上手动安装了不兼容的APK。
由于这种情况仅在迁移到Android App Bundle后的Android 4设备上发生,我在添加后发现了一种方法: -
public class App extends Application {
static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); }
在build.gradle中: -
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
如本文所述: - Using android vector Drawables on pre Lollipop crash
因为这种情况发生在所有Android版本上。我重载Apk并且能够在logcat中重现相同的错误,所以这只能通过从我的项目中删除SwitchCompat来修复,我知道它是一个临时修复,谷歌肯定会对它做一些事情,以便至少崩溃不会发生在侧载apk后,可能重定向到Play商店将是更好的选择。但是,迁移到Android App Bundle后应用程序崩溃肯定会影响应用程序的稳定性,因为很多用户会定期执行此操作。
接受的答案绝对正确 - root of this issue是侧载APK文件。
然而,很多人仍在寻找解决方法,询问如何正确处理此案例。
在我的应用中,我做了以下事情:
pixel.png
的1x1图像并将其放入以下所有文件夹: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的数据确认了这一点。
来自46k的新用户(事件first_open
)266个用户收到此错误(已被捕获),221个用户点击了导致Google Play的按钮。
这是我的源代码(也可用on GitHub):
drawable是validator.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;
}
}
这有点晚了,但Google已经为Sideloading crash prevention
引入了新的API,它允许您检测使用Android App Bundle构建的应用程序的不完整安装。
例如,考虑使用Android应用套件来使用拆分APK优化应用下载大小的应用。当用户从Google Play商店下载应用时,它会确保设备下载并安装在该特定设备上运行该应用所需的全套拆分APK。当您绕过Google Play以侧载应用时,该平台没有足够的数据来验证应用安装,并且无法保证应用的正常功能。
首先,在项目中包含Play Core 1.6.0或更高版本。
在app项目的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'
}
}
您可以使用以下3种方法中的1种
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)在自定义Application类中应用检查
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
从上面的链接我了解到应用程序中使用的图标应该在drawable资源文件夹中,而启动图标应该在mipmap资源文件夹中。我转移了我的图标,它对我有用。
您可以检查用户从play console共享(侧载)应用程序登录播放控制台选择您发布应用程序包而不是apk的应用程序。
选择Android Vital - > ANRs&crashes并单击崩溃选项卡。
从播放中选择安装