【问题标题】:App sometimes crashes with Resources$NotFoundException after switching to android app bundle distribution切换到 Android 应用程序包分发后,应用程序有时会因 Resources$NotFoundException 而崩溃
【发布时间】:2019-02-27 09:49:29
【问题描述】:

应用每月有超过 20000 名活跃用户。 它已经在 google play 上发布了几个月。 在我最近从使用 .apk 的分发切换到使用 .aab 的分发后,我开始在 crashlytics 和 google play store 上收到随机崩溃。在引入崩溃的构建中没有进行其他重大更改。

崩溃发生在应用程序的第一个屏幕上,同时扩展了 xml 布局。有问题的 xml 布局是一个简单的初始屏幕,仅包含一个图像视图和一个文本视图。 imageview 是 android.widget.ImageView,不是兼容版本,它显示 png 图像,而不是矢量图像。该图像存在于所有可绘制文件夹变体中:drawable、drawable-mdpi、...、drawable-xxxhdpi。

Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.company/com.company.ui.splash.SplashActivity}: android.view.InflateException: Binary XML file line #14: Binary XML file line #14: Error inflating class ImageView
          at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
          at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
          at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
          at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
          at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
          at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
          at android.os.Handler.dispatchMessage(Handler.java:106)
          at android.os.Looper.loop(Looper.java:193)
          at android.app.ActivityThread.main(ActivityThread.java:6669)
          at java.lang.reflect.Method.invoke(Method.java)
          at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:495)
          at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

   Caused by android.view.InflateException: Binary XML file line #14: Binary XML file line #14: Error inflating class ImageView


   Caused by android.view.InflateException: Binary XML file line #14: Error inflating class ImageView


   Caused by android.content.res.Resources$NotFoundException: Drawable (missing name) with resource ID #0x7f0800b2


   Caused by android.content.res.Resources$NotFoundException: Unable to find resource ID #0x7f0800b2
          at android.content.res.ResourcesImpl.getResourceName(ResourcesImpl.java:255)
          at android.content.res.ResourcesImpl.loadDrawableForCookie(ResourcesImpl.java:785)
          at android.content.res.ResourcesImpl.loadDrawable(ResourcesImpl.java:631)
          at android.content.res.Resources.loadDrawable(Resources.java:897)
          at android.content.res.TypedArray.getDrawableForDensity(TypedArray.java:955)
          at android.content.res.TypedArray.getDrawable(TypedArray.java:930)
          at android.widget.ImageView.<init>(ImageView.java:189)
          at android.widget.ImageView.<init>(ImageView.java:172)
          at android.support.v7.widget.AppCompatImageView.<init>(AppCompatImageView.java:71)
          at android.support.v7.widget.AppCompatImageView.<init>(AppCompatImageView.java:67)
          at android.support.v7.app.AppCompatViewInflater.createImageView(AppCompatViewInflater.java:181)
          at android.support.v7.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:105)
          at android.support.v7.app.AppCompatDelegateImplV9.createView(AppCompatDelegateImplV9.java:1035)
          at android.support.v7.app.AppCompatDelegateImplV9.onCreateView(AppCompatDelegateImplV9.java:1092)
          at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:772)
          at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
          at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
          at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
          at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
          at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
          at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
          at android.support.v7.app.AppCompatDelegateImplV9.setContentView(AppCompatDelegateImplV9.java:287)
          at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:139)
          at com.company.ui.splash.SplashActivity.onCreate(SplashActivity.java:58)
          at android.app.Activity.performCreate(Activity.java:7136)
          at android.app.Activity.performCreate(Activity.java:7127)
          at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
          at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
          at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
          at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
          at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
          at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
          at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
          at android.os.Handler.dispatchMessage(Handler.java:106)
          at android.os.Looper.loop(Looper.java:193)
          at android.app.ActivityThread.main(ActivityThread.java:6669)
          at java.lang.reflect.Method.invoke(Method.java)
          at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:495)
          at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

导致崩溃的部分xml文件:

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_above="@id/center"
    android:layout_centerHorizontal="true"
    android:src="@drawable/logo" />

崩溃发生在所有 android 版本上,从 4.1.2 到 9.0。

除了其他设备外,我还收到了来自 Google Pixel 和 Nexus 5X 的崩溃,这两个设备均未获得 root 权限。我碰巧拥有这两种设备。我尝试通过 google play 和侧载服务(例如 pureapk)在它们上安装我的应用程序,但我无法重现崩溃。

这个问题类似于Android App Bundle introduces Resource Not found crash in Android app,但是在那个问题中,作者能够通过使用vector drawable compat来解决他的问题。这不是我的情况。

似乎整个资源文件夹都以某种方式从 apk 中丢失,尽管很难测试这个假设。我无法重现该问题,因此我将重新发布该应用程序并等待几天看看崩溃发生了什么变化,我宁愿不对实时用户进行测试。

当这个错误发生时,它通常会在同一台设备上连续发生多次,这让我相信遇到这个错误的用户永远无法启动应用程序。另外,我知道一些以前使用该应用程序的用户不能再使用它了。

所以,总结一下:
1. 在google play上切换到android应用程序包分发后立即开始出现崩溃
2. 应用程序在首次尝试恢复可绘制资源时崩溃 - 一个简单的 png 图像
3.崩溃不是android-version特定的;它发生在有根和无根设备上
4.如果用户遇到这个bug,他可能会永远卡住

是什么导致了这个崩溃?有解决办法吗?

===========

更新:阅读下面的答案后,我得出的结论是,唯一的解决方法是检测侧载安装,然后在没有任何可绘制资源或样式的情况下打开活动,并链接到 Google Play 和带有旧的官方网站-学校 apk 文件。然后用户可以从其他来源重新下载应用程序。

这是我用来检测应用程序是否被侧载的代码(如果您的应用程序中没有本机库,您可能需要删除 nativeLibrariesPresent 部分):

private fun isValidInstallation(): Boolean {
    var resourcesPresent: Boolean
    try {
        // Any drawable id will suffice
        val logo = ResourcesCompat.getDrawable(resources, R.drawable.logo_white, null)
        resourcesPresent = logo != null
    } catch (e: Exception) {
        resourcesPresent = false
    }

    if (!resourcesPresent) {
        Timber.e("No drawable resources detected inside app")
    }

    var nativeLibrariesPresent: Boolean
    try {
        val nativeLibraryDir = File(applicationInfo.nativeLibraryDir)
        val primaryNativeLibraries = nativeLibraryDir.list()
        nativeLibrariesPresent = primaryNativeLibraries.isNotEmpty()
    } catch (e: Exception) {
        nativeLibrariesPresent = false
    }

    if (!nativeLibrariesPresent) {
        Timber.e("No native libraries detected inside app")
    }

    return resourcesPresent && nativeLibrariesPresent
}

在您在主要活动中执行任何操作之前,您需要开始替代活动:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    if (!isValidInstallation()) {
        val intent = Intent(this, InvalidInstallationActivity::class.java)
        startActivity(intent)
        finish()
        return
    }

    setContentView(R.layout.activity_main)
    ...

InvalidInstallationActivity 可以使用 xml 布局,如果您不按语言 (language { enableSplit = false }) 拆分 aab,它可以使用字符串资源,但它不能使用任何可绘制资源。

【问题讨论】:

  • 我不完全熟悉拆分 apk 的工作原理,但我想知道 @drawable/logo 是否仅适用于某些屏幕密度,因此不包括用于例如xxhdpi 设备
  • @BenP。徽标适用于所有密度。此外,我已经尝试在不同的设备上安装该应用程序的所有版本,并且从未崩溃过。我还验证了即使你只在你的 aab 中放了 1 个版本的图像(比如只有 xxhdpi 版本),生成的 apk 仍然可以在更低和更高密度的设备上运行。
  • @yuval 你是对的,另一个问题是早些时候提出的,但在我的问题得到答案一个月后得到了相同的答案。那我就结束我的问题了。
  • @mochadwi 是的,在我添加 InvalidInstallationActivity 后,这个崩溃从 crashlytics 中消失了。

标签: android google-play


【解决方案1】:

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

人们习惯于处理非 Android App Bundle 应用程序只是转移和共享主 APK。但是您的 App bundle 应用程序有很多用于资源之类的“拆分 APK”,这就是节省大小的方式。您可以阅读有关此过程的所有信息on the help page。如果用户在安装主 APK 时未安装正确的拆分 APK,则应用第一次尝试加载资源时会发生“找不到资源”崩溃。

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

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

【讨论】:

  • 我不认为它是这样工作的。如果生成的 apk 缺少特定的密度,设备将使用另一个可用的密度。我已经用 bundletool 对此进行了测试。如果您在 xxhdpi 设备上安装 ldpi 版本,它可以工作。图像模糊,但不会崩溃。 mdpi 设备上的 xxxhdpi 版本相同。而且我认为 google play 实际上并没有使用“拆分 APK”。如果您在 google play console 中点击该应用程序,您可以看到它实际上使用“独立”APK,因此每个用户最终仍然只获得 1 个 apk 文件,它包含的资源更少。这并不能解释为什么图像完全丢失
  • 相信我,Google Play 确实使用拆分 APK(我在 Google Play 上工作)。这些独立的 APK 用于调试,而不是交付给用户的内容。有关详细信息,请参阅此帮助页面:developer.android.com/guide/app-bundle/#dynamic_delivery
  • 我已经检查过这个问题主要发生在有根设备中。启动屏幕,XML 布局的第一行因 Resources$NotFoundException 而崩溃。
  • 我怀疑这在 Google 的发布前报告中出现了问题。 developer.android.com/distribute/best-practices/launch/…。我会调查的。 @KasiaK。
  • 嗨@NickFortescue。我们在我们的应用程序中看到了同样的问题。看来,OEM 备份工具(来自三星和华为)是问题所在,因为圣诞节后崩溃率增加了(新设备!?)。该问题的最佳做法是什么?因为我们需要PNG作为资产,所以我们不能完全切换到VectorDrawables。我不知道恢复的应用程序是否将 PlayStore 显示为安装源。如果没有,我可以向用户显示 AlertDialog 以重新安装应用程序,但在不知情的情况下,我无能为力。 - PS:在我们的应用程序中,我们不允许备份。
【解决方案2】:

您可以通过使用 com.google.android.play.core.missingsplits.MissingSplitsDetectingApplication 作为您的应用程序或在您自己的应用程序中执行此操作来解决此问题:

class MyApplication : Application() {
    override fun onCreate() {
        if (MissingSplitsManagerFactory.create(this).disableAppIfMissingRequiredSplits()) {
            // Skip app initialization when the app is missing required splits.
            return
        }
        super.onCreate()
        // ...
    }
}

为此,您需要 google play 核心依赖项。仅供参考:它已经是 deprecated:缺少所需的拆分已经被 Google Play 保护和 Android 10 或更高版本的设备自动捕获。

【讨论】:

    猜你喜欢
    • 2016-11-09
    • 1970-01-01
    • 2019-05-15
    • 1970-01-01
    • 2017-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-17
    相关资源
    最近更新 更多