如何使用 AmazonSNSClient 避免 Android 9 中的应用程序崩溃?

How to avoid appcrashes in Android 9 with AmazonSNSClient?

在 Android 9 (API 28) 中,我的应用程序在创建新的 AmazonSNSClient 时崩溃(在 API 26 中,我没有收到任何错误):

AmazonSNSClient pushClient = new AmazonSNSClient(credentialsProvider);

我的 LogCat 说:

    java.lang.NoClassDefFoundError: Failed resolution of: Lorg/apache/commons/logging/LogFactory;
        at com.amazonaws.AmazonWebServiceClient.<clinit>(AmazonWebServiceClient.java:55)
        at myapp.service.AWSMessagingService.createEndpoint(AWSMessagingService.java:170)
        at myapp.service.AWSMessagingService.registerWithSNS(AWSMessagingService.java:103)
        at myapp.service.PushNotificationService.sendRegistrationToAWS(PushNotificationService.java:109)
        at myapp.service.PushNotificationService.onNewToken(PushNotificationService.java:105)
        at com.google.firebase.messaging.FirebaseMessagingService.zzd(Unknown Source:86)
        at com.google.firebase.iid.zzg.run(Unknown Source:4)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at com.google.android.gms.common.util.concurrent.zza.run(Unknown Source:7)
        at java.lang.Thread.run(Thread.java:764)
     Caused by: java.lang.ClassNotFoundException: Didn't find class "org.apache.commons.logging.LogFactory" on path: DexPathList[[zip file "/data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/base.apk", zip file "/data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_dependencies_apk.apk", zip file "/data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_resources_apk.apk", zip file "/data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_0_apk.apk", zip file "/data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_1_apk.apk", zip file "/data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_2_apk.apk", zip file "/data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_3_apk.apk", zip file "/data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_4_apk.apk", zip file "/data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_5_apk.apk", zip file "/data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_6_apk.apk", zip file "/data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_7_apk.apk", zip file "/data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_8_apk.apk", zip file "/data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_9_apk.apk"],nativeLibraryDirectories=[/data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/lib/x86, /data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/base.apk!/lib/x86, /data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_dependencies_apk.apk!/lib/x86, /data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_resources_apk.apk!/lib/x86, /data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_0_apk.apk!/lib/x86, /data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_1_apk.apk!/lib/x86, /data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_2_apk.apk!/lib/x86, /data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_3_apk.apk!/lib/x86, /data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_4_apk.apk!/lib/x86, /data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_5_apk.apk!/lib/x86, /data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_6_apk.apk!/lib/x86, /data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_7_apk.apk!/lib/x86, /data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_8_apk.apk!/lib/x86, /data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_slice_9_apk.apk!/lib/x86, /system/lib]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
        at com.amazonaws.AmazonWebServiceClient.<clinit>(AmazonWebServiceClient.java:55) 
        at myapp.service.AWSMessagingService.createEndpoint(AWSMessagingService.java:170) 
        at myapp.service.AWSMessagingService.registerWithSNS(AWSMessagingService.java:103) 
        at myapp.service.PushNotificationService.sendRegistrationToAWS(PushNotificationService.java:109) 
        at myapp.service.PushNotificationService.onNewToken(PushNotificationService.java:105) 
        at com.google.firebase.messaging.FirebaseMessagingService.zzd(Unknown Source:86) 
        at com.google.firebase.iid.zzg.run(Unknown Source:4) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
        at com.google.android.gms.common.util.concurrent.zza.run(Unknown Source:7) 
        at java.lang.Thread.run(Thread.java:764) 
2018-12-17 09:25:07.483 10291-10344/myapp E/AndroidRuntime:     Suppressed: java.io.IOException: No original dex files found for dex location /data/app/myapp-grqOb2dmxK1zDq9u44b9Rg==/split_lib_resources_apk.apk
        at dalvik.system.DexFile.openDexFileNative(Native Method)
        at dalvik.system.DexFile.openDexFile(DexFile.java:354)
        at dalvik.system.DexFile.<init>(DexFile.java:101)
        at dalvik.system.DexFile.<init>(DexFile.java:75)
        at dalvik.system.DexPathList.loadDexFile(DexPathList.java:394)
        at dalvik.system.DexPathList.makeDexElements(DexPathList.java:354)
        at dalvik.system.DexPathList.<init>(DexPathList.java:164)
        at dalvik.system.BaseDexClassLoader.<init>(BaseDexClassLoader.java:74)
        at dalvik.system.BaseDexClassLoader.<init>(BaseDexClassLoader.java:65)
        at dalvik.system.PathClassLoader.<init>(PathClassLoader.java:64)
        at com.android.internal.os.ClassLoaderFactory.createClassLoader(ClassLoaderFactory.java:73)
        at com.android.internal.os.ClassLoaderFactory.createClassLoader(ClassLoaderFactory.java:88)
        at android.app.ApplicationLoaders.getClassLoader(ApplicationLoaders.java:74)
        at android.app.ApplicationLoaders.getClassLoader(ApplicationLoaders.java:40)
        at android.app.LoadedApk.createOrUpdateClassLoaderLocked(LoadedApk.java:727)
        at android.app.LoadedApk.getClassLoader(LoadedApk.java:810)
        at android.app.LoadedApk.getResources(LoadedApk.java:1032)
        at android.app.ContextImpl.createAppContext(ContextImpl.java:2345)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5749)
        at android.app.ActivityThread.access00(ActivityThread.java:199)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1650)
        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(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

我发现如果我不在 build.gradle 中从 "com.amazonaws:aws-android-sdk-sns" 中排除 "commons-logging" 就可以避免错误,所以我替换了:

implementation 'com.amazonaws:aws-android-sdk-sns:2.2.0', {
    exclude module: 'commons-logging'
}

与:

implementation 'com.amazonaws:aws-android-sdk-sns:2.2.0'

该应用现在可以正常运行,但我无法构建已签名的 APK,因为我得到 错误 "DuplicatePlatformClasses: Duplicate Platform Classes" 和 我的皮棉报告说:

commons-logging defines classes that conflict with classes now provided by Android. Solutions include finding newer versions or alternative libraries that don't have the same problem (for example, for httpclient use HttpUrlConnection or okhttp instead), or repackaging the library using something like jarjar. There are a number of libraries that duplicate not just functionality of the Android platform but using the exact same class names as the ones provided in Android -- for example the apache http classes. This can lead to unexpected crashes.

To solve this, you need to either find a newer version of the library which no longer has this problem, or to repackage the library (and all of its dependencies) using something like the jarjar tool, or finally, rewriting the code to use different APIs (for example, for http code, consider using HttpUrlConnection or a library like okhttp). Note: This issue has an associated quickfix operation in Android Studio and IntelliJ IDEA. To suppress this error, use the issue id "DuplicatePlatformClasses" as explained in the Suppressing Warnings and Errors section.

所以我在我的项目文件夹的终端中 运行 "gradlew app:dependencies > dependencies.txt" 发现 "com.amazonaws:aws-android-sdk-sns:2.2.0" 使用 "commons-logging:commons-logging:1.1.1" 但我也可以找到 "commons-logging:commons-logging:1.2"我猜是 "provided by Android"?

那么,如果我排除 "commons-logging:commons-logging:1.1.1",为什么 "com.amazonaws:aws-android-sdk-sns:2.2.0" 不使用 "commons-logging:commons-logging:1.2",我该如何解决这个问题?

我可以通过将 "com.amazonaws:aws-android-sdk-sns:2.2.0" 更新到更新的版本来解决错误(在我的例子中是 "com.amazonaws:aws-android-sdk-sns:2.9.1")。

Android9中的NoClassDefFoundError也在这个issue中被跟踪: https://github.com/aws-amplify/aws-sdk-android/issues/476