Android/Gradle: how to find the good mix of Google dependencies versions? - java

I have often compiling errors due to the versions of the different Google dependencies that have bad interactions between them.
Typical gradle file:
implementation 'com.google.android.gms:play-services-analytics:16.0.1'
implementation 'com.google.android.gms:play-services-ads:17.1.1'
implementation 'com.google.firebase:firebase-core:16.0.1'
implementation 'com.google.firebase:firebase-messaging:17.1.0'
implementation 'com.google.ads.mediation:facebook:4.22.1.0'
At the end, the project doesn't compile with an error like this:
FAILURE: Build failed with an exception.
* What went wrong:
Could not determine the dependencies of task ':XXX:preDebugBuild'.
> In project 'XXX' a resolved Google Play services library dependency depends on another at an exact version (e.g. "[1
5.0.1]", but isn't being resolved to that version. Behavior exhibited by the library will be unknown.
Dependency failing: com.google.android.gms:play-services-tasks:15.0.1 -> com.google.android.gms:play-services-basement#[
15.0.1], but play-services-basement version was 16.0.1.
The following dependencies are project dependencies that are direct or have transitive dependencies that lead to the art
ifact with the issue.
-- Project 'XXX' depends onto com.google.firebase:firebase-config#16.0.0
-- Project 'XXX' depends onto com.google.android.gms:play-services-analytics#16.0.1
-- Project 'XXX' depends onto com.facebook.android:audience-network-sdk#4.22.1
-- Project 'XXX' depends onto com.google.android.gms:play-services-ads#17.1.1
-- Project 'XXX' depends onto com.google.firebase:firebase-core#16.0.1
-- Project 'XXX' depends onto com.google.firebase:firebase-messaging#17.1.0
For extended debugging info execute Gradle from the command line with ./gradlew --info :XXX:assembleDebug to see the
dependency paths to the artifact. This error message came from the google-services Gradle plugin, report issues at http
s://github.com/google/play-services-plugins and disable by adding "googleServices { disableVersionCheck = false }" to yo
ur build.gradle file.
* Try:
Run with --stacktrace option to get the stack trace. Run with --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 25s
How to solve this kind of issue with a reliable methodology ? (with the goal to have the latest possible version for each lib)

According to your Log file
Dependency failing: com.google.android.gms:play-services-tasks:15.0.1 -> com.google.android.gms:play-services-basement#[
15.0.1], but play-services-basement version was 16.0.1.
Its problem occurred due to different version of Google Play Service.
To resolve these kind of problems in android define a constant version in gradle.properties file
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
org.gradle.parallel=true
COMPILE_SDK_VERSION=26
BUILD_TOOLS_VERSION=27.0.3
TARGET_SDK_VERSION=26
MIN_SDK_VERSION=17
ANDROID_SUPPORT_VERSION=26.1.0
PLAY_SERVICE_VERSION=16.0.1
To use these constant in build.gradle(Module:app) define like below:
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "com.android.support:appcompat-v7:${ANDROID_SUPPORT_VERSION as String}"
implementation "com.google.android.gms:play-services-analytics:${PLAY_SERVICE_VERSION as String}"
implementation "com.google.android.gms:play-services-ads:${PLAY_SERVICE_VERSION as String}"
}
Similarly you can define others library like firebase or others.

I don't think there is a straight answer to your question.
My recommendation would be to use com.google.firebase:firebase-ads:17.1.0 since it should also include both play-services-analytics and play-services-ads which can then be removed. And then keeping an eye on the release versions of your libraries every two weeks.
Yes, I know, this is probably not the answer you were looking for, but on the long run, it will give you less headaches.
If that's not enough to convince you, there is another way of reducing the amount of time it takes to keep the versions up to date using + in the minor version number (for instance 16.0.+ instead of 16.0.0).
WARNING: Automatically increasing the version numbers could lead to issues (i.e.: different versions resolved in your CI and your local machine, unexpected incompatibilities, irreproducible builds, etc.)
On your main build.gradle file define a constant:
allprojects {
ext {
global_version_firebase = '16.0.+'
}
}
And use it like implementation "com.google.firebase:firebase-core:$global_version_firebase"
And some version differences on firebase and play services are actually major changes (i.e.: firebase-core:16.0.4 and firebase-ads:17.1.0), so the convenient + on the minor version would not work for all cases, and you would need to put the + on the whole version number, which is a no-go.

