Android应用崩溃三星棒棒糖设备上的NoClassDefFoundError

我们最近将我们应用程序的minSdkVersion从16(Jellybean)撞到了21(Lollipop)。 虽然我们使用我们的应用程序主要使用调试版本进行了广泛的测试,但是我们现在面临着应用程序启动时的大量生产崩溃,主要是老三星设备上(注3和S4是最糟糕的),而且总是在棒棒糖上。

错误是

Fatal Exception: java.lang.NoClassDefFoundError: com.retailconvergence.ruelala.delegate.GoogleLoginDelegate at com.retailconvergence.ruelala.delegate.LifecycleDelegateManager.addDelegateOfType(LifecycleDelegateManager.java:48) at com.retailconvergence.ruelala.extensions.activity.LifecycleDelegateActivity.addDelegateOfType(LifecycleDelegateActivity.java:55) at com.retailconvergence.ruelala.activity.SplashActivity.setupDelegates(SplashActivity.java:198) at com.retailconvergence.ruelala.activity.SplashActivity.onCreate(SplashActivity.java:60) at android.app.Activity.performCreate(Activity.java:6288) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2758) at android.app.ActivityThread.access$900(ActivityThread.java:177) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1448) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:145) at android.app.ActivityThread.main(ActivityThread.java:5942) at java.lang.reflect.Method.invoke(Method.java) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194) 

SplashActivity是应用程序最初的开发活动。 没有找到的课程是一个历史悠久的课程,而不是新引入的课程。 作为最新版本的一部分,我们升级到Android Studio 3并引入了Kotlin代码,但是我不认为这些问题与此问题有关。 在构建中我们不使用proguard。

我知道,当minSdkVersion是21岁以上,有关使用艺术,而不是Dalvik,所以我想知道是否有一些缺陷,三星棒棒糖设备仍然在寻找类现在主要的dex文件?

模块级的build.gradle:

 import java.text.SimpleDateFormat import java.util.concurrent.TimeUnit apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'io.fabric' apply plugin: 'spoon' // Manifest version information def versionMajor = 4 def versionMinor = 2 def versionPatch = 0 def versionBuild = 0 // bump for dogfood builds, public betas, etc. ext.versionReleaseDate="OCT-13-2017" // UPDATE THIS WHEN YOU BUMP THE VERSIONS ABOVE FOR A NEW RELEASE MMM-dd-yyy repositories { mavenCentral() maven { url 'https://maven.fabric.io/public' } maven { url 'http://salesforce-marketingcloud.github.io/JB4A-SDK-Android/repository' } maven { url "https://maven.google.com" } maven { url "http://maven.tealiumiq.com/android/releases/" } } def getCountOfHoursSinceVersionUpdate() { def currentDate = new Date() def format = new SimpleDateFormat("MMM-dd-yyyy") def buildDate = (Date)format.parse(versionReleaseDate) return (Integer)((currentDate.getTime() - buildDate.getTime()) / TimeUnit.HOURS.toMillis(1)) } android { compileSdkVersion 26 buildToolsVersion '26.0.1' defaultConfig { targetSdkVersion 25 /** * Increment versionCode by commit count */ versionCode versionMajor * 100000 + versionMinor * 10000 + versionPatch * 1000 + versionBuild + getCountOfHoursSinceVersionUpdate() testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" // Enabling multidex support. :( multiDexEnabled true def manifestPath = project(':').file('app/src/androidTest/AndroidManifest.xml') buildConfigField "String", "MANIFEST_PATH", "\"" + manifestPath + "\"" def resPath = project(':').file('app/src/main/res/') buildConfigField "String", "RES_PATH", "\"" + resPath + "\"" def assetPath = project(':').file('app/src/prod/assets/') buildConfigField "String", "ASSET_PATH", "\"" + assetPath + "\"" } dexOptions { javaMaxHeapSize "8g" dexInProcess true // the magic line } flavorDimensions "debugDimension" /** * productFlavors override defaultConfig properties as well as force gradle to look in the new * folders that we have created to differentiate the build assets and manifests. * src/dev, src/prod */ productFlavors { dev { minSdkVersion 21 applicationId "com.retailconvergence.ruelala.dev" versionName "${versionMajor}.${versionMinor}.0${versionPatch}" manifestPlaceholders = [optimizelyId: "optly4740131949"] dimension "debugDimension" } prod { minSdkVersion 21 applicationId "com.retailconvergence.ruelala" versionName "${versionMajor}.${versionMinor}.${versionPatch}" manifestPlaceholders = [optimizelyId: "optly4752051515"] dimension "debugDimension" } } signingConfigs { prod { //the key is up a level, don't include in the modules storeFile file("../RueLaLaKeystore") storePassword "Boutiques" keyAlias "rue la la" keyPassword "Boutiques" } } buildTypes { release { signingConfig signingConfigs.prod ext.betaDistributionReleaseNotesFilePath = 'release_notes.txt' ext.betaDistributionGroupAliases = 'AndroidTesters' ext.betaDistributionNotifications = true } debug { versionNameSuffix '-dev' signingConfig signingConfigs.prod // to get coverage report, set testCoverageEnabled to true and run gradle task called createDevelopmentDebugAndroidTestCoverageReport // Note that test coverage doesn't seem to work on Samsung devices, other brand or emulator should work though testCoverageEnabled = false ext.betaDistributionReleaseNotesFilePath = 'release_notes.txt' ext.betaDistributionGroupAliases = 'AndroidTesters' ext.betaDistributionNotifications = true } } packagingOptions { exclude 'META-INF/LICENSE.txt' exclude 'META-INF/NOTICE.txt' exclude 'META-INF/LICENSE' exclude 'META-INF/NOTICE' exclude 'LICENSE.txt' exclude 'LICENSE' exclude 'READ.ME' exclude 'README' } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } configurations { } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) //include our modules compile project(':core') compile project(':data') //android final APP_COMPAT_VERSION = '26.1.0' compile "com.android.support:appcompat-v7:$APP_COMPAT_VERSION" compile "com.android.support:recyclerview-v7:$APP_COMPAT_VERSION" compile "com.android.support:design:$APP_COMPAT_VERSION" compile "com.android.support:multidex:1.0.0" compile "com.android.support:cardview-v7:$APP_COMPAT_VERSION" // google final PLAY_SERVICES_VERSION = '10.2.4' compile "com.google.android.gms:play-services-wallet:$PLAY_SERVICES_VERSION" compile "com.google.android.gms:play-services-location:$PLAY_SERVICES_VERSION" compile "com.google.android.gms:play-services-gcm:$PLAY_SERVICES_VERSION" compile "com.google.android.gms:play-services-plus:$PLAY_SERVICES_VERSION" compile "com.google.android.gms:play-services-identity:$PLAY_SERVICES_VERSION" compile "com.google.android.gms:play-services-analytics:$PLAY_SERVICES_VERSION" compile "com.google.android.gms:play-services-auth:$PLAY_SERVICES_VERSION" compile "com.google.android.gms:play-services-maps:$PLAY_SERVICES_VERSION" // facebook compile 'com.facebook.android:facebook-android-sdk:4.8.+' compile 'com.facebook.stetho:stetho:1.1.0' //markdown4j compile 'org.commonjava.googlecode.markdown4j:markdown4j:2.2-cj-1.0' //crashlytics compile('com.crashlytics.sdk.android:crashlytics:2.5.2@aar') { transitive = true; } //image zoom compile 'com.github.chrisbanes.photoview:library:1.2.3' //square compile 'com.squareup.picasso:picasso:2.5.2' compile 'com.makeramen:roundedimageview:2.2.1' debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1' testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1' compile 'com.jakewharton:butterknife:8.6.0' annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.0' // optimizely compile('com.optimizely:optimizely:1.4.2@aar') { transitive = true } //braintree compile 'com.braintreepayments.api:braintree:2.6.0' compile 'com.braintreepayments.api:data-collector:2.+' // guava compile 'com.google.guava:guava:19.0' // sticky headers compile 'com.github.mtotschnig:StickyListHeaders:2.7.1' // expandable recyclerview compile 'eu.davidea:flexible-adapter:5.0.0-rc2' //recyclerview animations compile 'jp.wasabeef:recyclerview-animators:2.2.3' // tooltip compile 'com.github.michaelye.easydialog:easydialog:1.4' // tealium compile 'com.tealium:library:5.3.0' // circle indicator compile 'me.relex:circleindicator:1.2.2@aar' //testing final HAMCREST_VERSION = '1.3' def jUnit = "junit:junit:4.12" // ExactTarget SDK compile ('com.salesforce.marketingcloud:marketingcloudsdk:5.0.5') { exclude module: 'android-beacon-library' //remove to use Proximity messaging exclude module: 'play-services-location' //remove to use Geofence or Proximity messaging } androidTestCompile jUnit // Unit tests dependencies testCompile jUnit testCompile "org.hamcrest:hamcrest-core:$HAMCREST_VERSION" testCompile "org.hamcrest:hamcrest-library:$HAMCREST_VERSION" testCompile "org.hamcrest:hamcrest-integration:$HAMCREST_VERSION" testCompile 'org.robolectric:robolectric:3.1' testCompile 'org.mockito:mockito-core:1.+' testCompile 'com.google.guava:guava:19.0' testCompile("com.android.support:support-v4:$APP_COMPAT_VERSION") { exclude module: 'support-annotations' } testCompile('org.powermock:powermock-api-mockito:1.6.4') { exclude module: 'objenesis' } testCompile('org.powermock:powermock-module-junit4:1.6.4') { exclude module: 'objenesis' } testCompile 'io.reactivex:rxandroid:1.0.1' testCompile 'io.reactivex:rxjava:1.1.0' // Espresso androidTestCompile('com.android.support.test:runner:0.5') { exclude module: 'support-annotations' } androidTestCompile('com.android.support.test:rules:0.5') { exclude module: 'support-annotations' } androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2') { exclude module: 'support-annotations' } androidTestCompile('com.android.support.test.espresso:espresso-intents:2.2.2') { exclude module: 'support-annotations' } androidTestCompile('com.android.support.test.espresso:espresso-web:2.2.2') { exclude module: 'support-annotations' } androidTestCompile('com.android.support.test.espresso:espresso-contrib:2.2.2') { exclude module: 'support-annotations' exclude module: 'recyclerview-v7' exclude module: 'appcompat-v7' exclude module: 'design' exclude module: 'support-v4' } // allows java 8 compile compile 'com.annimon:stream:1.1.2' // For taking screenshots androidTestCompile 'com.squareup.spoon:spoon-client:1.7.0' testCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2' compile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2' compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" } apply plugin: 'com.google.gms.google-services' spoon { noAnimations = true grantAllPermissions = true } apply plugin: 'devicefarm' devicefarm { projectName "Rue Mobile" devicePool "Smoke Test Pool" useUnmeteredDevices() authentication { accessKey System.getenv("AWS_DEVICE_FARM_ACCESS_KEY") secretKey System.getenv("AWS_DEVICE_FARM_SECRET_KEY") } } 

解决方法是禁用预分配:

 dexOptions { preDexLibraries false } 

在应用程序build.gradle。 对此的启示来自这个链接,关于一个没有发现在棒棒糖上的错误的毕加索类: 看到这里

它并不完全清楚为什么禁用预分解解决了这个问题,但是我只能推断,构建过程会进行一些优化,影响到apk的dex文件中的类的排序方式,从而影响应用程序在这些三星棒棒糖设备上安装。 从理论上讲,ART应该照顾所有这些,但是很明显,pre-dex优化和一些棒棒糖设备之间存在依赖关系。

Interesting Posts