2017-10-18 27 views
2

최근에 Google 앱의 minSdkVersion이 16 (Jellybean)에서 21 (Lollipop)으로 바뀌 었습니다. 우리가 주로 디버그 빌드를 사용하여 광범위하게 테스트 했음에도 불구하고, 우리는 이제 앱을 시작할 때 주로 오래된 삼성 장치 (주 3 및 S4가 최고 크래셔)와 항상 롤리팝에 대량 생산 충돌을 겪고 있습니다.Samsung Lollipop 기기에서 Android 앱이 다운되다 NoClassDefFoundError

오류가

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 코드를 도입했습니다. 그러나 이러한 문제는 관련이 없다고 생각합니다. 우리는 빌드에서 프로 가드를 사용하지 않습니다.

Dalvik 대신 ART를 사용하는 것과 관련하여 minSdkVersion이 21 이상일 때 빌드에 대한 중요한 변경 사항이 있음을 알고 있습니다. 따라서 여전히보고있는 삼성 Lollipop 장치의 결함이 있는지 궁금합니다. 이제 기본 dex 파일에있는 클래스에 대해?

모듈 수준 build.gradle : 응용 프로그램의 build.gradle에서

dexOptions { 
    preDexLibraries false 
} 

:

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:[email protected]') { 
     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:[email protected]') { 
     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:[email protected]' 

    //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") 
    } 
} 

답변

2

이에 대한 수정은 사전한다 Dexing을 해제하는 것이 었습니다. 영감을 얻으려면 Lollipop에서 Picasso 클래스를 찾을 수 없다는 오류 메시지가 나타납니다. see here

왜 내가 사전에 덱싱을 사용하지 못하게하면 문제가 해결되는지 완전히 알 수는 없지만 다음과 같은 최적화 작업이 있다고 이론화 할 수 있습니다. apk의 dex 파일에서 클래스가 정렬되는 순서에 영향을주는 빌드 프로세스는이 Samsung Lollipop 장치의 앱 설치에 영향을 미칩니다. 이론적으로 ART는이 모든 것을 처리해야하지만, 사전 dex 최적화와 일부 Lollipop 장치 간의 의존성이 분명합니다.