Related

Gradle 7.3 with Java 17 with task processIntTestResources: Entry [filename] is a duplicate but no duplicate handling strategy has been set

I am trying to update a gradle 6.x version multi project application to gradle 7.3 as it is the first version to support Java 17. However, I am unable to progress past an issue arising from a task which is not declared in any of my build.gradle files. The error is below: ([] pieces are redacted)
Execution failed for task ':[root module]:[module]:processIntTestResources'.
> Entry [filename] is a duplicate but no duplicate handling strategy has been set. Please refer to https://docs.gradle.org/7.3/dsl/org.gradle.api.tasks.Copy.html#org.gradle.api.tasks.Copy:duplicatesStrategy for details.
I think is associated with a sourceSet for integration tests, however, I never explicitly copy and files for those tests. I have also set all copy instructions to have this configuration with regard to duplicate handling:
duplicatesStrategy = DuplicatesStrategy.INCLUDE
I also tried adding the above to projects which failed because that setting is only valid for Copy type tasks or blocks. I am by no means an expert in gradle and can add any relevant information needed, but I believe I have included what might be most relevant. I am really just looking for a direction I can head in to further debug this issue.
You didn't show much about how you have integration tests configured, but I ran into a similar problem. What saved me was this blog post by Tom Gregory:
Running integration tests in Gradle
Since links can disappear, let me copy and paste the most important part that I found relevant, which is regarding the new (as of Gradle 7.3) JVM Test Suite Plugin that adds support for integration tests. For me, this replaced my old integration test configuration:
testing {
suites {
integrationTest(JvmTestSuite) {
dependencies {
implementation project
}
}
}
}
tasks.named('check') {
dependsOn testing.suites.integrationTest
}
I also found the following useful, which is not in the above blog post, but is a leftover from my previous Gradle 6 configuration. This for me duplicates the 'test' dependencies for 'integrationTest'. This is not the recommended way of handling the test depedencies now (see the JVM Test Suite Plugin documentation), but I still found it useful to get me back running quickly:
configurations {
integrationTestImplementation.extendsFrom testImplementation
integrationTestRuntime.extendsFrom testRuntime
}

Getting NoClassDefFoundError -> com/sun/jna/platform/win32/Psapi with Eclipse

My program relies on the following code to get available system memory:
import oshi.SystemInfo;
import oshi.hardware.HardwareAbstractionLayer;
SystemInfo si = new SystemInfo();
HardwareAbstractionLayer hal = si.getHardware();
// Next line throws exception: NoClassDefFoundError -> com/sun/jna/platform/win32/Psapi
long availableBytes = hal.getMemory().getAvailable();
double availableMegabytes = ((double) availableBytes) / 1048576;
double availableGigabytes = ((double) availableMegabytes)/1024;
Update: After deleting every occurrence of oshi-core from every project in Workspace (to remove possibility of transient conflict dependency - only 4.2.1 is left). Now the error I get is -> java.lang.NoClassDefFoundError: com/sun/jna/platform/win32/VersionHelpers
In pom.xml I've added oshi-core dependency - I've tried almost every version starting from version 3.4.0 to latest version 4.2.1 and they all result in the same error.
I realize oshi-core relies on jna and jna-platform. In Dependency Hierarchy I see both have resolved (compiled) to version 5.5.0.
What is causing this error and how can it be solved?
Thanks!
P.S
I've seen some other threads with similar error but could not find any thread with this exact problem (missing com/sun/jna/platform/win32/Psapi)
While you've pointed out in your comments that you think the latest version of JNA is being resolved, the errors indicate that your project does not have the most recent version of jna-platform (or possibly it has multiple versions linked on the classpath). This is nearly always the case for NoClassDefFoundError and while you're troubleshooting in the right direction, evidence indicates there's an old jna-platform version in your project somewhere.
The com.sun.jna.platform.win32.VersionHelpers class is in jna-platform version 5.3.0 and newer. The GetPerformanceInfo() method required for the method call giving you the error is in the com.sun.jna.platform.win32.Psapi class is in jna-platform version 4.3.0 and newer. If your classloader can't find these classes, then you don't have the correct jars linked to your project -- or you have incorrect jars linked alongside the correct ones.
Maven resolves dependencies by level... first it does all the dependencies you list in your POM (in order), then the transitive dependencies of those projects (in order) and so on. Ensuring the most recent version of JNA is used can be enforced by either (or both) of:
Specify oshi-core dependency earlier in your list of dependencies
in your POM, specifically, before any project that depends on an
earlier version of JNA.
Explicitly specify the jna and
jna-platform versions (5.5.0) in your top-level POM.
Also, in Eclipse, be sure to go through the menus to Update Maven Project to ensure your dependencies are in sync after changes in the POM.
It's possible that your local repository is not downloading the updated jar, in which case you can purge it (or just delete any JNA artifacts, or everything, from C:\Users\<username>\.m2\repository and let it rebuild.)
Also check the classpath in Eclipse. If you have manually added dependencies (e.g., to JNA) before setting up your POM to get them from Maven, you could be using those.
If the above hints do not resolve your problem, please post the contents of the dependencies section your pom.xml file so we can provide additional advice.
Seems oshi-core relies on internal undocumented features of the Sun / Oracle JVM, and you're running on a different and/or newer JVM that doesn't have that undocumented feature anymore. That's the risk of using undocumented features.
Get a newer/other version of oshi-core that supports the version of the JVM you're using, or switch to use a JVM that oshi-core supports.

Where/how to get the MSVC dlls Java 1.8.0_144 wants?

I'm experimenting with building my application with Java 1.8.0_144 to workaround an issue that apparently started after that. I run this command to build:
gradle jfxNative -Dorg.gradle.java.home="c:\Program Files\Java\jdk1.8.0_144"
and it stops with this error:
Execution failed for task ':jfxNative'.
> Not found MSVC dlls
Where and how do I get these MSVC dlls?
The full output looks like this:
c:\...\>gradle jfxNative -Dorg.gradle.java.home="c:\Program Files\Java\jdk1.8.0_144"
> Task :jfxNative
The jar lib\lombok-1.16.18.jar has a main class lombok.launch.Main that does not match the declared main tech.dashman.dashman.ConfiguratorApp
The jar lib\jna-4.5.0.jar has a main class com.sun.jna.Native that does not match the declared main tech.dashman.dashman.ConfiguratorApp
The jar lib\javassist-3.22.0-CR2.jar has a main class javassist.CtClass that does not match the declared main tech.dashman.dashman.ConfiguratorApp
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':jfxNative'.
> Not found MSVC dlls
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 8s
5 actionable tasks: 2 executed, 3 up-to-date
My current list of dependencies look like this:
dependencies {
compile "tech.dashman:dashmancommon:1.0.0-SNAPSHOT"
compile "org.projectlombok:lombok:1.16.18"
compile "org.springframework:spring-web:5.0.2.RELEASE"
compile "org.springframework.retry:spring-retry:1.2.2.RELEASE"
compile "com.fasterxml.jackson.core:jackson-databind:2.9.3"
compile "org.kordamp.ikonli:ikonli-javafx:2.1.0"
compile "org.kordamp.ikonli:ikonli-fontawesome5-pack:2.1.1"
compile "net.harawata:appdirs:1.0.1"
compile "io.sentry:sentry:1.6.4"
compile "org.javassist:javassist:3.22.0-CR2"
testCompile "junit:junit:4.12"
}
I tried adding
compile "net.java.dev.jna:jna-platform:4.5.1"
to that list but I'm still getting the same error when trying to build the installer.
Adding it to my buildscript dependencies did not change the error either:
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath "de.dynamicfiles.projects.gradle.plugins:javafx-gradle-plugin:8.8.2"
classpath "com.github.ben-manes:gradle-versions-plugin:0.17.0"
classpath "de.dynamicfiles.projects.javafx.bundler:custom-file-extension-windows-bundler:1.0.2-SNAPSHOT"
classpath "net.java.dev.jna:jna-platform:4.5.1"
}
}
Maintainer of the javafx-maven-plugin/Author of the javafx-gradle-plugin here!
Even if this is a very old post, and I did not see this one before (sorry), I might have an answer to this issue. And it happens even today.
While debugging an issue on the plugin (https://github.com/javafx-maven-plugin/javafx-maven-plugin/issues/395) I found that sometimes there are 2 files missing inside the JDK itself.
In case someone has installed any non-Oracle JDK, e.g. OpenLogic, the provided files are incomplete.
The JDK provided by OpenLogic (other others) provides a file called ant-javafx.jar, where all the system native files are contained (can be found inside the installed JDK in the lib-folder). That file is missing the required runtime files, that are required by the launcher.
Here a screenshot of what it looks like with OracleJDK:
Here a screenshot of what it looks with OpenLogic JDK:
As you can see, there are files missing in there, which makes that JDK not equivalent to the OracleJDK sadly.
On maven-plugin level I can not do anything here to fix this, but you might be able to fix that by modifying that JAR-file by adding the missing files. You should be able to find them on your local windows installation at C:\Windows\System32\vcruntime140.dll or C:\Windows\System32\msvcp140.dll. If these files are missing, you just can download a official runtime installer of these Visual C++ Redistributable files here:
for 32-bit: https://aka.ms/vs/16/release/vc_redist.x86.exe
for 64-bit: https://aka.ms/vs/16/release/vc_redist.x64.exe
Another alternative would be to install a different OpenJDK, for example ojdkbuild (https://github.com/ojdkbuild/ojdkbuild). Using chocolatey on Windows just makes this a one-liner choco install ojdkbuild8 and does contain these required files.

Version conflict when Gradle pull dependencies

In my project, jersey-core is pull from many dependencies. I don't know from which ones. I believed it doesn't matter because I thought that if multiples dependencies pull the same one, than gradle would always take the higher version. I was wrong.
[ERROR] [main] [n/a] org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/] - StandardWrapper.Throwable
java.lang.NoSuchMethodError: com.sun.jersey.core.reflection.ReflectionHelper.getContextClassLoaderPA()Ljava/security/PrivilegedAction;
at com.sun.jersey.spi.scanning.AnnotationScannerListener.<init>(AnnotationScannerListener.java:94) ~[jersey-server-1.19.jar:1.19]
AnnotationScannerListener is 1.19, ReflectionHelper is 1.1, and the method getContextClassLoaderPA() does not exist in ReflectionHelper 1.1
How can I force gradle to always take the higher version?
I use intellij.
By default gradle should add the highest version of a dependency to the classpath.
You can force the version of a dependency to be a specific version like so:
configurations.all {
resolutionStrategy {
// force certain versions of dependencies (including transitive)
// *append new forced modules:
force 'asm:asm-all:3.3.1', 'commons-io:commons-io:1.4'
}
}
This example was lifted directly from https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html, which might be worth a read, along with https://docs.gradle.org/current/userguide/dependency_management.html
Another piece of advice, if you want to find out what is pulling in conflicting versions of jars, you can do the following:
gradle dependencyInsight --dependency $dependencyName --configuration $configurationName
where $dependencyName should be substituted for the name of your dependency (such as asm-all), and $configurationName should be replaced with the configuration name you wish to check for (such as compile). This will give you a graph of what versions are being pulled in by which dependencies.

Using jackson-dataformat-xml on android

I'm strugling with using jackson-dataformat-xml on android
I have some very basic code that works fine on oracle jre
JacksonXmlModule module = new JacksonXmlModule();
module.setDefaultUseWrapper(false);
XmlMapper xmlMapper = new XmlMapper(module);
First I tried official documentation adapted for gradle (by me, not sure if done correctly):
compile 'com.fasterxml.jackson.core:jackson-core:2.5.4'
compile 'com.fasterxml.jackson.core:jackson-annotations:2.5.4'
compile 'com.fasterxml.jackson.core:jackson-databind:2.5.4'
compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.5.4'
compile 'org.codehaus.woodstox:woodstox-core-asl:4.4.1'
compile 'javax.xml.stream:stax-api:1.0-2'
Result: gradle fails build time about bundling corelibraries into an application
...
:app:preDexDebug
trouble processing "javax/xml/stream/EventFilter.class":
Ill-advised or mistaken usage of a core class (java.* or javax.*)
when not building a core library.
...
2nd attempt trying to follow Sean's answer
(Basicly he repackages corelibs with prefix names and rebuilds jackson-dataformat-xml to use the prefixed names)
compile 'com.fasterxml.jackson.core:jackson-core:2.1.2'
compile 'com.fasterxml.jackson.core:jackson-annotations:2.1.2'
compile 'com.fasterxml.jackson.core:jackson-databind:2.1.2'
// Repackaged XML-specific libraries
compile 'edu.usf.cutr.android.xml:jackson-dataformat-xml-android:2.1.2'
compile 'edu.usf.cutr.android.xml:stax2-api-android:3.1.1'
compile 'edu.usf.cutr.android.xml:stax-api-android:1.0-2'
compile 'edu.usf.cutr.android.xml:aalto-xml-android:0.9.8'
And build time failed on duplicates
Duplicate files copied in APK META-INF/services/com.fasterxml.jackson.core.ObjectCodec
so added:
packagingOptions {
...
exclude 'META-INF/services/com.fasterxml.jackson.core.JsonFactory'
exclude 'META-INF/services/com.fasterxml.jackson.core.ObjectCodec'
}
When adding the exclusions it builds and deploys, but fails runtime on below stackdump (AFAIK it cant find the SAX provider, even tho it is added to the classpath to my understanding)
edu.usf.cutr.javax.xml.stream.FactoryConfigurationError: Provider com.bea.xml.stream.MXParserFactory not found
at edu.usf.cutr.javax.xml.stream.FactoryFinder.newInstance(FactoryFinder.java:72)
at edu.usf.cutr.javax.xml.stream.FactoryFinder.find(FactoryFinder.java:176)
at edu.usf.cutr.javax.xml.stream.FactoryFinder.find(FactoryFinder.java:92)
at edu.usf.cutr.javax.xml.stream.XMLInputFactory.newInstance(XMLInputFactory.java:136)
at com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(XmlFactory.java:97)
at com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(XmlFactory.java:85)
at com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(XmlFactory.java:82)
at com.fasterxml.jackson.dataformat.xml.XmlMapper.<init>(XmlMapper.java:46)
What is the proper way to move forward on either #1 or #2?
Number 2 is the correct approach (Android doesn't like it when you include classes in the official Java package namespace - but then again, I wrote the original answer so I'm biased ;) ).
I believe the FactoryConfigurationError: Provider com.bea.xml.stream.MXParserFactory not found error is due to a bug in the Android build tools. In previous versions of ADT for Eclipse and Gradle plugin < 0.7.0 the /META-INF/* files are stripped from the JARs during the build process. It seems like >= v0.7.0 shouldn't have the problem according to Google, but from others' reports it sounds like it still may be problematic, and could potentially remove the META-INF/services/javax.xml.stream.XMLInputFactory file, which is required for the platform to register Aalto.
Try the workaround mentioned in AOSP issue 59658 comment 22:
right click on /src/main (where you have /java and /res folders),
select New > Folder > Java Resources Folder,
click Finish (do not change Folder Location),
right click on new /resources folder,
select New > Directory
enter "META-INF" (without quotes),
right click on /resources/META-INF folder,
select New > Directory
enter "services" (without quotes)
copy any file you need into /resources/META-INF/services
For you, in step 10 above you'd need to copy this file into /resources/META-INF/services. In case the file link is broken in the future, the name of the file is javax.xml.stream.XMLInputFactory and it consists of a single line:
com.fasterxml.aalto.stax.InputFactoryImpl
EDIT
If you get a "Error:duplicate files during packaging of APK... Path in archive: META-INF/services/javax.xml.stream.XMLInputFactory", you can try telling Gradle to keep the first occurrence with:
android {
packagingOptions {
pickFirst 'META-INF/services/javax.xml.stream.XMLInputFactory'
}
}
EDIT 2
This bug may be affecting "pickFirst". Please make sure you're running the latest version of Android Studio, and update your local tools and Android Gradle plugin to make sure you're running the most recent version of the tools. This may be fixed in Android Studio 1.3 RC1.
I have attempted to add XmlPull support to jackson xml. Find the forked project here:
https://github.com/finvu/jackson-dataformat-xml
Currently, only supported for version 2.9.6. (clone the branch jackson-dataformat-xml-2.9.6-XmlPull)
Sorry, I am not able to provide detailed documentation due to time constraints. If you have knowledge of git and maven to pull a specific branch and build the jar, then it should be relatively easy.
To those who will be in need of this in the future:
first integrate Jitpack in Your Android app, following their instructions:
https://jitpack.io/
Then paste teh GitHub url of jackson-dataformat-xml on Jitpack sites' corresponding text box. GitHub url is:
https://github.com/FasterXML/jackson-dataformat-xml.
That's it! Enjoy the result. :)

Categories

Resources