简体   繁体   中英

android ART NoClassDefFoundError when deploying a multidex apk to fabric beta

I have a strange issue.

I have this kotlin piece of code that sorts a dictionary, inside my multidix mixed java-kotlin application. (code below)

when running the app on development phone (SAMSUNG s9) everything runs ok. When deployed the app to Fabric's "beta", a big portion (50%) of the users are having crashes of type NoClassDefFoundError . The affected phones include xioami's MI 5s and Red-mi phones and multiple types of onePlus phones

I tried to look at the output apk (via build -> Analyze APK) and made sure the class is, indeed, there. As you can see from 这个图片 - that the class is actually on the main "classes.dex" file.

Any help will be much appreciated!

log file:

... (custom logging from the app on initiation level)

09-09 13:04:31.667 17365-17365/com.example.orcam.basic_recognition_app I/art: Rejecting re-init on previously-failed class java.lang.Class<com.example.orcam.logic_myme.ComputedData.ComputedPersonData$calculateMeetingsForPerson$2>

... (custom logging from the app on normal run level)

09-09 13:04:31.762 17365-17365/com.example.orcam.basic_recognition_app E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.orcam.basic_recognition_app, PID: 17365 java.lang.NoClassDefFoundError: com.example.orcam.logic_myme.ComputedData.ComputedPersonData$calculateMeetingsForPerson$2 at com.example.orcam.logic_myme.ComputedData.ComputedPersonData.calculateMeetingsForPerson(ComputedPersonData.kt:45) at com.example.orcam.logic_myme.ComputedData.ComputedData.calculate(ComputedData.kt:7) at com.example.orcam.logic_myme.db.DBManager$init$2.onDbInitAndReady(DBManager.kt:79) at com.example.lib_sync.sync.SyncManager2.(SyncManager2.java:63) at com.example.orcam.logic_myme.db.DBManager.init(DBManager.kt:76) at com.example.orcam.basic_recognition_app.LogicManager.init(LogicManager.java:58) at com.example.orcam.basic_recognition_app.MyMeApplication.initManagers(MyMeApplication.kt:31) at com.example.orcam.basic_recognition_app.MyMeApplication.onCreate(MyMeApplication.kt:13) at android.app. Instrumentation.callApplicationOnCreate(Instrumentation.java:1014) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4782) at android.app.ActivityThread.access$1700(ActivityThread.java:153) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1445) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:5544) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629) 09-09 13:04:31.763 17365-17365/com.example.orcam.basic_recognition_app E/MQSEventManagerDelegate: failed to get MQSService.

build.gradle file:

buildscript {
    repositories {
        maven { url 'https://maven.fabric.io/public' }
        google()
    }

    dependencies {
        classpath 'io.fabric.tools:gradle:1.+'
    }
}
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

repositories {
    maven { url 'https://maven.fabric.io/public' }
    google()
}


android {
    compileSdkVersion 27
    buildToolsVersion "27.0.3"

    defaultConfig {
        applicationId "com.example.orcam.basic_recognition_app"
        minSdkVersion 21
        targetSdkVersion 27
        versionCode 29
        versionName "5.0.9"

    }
    buildTypes {
        debug {
            applicationIdSuffix ".debug"
        }

        beta {
            initWith debug
            applicationIdSuffix ""
        }



        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    packagingOptions {
        pickFirst 'META-INF/LICENSE'
        pickFirst 'META-INF/DEPENDENCIES'
        pickFirst 'META-INF/ASL-2.0.txt'
        pickFirst 'META-INF/LGPL-3.0.txt'
        exclude 'META-INF/main.kotlin_module'
    }
    dexOptions {
        preDexLibraries = false
    }
}

ext {
    supportLibVersion = '27.1.1'
}

dependencies {
    /* ... a lot of dependencies ... */

    // multi dex
    implementation 'com.android.support:multidex:1.0.3'

    // kotlin
    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

}
kapt {
    generateStubs = true
}

ComputedPersonData.kt file (simplified version with only the "bad" function):

class ComputedPersonData() {
    var meetingsByPerson = mapOf<String, ArrayList<String>>()

    fun calculateMeetingsForPerson() {
        val faces: Map<String: Face?> = getFaces()
        val faceToContact: Map<String: String?> = getMapping()
        val peopleWithFaces = mutableMapOf<String, ArrayList<Face>>()


        faces.values.forEach {
            if (it != null) {
                val personId = faceToContact[it.imageId] ?: ""

                val list = peopleWithFaces[personId] ?: run {
                    peopleWithFaces[personId] = arrayListOf(it)
                    return@forEach
                }
                list.add(it)
            }
        }

        val dictSorted = mutableMapOf<String, ArrayList<Face>>()
        peopleWithFaces.forEach { id, item ->
            dictSorted[id] = ArrayList(item.sortedBy { it.timestamp })
        }

// the "dictSorted.mapValues{}" generates the "bad" $2 class

        val dictFaceToString: Map<String, ArrayList<String>> = dictSorted.mapValues {
            ArrayList(it.value.map {
                it.id
            }
            )
        }

        this.meetingsByPerson = dictFaceToString
    }
}

application class:

class MyApplication : MultiDexApplication()

well, after MONTHS of investigation apparently the bad lines were -

peopleWithFaces.forEach { id, item ->
            dictSorted[id] = ArrayList(item.sortedBy { it.timestamp })
        }

There was an issue with old android-OS (6.0.0 specific) and kotlin's decoupled for-each .

Once the problem found, the solution was easy. All we needed to do was to re-write this fun like that:

peopleWithFaces.forEach { 
            val id = it.key
            val item = it.value
            dictSorted[id] = ArrayList(item.sortedBy { it.timestamp })
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM