dart-lang / native

Dart packages related to FFI and native assets bundling.
BSD 3-Clause "New" or "Revised" License
115 stars 40 forks source link

JNIGEN throws error when generate binding for `com.google.common.util.concurrent.ListenableFuture`. #1225

Closed yanshouwang closed 2 months ago

yanshouwang commented 2 months ago

When I generate JNI bindings for CameraX today earlier. I found an error with ListenableFuture class.

The jnigen.yaml is like this.

# Run with `dart run jnigen --config jnigen.yaml`.
android_sdk_config:
  add_gradle_deps: true
  android_example: example/
suspend_fun_to_async: true
enable_experiment:
  - interface_implementation
output:
  dart:
    path: lib/src/jni.g.dart
    structure: single_file
log_level: all
classes:
  - androidx.core.content.ContextCompat
  - androidx.camera.core.CameraSelector
  - androidx.camera.core.ZoomState
  - androidx.camera.view.CameraController
  - androidx.camera.view.LifecycleCameraController
  - androidx.camera.view.PreviewView
  - androidx.lifecycle.LifecycleOwner
  - androidx.lifecycle.LiveData
  - androidx.lifecycle.Observer
  - com.google.common.util.concurrent.ListenableFuture
  - java.lang.Runnable
  - java.util.concurrent.Future
  - dev.hebei.camerax_android.PreviewViewFactory

After run the command I got this error:

PS C:\Users\yanshouwang\dev\camerax\camerax_android> dart run jnigen --config jnigen.yaml
(jnigen) INFO: ApiSummarizer.jar exists. Skipping build..
(jnigen) FINE: Set log level: ALL
(jnigen) INFO: trying to obtain gradle dependencies [getReleaseCompileClasspath]...
(jnigen) FINER: Writing temporary gradle script with stub "getReleaseCompileClasspath"...
(jnigen) FINER: Running gradle wrapper...
(jnigen) INFO: Restoring build scripts
(jnigen) FINE: Found 59 entries
(jnigen) INFO: execute java -jar .dart_tool/jnigen/ApiSummarizer.jar -c "C:\Users\yanshouwang\AppData\Local\Android\SDK\platforms\android-34\android.jar;C:\Users\yanshouwang\dev\camerax\camerax_android\example\build\app\intermediates\compile_and_runtime_not_namespaced_r_class_jar\release\R.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\ec063f47f4c27d126346d5f0e2be843c\transformed\jetified-libs.jar;C:\Users\yanshouwang\dev\camerax\camerax_android\example\build\camerax_android\intermediates\compile_library_classes_jar\release\classes.jar;C:\Users\yanshouwang\dev\camerax\camerax_android\example\build\integration_test\intermediates\compile_library_classes_jar\release\classes.jar;C:\Users\yanshouwang\dev\camerax\camerax_android\example\build\jni\intermediates\compile_library_classes_jar\release\classes.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\c3f29f1edd3239c377c034f99c20a82c\transformed\jetified-flutter_embedding_release-1.0.0-edd8546116457bdf1c5bdfb13ecb9463d2bb5ed4.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\4c12561b2ae2747671b71e5921208e07\transformed\jetified-window-java-1.0.0-beta04-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\e8f28f4aa3e53326585c527ec8d44f1a\transformed\jetified-window-1.0.0-beta04-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\8afce66f452b811e637ef0d81969a638\transformed\jetified-kotlinx-coroutines-android-1.5.2.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\85782104583e7151c955fe469e900df5\transformed\jetified-kotlinx-coroutines-core-jvm-1.5.2.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\d2fed106c5849de6c92444308a9a30af\transformed\jetified-kotlin-stdlib-jdk8-1.8.22.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\cec809caf3f4b53dfb6cb1dc65ac49b9\transformed\jetified-armeabi_v7a_release-1.0.0-edd8546116457bdf1c5bdfb13ecb9463d2bb5ed4.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\64e1dc5f9c39218cfe32675242cfd05b\transformed\jetified-arm64_v8a_release-1.0.0-edd8546116457bdf1c5bdfb13ecb9463d2bb5ed4.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\4b1aac1ab94b6483e2b8257581ce5e71\transformed\jetified-x86_64_release-1.0.0-edd8546116457bdf1c5bdfb13ecb9463d2bb5ed4.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\b0a5844f211ea56d7409564466507072\transformed\jetified-camera-video-1.3.4-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\135470497fa5048618b9136c2d5f1759\transformed\jetified-camera-view-1.3.4-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\b6cc78aa8d1cb92df39ec15b1f204a0a\transformed\jetified-camera-lifecycle-1.3.4-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\819c4cde24338ff7bca8972d9ccaf4b1\transformed\jetified-camera-camera2-1.3.4-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\ecb627fc9fe87ec8ce00506692b4f604\transformed\jetified-camera-core-1.3.4-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\a08d06dab8b70b7ac904c947547557cf\transformed\rules-1.2.0-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\1584d06e818579f0856f50ceb15ddd8b\transformed\espresso-core-3.2.0-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\d610a9b20fe8d4a808148d7510deed48\transformed\runner-1.2.0-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\ae010e3eed5792daa185abb19eb23a07\transformed\fragment-1.1.0-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\3317fac89a195a3c4b5ac46dcdd385b0\transformed\viewpager-1.0.0-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\4ff4d7a20ae4b90cc144c24ab07a8ca4\transformed\loader-1.0.0-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\a9696a070aefeb4dc196d17cfd845609\transformed\jetified-activity-1.0.0-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\00bc4016f37799748a50d2e7c40dd401\transformed\customview-1.0.0-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\bc63610dc9d29d319d9a8310831736ad\transformed\core-1.6.0-api.jar;C:\Users\yanshouwang\.gradle\caches\modules-2\files-2.1\androidx.lifecycle\lifecycle-common-java8\2.2.0\cd3478503da69b1a7e0319bd2d1389943db9b364\lifecycle-common-java8-2.2.0.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\58ae162724efa226618081bb60e9ab12\transformed\lifecycle-runtime-2.2.0-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\868dfb50a28cc7190de823080e89d218\transformed\lifecycle-livedata-2.1.0-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\8edd9ced69710253be92dfeace57d808\transformed\lifecycle-livedata-core-2.1.0-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\edf0becee105268317ee22be6727943d\transformed\jetified-savedstate-1.0.0-api.jar;C:\Users\yanshouwang\.gradle\caches\modules-2\files-2.1\androidx.lifecycle\lifecycle-common\2.2.0\4ef09a745007778eef83b92f8f23987a8ea59496\lifecycle-common-2.2.0.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\d968ea546b9173b874b0e808d29dcea2\transformed\monitor-1.2.0-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\2eccc499815d26a2335cf8f2bfd9c633\transformed\versionedparcelable-1.1.1-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\c76b091b5cfe3694442274e73afd447d\transformed\core-runtime-2.1.0-api.jar;C:\Users\yanshouwang\.gradle\caches\modules-2\files-2.1\androidx.arch.core\core-common\2.1.0\b3152fc64428c9354344bd89848ecddc09b6f07e\core-common-2.1.0.jar;C:\Users\yanshouwang\.gradle\caches\modules-2\files-2.1\androidx.collection\collection\1.1.0\1f27220b47669781457de0d600849a5de0e89909\collection-1.1.0.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\9da1da3dccb533d0f1aa43b473725e04\transformed\lifecycle-viewmodel-2.1.0-api.jar;C:\Users\yanshouwang\.gradle\caches\modules-2\files-2.1\androidx.annotation\annotation\1.2.0\57136ff68ee784c6e19db34ed4a175338fadfde1\annotation-1.2.0.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\ad268299fd979528530efe675e479011\transformed\jetified-annotation-experimental-1.3.1-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\1489d0dc668d1b45b5158203e57d5478\transformed\jetified-kotlin-stdlib-jdk7-1.8.22.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\a7ce25e9d4a7d35349ba55deaf7644ab\transformed\jetified-kotlin-stdlib-1.8.22.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\ddae8d9443506991fd77305380135b70\transformed\jetified-kotlin-stdlib-common-1.8.22.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\fb2831575e0980eba4f56473e2b0979a\transformed\jetified-annotations-13.0.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\03f7c26f446d76cca35cfdf739539d39\transformed\jetified-listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\23b3fd543ae0d043dfcc7fadc18fb877\transformed\jetified-tracing-1.0.0-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\edba4ca4738e6e4987df90fa9b5cbb0f\transformed\jetified-junit-4.12.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\5016bea5abe36b772b039657ac550d63\transformed\jetified-hamcrest-integration-1.3.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\eaaf4db639ef32e07a6e620f0d5b335b\transformed\jetified-hamcrest-library-1.3.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\2be7be2f4e98f7969936b30ca4d29324\transformed\jetified-hamcrest-core-1.3.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\a3ab3bbb5ac550c2c6a0e8385f95cd1b\transformed\jetified-kxml2-2.3.0.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\e7a29c42dccb1d6719cc12dce1a76d82\transformed\espresso-idling-resource-3.2.0-api.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\710e1455e95e2888b47aff15416dd829\transformed\jetified-javawriter-2.1.1.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\e79c0b741d0344260a97e254ac01c1bc\transformed\jetified-javax.inject-1.jar;C:\Users\yanshouwang\.gradle\caches\transforms-3\8cb67e97b810c6d5f0de6b5f29c3974e\transformed\jetified-jsr305-3.0.2.jar;C:\Users\yanshouwang\dev\camerax\camerax_android\example\build\app\tmp\kotlin-classes\release" androidx.core.content.ContextCompat androidx.camera.core.CameraSelector androidx.camera.core.ZoomState androidx.camera.view.CameraController androidx.camera.view.LifecycleCameraController androidx.camera.view.PreviewView androidx.lifecycle.LifecycleOwner androidx.lifecycle.LiveData androidx.lifecycle.Observer com.google.common.util.concurrent.ListenableFuture java.lang.Runnable java.util.concurrent.Future dev.hebei.camerax_android.PreviewViewFactory
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8
Not found: [com.google.common.util.concurrent.ListenableFuture]

Fatal: Cannot generate summary: FormatException: Unexpected end of input (at character 1)

^

I notice that JNIGEN use wrong class path with C:\Users\yanshouwang\.gradle\caches\transforms-3\03f7c26f446d76cca35cfdf739539d39\transformed\jetified-listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar

I can fix this error by declare the real class path in jnigen.yaml

class_path:
  C:\Users\yanshouwang\.gradle\caches\transforms-3\89f247aea93bdb83a7ec18782b35801d\transformed\jetified-listenablefuture-1.0.jar
HosseinYousefi commented 2 months ago

9999.0 is just a trick that Guava has used for pre-27 to avoid a duplicate class error. See https://mvnrepository.com/artifact/com.google.guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava

Please provide your dependencies inside your build.gradle.

yanshouwang commented 2 months ago

9999.0 is just a trick that Guava has used for pre-27 to avoid a duplicate class error. See https://mvnrepository.com/artifact/com.google.guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava

Please provide your dependencies inside your build.gradle.

Here is my dependencies


buildscript {
    ext.kotlin_version = "1.7.10"
    ext.camerax_version = "1.3.4"
    repositories {
        google()
        mavenCentral()
    }

    dependencies {
        classpath("com.android.tools.build:gradle:7.3.0")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
    }
}

...

    dependencies {
        // The following line is optional, as the core library is included indirectly by camera-camera2
        api "androidx.camera:camera-core:${camerax_version}"
        api "androidx.camera:camera-camera2:${camerax_version}"
        // If you want to additionally use the CameraX Lifecycle library
        api "androidx.camera:camera-lifecycle:${camerax_version}"
        // If you want to additionally use the CameraX VideoCapture library
        //api "androidx.camera:camera-video:${camerax_version}"
        // If you want to additionally use the CameraX View class
        api "androidx.camera:camera-view:${camerax_version}"
        // If you want to additionally add CameraX ML Kit Vision Integration
        //api "androidx.camera:camera-mlkit-vision:${camerax_version}"
        // If you want to additionally use the CameraX Extensions library
        //api "androidx.camera:camera-extensions:${camerax_version}"

        testImplementation("org.jetbrains.kotlin:kotlin-test")
        testImplementation("org.mockito:mockito-core:5.0.0")
    }

I can't fix this even if I add the listenablefuture:1.0 as a dependency manually.

HosseinYousefi commented 2 months ago

Haha. There is an entire blog post about this: https://blog.gradle.org/guava

androidx.concurrent:concurrent-futures depends on the library's 1.0, as you don't have any guava dependencies, it's odd to see 9999 being picked up by gradle.

Any changes you make need to be followed by a flutter clean + flutter build apk in the example directory.

It's out of jnigen's scope to fix gradle problems, so I would simply copy the jar to the code directory and use its path for class_path.

yanshouwang commented 2 months ago

so I would simply copy the jar to the cod

I see, I have no idea why the 9999.0 is resolved, but as I can fix this by declare the real class_path, just close this :wink: