Android应用程序在Samsung Lollipop设备上崩溃NoClassDefFoundError [英] Android app crash NoClassDefFoundError on Samsung Lollipop devices
问题描述
我们最近将应用程序的minSdkVersion从16(豆形软糖)提高到21(棒棒糖).尽管我们主要使用调试版本对应用程序进行了广泛的测试,但我们现在在应用程序启动时面临着大量的生产崩溃,主要是在较旧的三星设备上-(Note3和S4是最主要的崩溃者),并且始终在Lollipop上.
We recently bumped the minSdkVersion of our app from 16 (Jellybean) to 21 (Lollipop). Although we did extensive testing with our app predominantly using debug builds, we are now facing a slew of production crashes at app startup, predominantly on older Samsung devices - (Note3 and S4 are the top crashers) and always on Lollipop.
错误是
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.
The SplashActivity is the initial lauching activity of the app. The class not found is a long-established class not something newly introduced. As a side note, as part of this latest release we upgraded to Android Studio 3 and introduced Kotlin code, but I dont think these are related to the issue. We are not using proguard in the build.
我知道当minSdkVersion为21及更高版本时,构建会发生重大变化,这与使用ART而不是Dalvik有关,所以我想知道Samsung Lollipop设备是否仍存在一些缺陷现在在主要dex文件中有一个类吗?
I'm aware that there was a significant change for builds when the minSdkVersion is 21 and above, relating to the use of ART instead of Dalvik, so I'm wondering if there is some flaw with Samsung Lollipop devices still looking for a class in the primary dex file now?
模块级build.gradle:
The module-level 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")
}
}
推荐答案
此问题的解决方法是禁用预删除:
The fix for this was to disable pre-dexing:
dexOptions {
preDexLibraries false
}
在应用程序build.gradle中
.来自此链接的灵感来自有关Lollipop上未找到Picasso类的错误的链接:
in the app build.gradle. Inspiration for this came from this link regarding a Picasso class not found error on Lollipop: see here
我尚不完全清楚为什么禁用预排序解决了问题,但我只能得出结论,构建过程中正在进行一些优化,这会影响apk的dex文件中类的排序方式,然后影响这些三星Lollipop设备上的应用安装.从理论上讲,ART应该解决所有这些问题,但是很显然,pre-dex优化与某些Lollipop设备之间存在依赖关系.
Its not entirely clear to me why disabling pre-dexing solves the problem, but I can only theorize that there is some optimization going on with the build process that affects the way classes are ordered in the dex files of the apk that then affects the app installation on these Samsung Lollipop devices. In theory ART should take care of all of that, but clearly there is a dependency between pre-dex optimization and some Lollipop devices.
这篇关于Android应用程序在Samsung Lollipop设备上崩溃NoClassDefFoundError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!