首先,它与错误的项目配置无关,如中所述为什么我在谷歌地图上时收到此错误“无法加载 DynamiteLoader:java.lang.ClassNotFoundException:找不到类? https://stackoverflow.com/questions/40701107/why-i-get-this-error-when-on-google-map-failed-to-load-dynamiteloader-java-lan.
有一天,我在 Fabric 中遇到了崩溃高峰(一天内崩溃了约 1300 次)com.google.android.gms.dynamite.DynamiteModule$zza: Remote load failed. No local fallback
,
com.google.android.gms.dynamite.DynamiteModule$zzc: No acceptable module found. Local version is 0 and remote version is 0
例外情况。
我乍一看并不清楚为什么会发生这种情况,因为在那段时间我没有发布任何应用程序更新。经过更深入的调查(总共几天),我发现问题是由Google Play 服务版本和过时的 Google Cast SDK 之间的兼容性已损坏。
我的 Android 应用程序使用 10.2.4 版本的 Google Cast SDK,该版本与某些 Google Play 服务版本不兼容。
我发现2002年11月3日(480-161239932) https://www.apkmirror.com/apk/google-inc/google-play-services/google-play-services-11-3-02-release/google-play-services-11-3-02-480-161239932-android-apk-download/Google Play 服务版本不兼容10.2.4谷歌投射 SDK。 (肯定)还有其他版本的 Google Play 服务与 Google Cast SDK 库不兼容,但我只找到了一个,它足以进行测试和进一步修复。
Having 2002年11月3日(480-161239932) https://www.apkmirror.com/apk/google-inc/google-play-services/google-play-services-11-3-02-release/google-play-services-11-3-02-480-161239932-android-apk-download/设备上安装的 Google Play 服务版本我的应用程序在启动后立即崩溃。值得注意的是,我发现我的设备上的其他应用程序在启动后立即崩溃,并且堆栈跟踪是相同的.
修复崩溃问题
修复对我来说很简单 -我必须将 Google Play 服务从 10.2.4 更新到 11.4.2,
尤其play-services-cast-framework
, play-services-ads
, firebase-core
, firebase-messaging
.
Fabric 中的 Spike 历史:
- 9 月 25 日(约 400 次崩溃),第一次高峰
- 9 月 27 日(约 200 次崩溃)
- 9 月 29 日(约 140 次崩溃)
- 10 月 8 日(约 1300 次崩溃)
10 月 8 日之后,崩溃不再那么严重(每天约 10-20 次崩溃),并且没有再观察到峰值。这意味着用户更新了 Google Play 服务,并且应用程序在启动时不再崩溃。
一旦我更新了 Google Play 服务版本并且用户更新到了新版本的应用程序,崩溃就消失了(每天约 1-2 次崩溃)。
解释发生此崩溃的原因
如您所知,Google Play 服务会在后台自动更新。这意味着有一天用户可以收到与应用程序中使用的 Google Cast SDK 不兼容的 Google Play 服务更新,并且应用程序将崩溃(100%)。
根据我的经验,Google Cast SDK 会出现这种情况,但其他库也可能出现这种情况(没有证据)。
当您从 Google Cast SDK 调用任何方法时,应用程序会崩溃。我已经评论了我的应用程序中依赖 Google Cast SDK 的不同位置,并且应用程序总是崩溃。
详细指南
如果有人好奇如何模仿这次崩溃,这里有详细的指南。
- First of all, we need to uninstall existing version of Google Play Services. This can be achieved from "Google Play Services" application info screen
-
在 Android 设备上安装 11.3.02 (480-161239932) 版本的 Google Play 服务 (apk镜像链接 https://www.apkmirror.com/apk/google-inc/google-play-services/google-play-services-11-3-02-release/google-play-services-11-3-02-480-161239932-android-apk-download/).
adb install -r com.google.android.gms_11.3.02_(480-161239932)-11302480_minAPI23(x86,x86_64)(nodpi)_apkmirror.com.apk
- 访问 Google Cast SDK 时,打开的应用程序和观察者应用程序崩溃。
事故第二次到达
我以为我已经通过更新 Google Play 服务修复了崩溃,但在沉默几周后,我收到通知,具有相同堆栈跟踪的崩溃再次出现。
经过一番调查(又是几天),我能够重现该问题。这是一个悲伤的消息 - 我对这次崩溃无能为力:sad_face:或者至少我还没有找到优雅的解决方案。
好消息是,重新出现的崩溃现象非常罕见(每月约 1-2 次崩溃)。
Google Play 服务自动更新或强制卸载(可能性较小)强制停止打开的应用程序以使 Play 服务更新生效。这是一个不可控的过程,这意味着Android操作系统可以随时静默安装Google Play服务。如果用户打开了应用程序并且 Google Play 服务安装在某个时刻完成,则应用程序将被系统终止,用户需要重新打开它。当应用程序被系统终止时,我们可以在日志中看到与第一种情况完全相同的崩溃堆栈跟踪。
这种情况很难重现,而且只在我身上发生过几次。
但这种情况更有可能发生,因为 Google Play 服务经常更新。
尽管有一种方法可以重现这种崩溃(在现实生活中可能性较小)-“从设备中删除 Google Play 服务更新”。它产生相同的堆栈跟踪。
所以基本上,我们需要开始删除 Google Play 服务更新并快速(我的意思是非常快)打开我们的应用程序。如果我们成功,该应用程序将在启动时被系统杀死,因为 Google Play 服务被删除并且系统会杀死该应用程序。
这是堆栈跟踪:
FATAL EXCEPTION: main
Process: XXX, PID: 26149
java.lang.RuntimeException: Unable to start activity ComponentInfo{XXX/XXX.SomeActivity}: android.view.InflateException: Binary XML file line #0: Binary XML file line #0: Error inflating class fragment
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2733)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2819)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1532)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6321)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by: android.view.InflateException: Binary XML file line #0: Binary XML file line #0: Error inflating class fragment
Caused by: android.view.InflateException: Binary XML file line #0: Error inflating class fragment
Caused by: java.lang.RuntimeException: com.google.android.gms.dynamite.DynamiteModule$zzc: No acceptable module found. Local version is 0 and remote version is 0.
at com.google.android.gms.internal.zzavl.zzbp(Unknown Source)
at com.google.android.gms.internal.zzavl.zza(Unknown Source)
at com.google.android.gms.cast.framework.CastContext.<init>(Unknown Source)
at com.google.android.gms.cast.framework.CastContext.getSharedInstance(Unknown Source)
at com.google.android.gms.cast.framework.media.uicontroller.UIMediaController.<init>(Unknown Source)
at com.google.android.gms.cast.framework.media.widget.MiniControllerFragment.onCreateView(Unknown Source)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:2343)
at android.support.v4.app.FragmentManagerImpl.ensureInflatedFragmentView(FragmentManager.java:1645)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1390)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1640)
at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1896)
at android.support.v4.app.FragmentManagerImpl.onCreateView(FragmentManager.java:3673)
at android.support.v4.app.FragmentController.onCreateView(FragmentController.java:111)
at android.support.v4.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:331)
at android.support.v4.app.BaseFragmentActivityApi14.onCreateView(BaseFragmentActivityApi14.java:39)
at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:65)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:777)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:727)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:858)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821)
at android.view.LayoutInflater.inflate(LayoutInflater.java:518)
at android.view.LayoutInflater.inflate(LayoutInflater.java:426)
at android.view.LayoutInflater.inflate(LayoutInflater.java:377)
at android.support.v7.app.AppCompatDelegateImplV9.setContentView(AppCompatDelegateImplV9.java:287)
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:139)
at XXX.SomeActivity.setContentView(SomeActivity:XXX)
at XXX.SomeActivity.onCreate(SomeActivity:XXX)
at android.app.Activity.performCreate(Activity.java:6760)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1134)
Update
有一个Google Play 服务 12.0.0 发布 https://developers.google.com/android/guides/releases#march_20_2018_-_version_1200,这应该可以解决这个问题:
修复了在具有过时版本的 Google Play 服务的设备上调用 CastContext.getSharedInstance() 导致崩溃的错误。过时的 Google Play 服务版本仍然会导致该方法失败,因此客户端应检查是否有合适的版本。
但事实上,即使更新到 12.0.0 版本后,我仍然看到很多崩溃。当设备上发生 Google Play 服务更新时,会发生崩溃。
为了解决这个问题,我们需要通过检查调用 Cast API 时是否未抛出异常来检查 Cast API 是否可用。
fun isCastApiAvailable(): Boolean {
val isCastApiAvailable = isNotTv(context)
&& GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS
try {
CastContext.getSharedInstance(context)
} catch (e: Exception) {
// track non-fatal
return false
}
return isCastApiAvailable
}
这样我们就可以防止崩溃。如果应用程序位于前台时发生 Play 服务更新,则应用程序可能会被系统终止并重新启动。或者,Cast API 相关功能将不可用(Chromecast 图标不可见)。
因此,我们通过这种方式避免崩溃并报告为非致命事件,只是为了了解这种情况发生的频率。