tjarvstrand / flutter_timezone

A fork of https://github.com/pinkfish/flutter_native_timezone
Apache License 2.0
42 stars 29 forks source link

java.lang.NoSuchMethodError on net.wolverinebeach.flutter_timezone.FlutterTimezonePlugin.getLocalTimezone #16

Closed raLaaaa closed 1 year ago

raLaaaa commented 1 year ago

Following low level exception occurs when running on certain devices:

Exception java.lang.NoSuchMethodError: No direct method (II)V in class Lj$/util/concurrent/ConcurrentHashMap; or its super classes (declaration of 'j$.util.concurrent.ConcurrentHashMap' appears in /data/app/androidx.test.tools.crawler-c9b3cs5GiKgF-HucStw1fg==/base.apk!classes2.dex) at j$.time.zone.g. at j$.time.zone.g.b at j$.time.s.r (SourceFile) at j$.time.ZoneId.of (SourceFile) at j$.time.ZoneId.systemDefault (SourceFile) at net.wolverinebeach.flutter_timezone.FlutterTimezonePlugin.getLocalTimezone (FlutterTimezonePlugin.java) at net.wolverinebeach.flutter_timezone.FlutterTimezonePlugin.onMethodCall (FlutterTimezonePlugin.java) at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage (MethodChannel.java) at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler (DartMessenger.java) at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0 (DartMessenger.java) at android.os.Handler.handleCallback (Handler.java:883) at android.os.Handler.dispatchMessage (Handler.java:100) at android.os.Looper.loop (Looper.java:237) at android.app.ActivityThread.main (ActivityThread.java:8016) at java.lang.reflect.Method.invoke at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1076)

See the image below for device informations from Google Playstore:

image

Any ideas on how to fix it on my side? Unfortunately the exception does not tell me a lot. Thanks for your effort!

tjarvstrand commented 1 year ago

Strange. This looks like it could be related: https://github.com/mockk/mockk/issues/530

Is this in release builds, or also in debug? What does your proguard config look like?

raLaaaa commented 1 year ago

This only happens for me in release builds and does only occur during Google PlayStores pre launch checks. I do not have a specific proguard config in my project. I'm only using default flutter R8 code shrinking with no extra config.

I'll paste a part of my build.gradle below:

  android {

    namespace "namespace"
    compileSdkVersion flutter.compileSdkVersion
    ndkVersion flutter.ndkVersion

    compileOptions {
        coreLibraryDesugaringEnabled true
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    defaultConfig {
        applicationId "my-id"
        multiDexEnabled true
        minSdkVersion localProperties.getProperty('flutter.minSdkVersion').toInteger()
        targetSdkVersion localProperties.getProperty('flutter.targetSdkVersion').toInteger()
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

    signingConfigs {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile file(keystoreProperties['storeFile'])
            storePassword keystoreProperties['storePassword']
        }
    }
    buildTypes {

        release {
            signingConfig signingConfigs.release
        }
    }
}

flutter {
    source '../..'
}

dependencies {
    coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

I indeed have desugaring enabled since my app is using local push notification scheduling. Maybe I can double check and try to disable it to narrow the issue down.

tjarvstrand commented 1 year ago

You may want to try adding something like: -keep class java.util.concurrent.ConcurrentHashMap {*;} to your proguard rules.

raLaaaa commented 1 year ago

Heading towards a vacation for some days. I'll get back to you asap afterwards. Thanks mate.

raLaaaa commented 1 year ago

I adapted my release config:

    buildTypes {

        release {
            signingConfig signingConfigs.release
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

My proguard-rules.pro file under android/app/ looks as following:

#Flutter Wrapper
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.**  { *; }
-keep class io.flutter.util.**  { *; }
-keep class io.flutter.view.**  { *; }
-keep class io.flutter.**  { *; }
-keep class io.flutter.plugins.**  { *; }
-keep class java.util.concurrent.ConcurrentHashMap { *; }

Still receiving:

Exception java.lang.NoSuchMethodError: No direct method <init>(II)V in class Lj$/util/concurrent/ConcurrentHashMap; or its super classes (declaration of 'j$.util.concurrent.ConcurrentHashMap' appears in /data/app/~~vpS1QgXFsV1-ngKQDB5v3w==/androidx.test.tools.crawler-RbJQvC7vlZjaCx3kyIXuWg==/base.apk!classes2.dex)
  at j$.time.zone.g.<clinit>
  at j$.time.zone.g.b
  at j$.time.s.r (SourceFile)
  at j$.time.ZoneId.of (SourceFile)
  at j$.time.ZoneId.systemDefault (SourceFile)
  at net.wolverinebeach.flutter_timezone.FlutterTimezonePlugin.getLocalTimezone (FlutterTimezonePlugin.java)
  at net.wolverinebeach.flutter_timezone.FlutterTimezonePlugin.onMethodCall (FlutterTimezonePlugin.java)
  at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage
  at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler (DartMessenger.java)
  at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0 (DartMessenger.java)
  at android.os.Handler.handleCallback (Handler.java:942)
  at android.os.Handler.dispatchMessage (Handler.java:99)
  at android.os.Looper.loopOnce (Looper.java:201)
  at android.os.Looper.loop (Looper.java:288)
  at android.app.ActivityThread.main (ActivityThread.java:7918)
  at java.lang.reflect.Method.invoke
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:548)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:936)

My build size increased at around 100kb compared to not using a progaurd rules so I assume that R8 gets the config file and keeps the java.util.concurrent.ConcurrentHashMap. I wonder why it does not find it though.

I'll run another test with flutter build appbundle --no-shrink and see if PlayStore pre launch determines errors as well.

tjarvstrand commented 1 year ago

It definitely looks like there is some non-public code in ConcurrentHashMap that doesn't make it into your build. Sadly, I don't have a lot of experience with ProGuard/R8. If I were you, I'd play around with the options here. In particular, -printconfiguration and -addconfigurationdebugging sound like they may be useful.

raLaaaa commented 1 year ago

Even with flutter build appbundle --no-shrink pre launch check finds the error from above. From my understanding this should disable code shrinking completly and therefore solve the issue if it's ProGuard/R8 related.

I'm just guessing how ever. I'll try to dig a little bit deeper. Thank you for your input / help so far!

I think we can close the issue since it is pretty sure on my side.

tjarvstrand commented 1 year ago

Good luck! Would be great to know if you come up with any gotchas related to using flutter_timezone with desugaring so we can document it for future users.