Android Studio 3.0 NoClassDefFoundError after UPDATE GRADLE to 4+ - gradle

I made a project with two modules - an Android application and a java library. After upgrading studio to v3.0, I get NoClassDefFoundError, only when I run the main() method from the java-lib module.
I did not make any changes to the build.gradle files, everything was automatic. implementation / api / compileOnly / runtimeOnly methods do not change.
I see information about switching to a new plug-in, it says about "Declare flavor dimensions". I have a problem with the translation of this and will soon go mad.
I tried:
classpath 'com.android.tools.build:gradle:3.0.0'
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-rc-4-all.zip
Help me migrate to GRADLE 4+.

You know, I've probably found the answer to my own question. I'm sure that many people have a project with two modules. The Android module works well with the new GRADLE 4+, and the second module as a java project (not a library) does not work with the new GRADLE 4+.
Result of search for the answer: LibGDX - GitHub

As stated in Android Developer Documentation:
In some cases, you may want to combine configurations from multiple product flavors. For example, you may want to create different configurations for the "full" and "demo" product flavors that are based on API level. To do this, the Android plugin for Gradle allows you to create groups of product flavors, called flavor dimensions. When building your app, Gradle combines a product flavor configuration from each flavor dimension you define, along with a build type configuration, to create the final build variant. Gradle does not combine product flavors that belong to the same flavor dimension.
You must specify at least one flavorDimension for Android Studio 3.0 & Gradle 4+
Most importantly, even if you don't have different flavors, you must specify at least one flavorDimension & apply it to all your productFlavors. That will solve your error. In your build.gradle file:
flavorDimensions "dummy"
productFlavors {
demo {
// Assigns this product flavor to the "dummy" flavor dimension.
dimension "dummy"
...
}
full {
dimension "dummy"
...
}

Related

Gradle monobuild and map of jar files for all gradle composite builds

We have a directory structure like so
java
build/build.gradle (This does NOT exist yet, but we want this)
servers
server1/build.gradle
server2/build.gradle
libraries
lib1/build.gradle
lib2/build.gradle
We have 11 servers and 14 libraries with varying uses of dependencies. EACH server is a composite build ONLY depending on libraries (we don’t allow servers to depend on each other). In this way, as our mono-repo grows, opening up server1 does NOT get slower and slower as more and more gradle code is added(ie. gradle only loads server1 and all it’s libraries and none of the other libraries OR servers are loaded keeping things FAST).
Ok, so one problem we are running into is duplication now which is why we need build/build.gradle file AND we want EVERY module in our mono repo to include that somehow for a few goals(each goal may need a different solution)
GOAL 1: To have an ext { … } section containing a Map of Strings to gradle dependencies much like so
deps = [
'web-webserver': "org.webpieces:http-webserver:${webpiecesVersion}",
'web-webserver-test': "org.webpieces:http-webserver-test:${webpiecesVersion}",
'web-devrouter': "org.webpieces:http-router-dev:${webpiecesVersion}"
]
In this way, we want ALL our projects to them import dependencies like so
compile deps['web-webserver']
GOAL 2: We want to 'include' a standard list of plugins so we are versioning all gradle plugins the same across the repo. While the above configures all jars to avoid jar hell in a mono-repo, we would like to do the same with just this section
plugins {
id 'com.github.sherter.google-java-format' version '0.9'
}
Of course, it each project may also want to add a few more plugins OR even not depend on this section(in case of an emergency and trying to just get the job done).
GOAL 3: We want checkstyle configuration (or any plugin config) to be defined the SAME for all projects (eventually!!!). We would like the checkstyle gradle to live in a common area but have all libraries somehow pull it in. Again, it would be nice for it to be optional in that, I can pull the gradle section into my build.gradle OR can create a new one in case of emergencies so I don't have to fix all projects in the monorepo right away.
IDEALLY, perhaps I kind of want configuration injection where when I run server1/build.gradle, it actually runs java/build/build.grade as it’s parent somehow but with overrides (IF I declare 'extends xxx.gradle' maybe) then all libraries it uses also use java/build/build.gradle as their parent. I am not sure this is possible or feasible. I am pretty sure 'extends xxx' doesn't exist in gradle.
Are any of these GOALS possible?
thanks,
Dean
I have been working on a monorepo with the exact same requirement as you, using gradle composite builds as well. The way we have solved this problem is by using pre compiled plugins
You need to do a new gradle project with only the code you want to share. This will create a plugin, that you can just add as a composite build and apply to the other projects.
I'm a bit confused by why you don't just use a "standard" gradle top level build file and compose the others as subprojects.
This solves all 3 of your goals
If you are concerned by build speed, you can target each server individually simply by running
./gradlew :server1:build
But if you are not able to do this for some reason you can use the apply from: syntax as described here

Gradle includeBuild vs implementation project

What is the key difference between includeBuild(...) and implementation(project(...)) in the Gradle build system? I cannot really see the usecase difference after reading the documentation:
https://docs.gradle.org/current/userguide/declaring_dependencies.html#sub:project_dependencies
https://docs.gradle.org/current/userguide/composite_builds.html#separate_composite
What I am trying to do: Share same codebase for two separate projects: data classes (kotlix.serialization), external database dao, interfaces. It is not a full library but just some code snippets.
How can I connect the two projects in Intellij so that type hinting works?
Composite Build (by using includeBuild) is a way to create a dependency between autonomous Gradle Projects.
Project import, is a way to create a dependency between two modules within a same Gradle Project.
Composite Build is far more powerful and is also meant to be the new way of factorizing gradle configuration between multiple projects that you traditionally do with the buildSrc technique.
I found this "Structuring Large Projects" article to be easier to read than the "Composite Builds" doc.
An excellent sample project that demonstrates the power of Composite Builds can be found in Gradle sample_structuring_software_projects.
Project dependency case
The tree would look like this:
settings.gradle.kts
module1/build.gradle.kts
module2/build.gradle.kts
And you are declaring a dependency in module1/build.gradle.kts like this:
dependencies {
implementation(project("com.domain:module2"))
}
The dependency will be resolved only if both projects are declared as sub-modules of a common root project.
It means you have a root settings.gradle.kts like this:
rootProject.name = "rootProject"
include(":module1")
include(":module2")
Composite build case
The projects do not need to have common "umbrella" root project.
Each project is a totally independent project.
One project can simply declare a dependency on the other project (without even the target project knowing about it).
Tree:
project1/build.gradle.kts
project1/settings.gradle.kts
project2/build.gradle.kts
project2/settings.gradle.kts
In project1/settings.gradle.kts:
rootProject.name = "project1"
includeBuild("../project2") //No more ':' as it is not a module
In project2/settings.gradle.kts:
rootProject.name = "project2"
In project1/build.gradle.kts like this:
dependencies {
implementation("com.domain:project2")
}
I have the same problem. Reading on the first link, the next para says:
Local forks of module dependencies
A module dependency can be substituted by a dependency to a local fork
of the sources of that module, if the module itself is built with
Gradle. This can be done by utilising composite builds. This allows
you, for example, to fix an issue in a library you use in an
application by using, and building, a locally patched version instead
of the published binary version. The details of this are described in
the section on composite builds.
So, it should be implementation project according to me.
P.S. The code completion is working on one of my sub project but not on the other. I am still trying to figure that out

Is there a way to define property to be used in both settings.gradle.kts and projects/subprojects build.gradle.kts with gradle 6.0?

We have multi-module android app with build logic written in gradle kotlin dsl. We use buildSrc to extract common logic like dependencies versions. We have something like:
buildSrc/src/main/kotlin/Dependencies.kt:
object Versions {
const val fooVersion = "1.2.3"
const val barVersion = "4.5.6"
}
object Libraries {
val foo = "com.example.foo:foo:$fooVersion"
val bar = "com.example.bar:bar:$barVersion"
}
object Modules {
const val app = ":app"
const val base = ":base"
const val baz = ":baz"
}
Then we can use these in modules' dependencies block to avoid hardcoded/duplicated values:
app/build.gradle.kts:
dependencies {
implementation(Libs.foo)
implementation(Libs.bar)
implementation(project(Modules.base))
implementation(project(Modules.baz))
}
And we also use it in settings.gradle.kts:
settings.gradle.kts:
include(
Modules.app,
Modules.base,
Modules.baz
)
This works ok with gradle 5.6. When I upgrade to 6.0, I get Unresolved reference: Modules in settings.gradle.kts file. I found it mentioned in migration guide:
Previously, the buildSrc project was built before applying the project’s settings script and its classes were visible within the script. Now, buildSrc is built after the settings script and its classes are not visible to it. The buildSrc classes remain visible to project build scripts and script plugins.
Custom logic can be used from a settings script by declaring external dependencies.
So I know what broke the build and I can fix the build by using hardcoded values in settings.gradle.kts:
include(
":app",
":base",
":baz"
)
Is it possible to avoid this duplication with gradle 6.0?
Please make sure you read the updates down below.
Original answer
See ticket #11090 "Definitions from buildSrc/ not found in settings.gradle.kts using gradle 6.0-rc-1". As you already noticed this changed recently:
This has changed in 6.0, and was deprecated in 5.6. Please see: https://docs.gradle.org/current/userguide/upgrading_version_5.html#buildsrc_usage_in_gradle_settings
-- https://github.com/gradle/gradle/issues/11090#issuecomment-544473179
One of the maintainers describes the reasons behind the decision:
Unfortunately, there are pros and cons to both arrangements (settings-then-buildSrc and buildSrc-then-settings), and we opted for the former after considering.
(...)
The pros that compelled us to make the change:
Settings plugins can influence buildSrc and main build (i.e. apply a build plugin to both)
Build cache configuration is applied to buildSrc
buildSrc behaves more like a regular included build
-- https://github.com/gradle/gradle/issues/11090#issuecomment-545697268
And finally some bad news:
We won't be changing the behaviour back to the pre Gradle 6 arrangement. Please let us know if you would like more detail on how to use one of the alternative mechanisms for using complex logic in a settings script.
-- https://github.com/gradle/gradle/issues/11090#issuecomment-545697268
Workarounds
In the aforementioned post the author proposes some workarounds:
The con of this is exactly what you have hit. It's now less convenient to use complex logic in your settings script. Now, you have to either:
Inline the logic into the settings file
Move the logic to a shared script that can be used where it needs to
Move the logic to a pre-built binary that you load in the settings file (i.e. a settings plugin)
-- https://github.com/gradle/gradle/issues/11090#issuecomment-545697268
#1 is pretty straightforward, but I can only assume what #2 and #3 mean. I come from the Groovy world and only recently started making friends with Kotlin DSL. Having said that let's give it a try.
In #3 the author might be talking about developing an external plugin and applying it in both scripts. I'm not really sure if this is something that would make sense to implement (it gives you strong typing though).
"#2 Move the logic to a shared script that can be used where it needs to"
I think it's about having a common script plugin and including it in both settings.gradle and build.gradle files. The plugin would put the static information in the ExtraPropertiesExtension of the ExtensionAware in scope (Settings in case of a settings.gradle script plugin and Project in case of build.gradle). This is described in this answer to "Include scripts with Gradle Kotlin DSL":
How can I put all common constants (such as dependency versions) to the separate file to include them just by using something like springBootVersion or Constants.springBootVersion with compile-time checks?
There is no good way to do it currently. You can use extra properties, but it won't guarantee compile time checks. Something like that:
// $rootDir/dependencies.gradle.kts
// this will try to take configuration from existing ones
val compile by configurations
val api by configurations
dependencies {
compile("commons-io:commons-io:1.2.3")
api("some.dep")
}
// This will put your version into extra extension
extra["springBootVersion"] = "1.2.3"
And you can use it like this:
// $rootDir/build.gradle.kts
subprojects {
apply {
plugin<JavaLibraryPlugin>()
from("$rootDir/dependencies.gradle.kts")
}
And in your module:
// $rootDir/module/build.gradle.kts
// This will take existing dependency from extra
val springBootVersion: String by extra
dependencies {
compile("org.spring:boot:$springBootVersion")
}
-- Include scripts with Gradle Kotlin DSL
UPDATE 1
The issue has become popular and gained attraction from Gradle maintainers:
Since there are so many comments still on this issue, let me clarify a few things about where we are and where we are actively moving to right now.
For the general topic "I want buildSrc to be done before anything else" there will be a solution soon with included builds and setting plugins. Most likely in the next release. Then you will be able to include a build, using a new DSL method, that is available earlier. This build can then contain a settings plugin which you can apply in settings. This makes the Jar containing the plugin available on the settings classpath. (Although ideally you would define a plugin extension and not use classes/static methods directly.)
settings.gradle.kts
pluginManagement {
includeBuildEarly("my-build-logic") //<- WIP - new API under development
}
plugins {
apply("my.settings.plugin) // this is defined in the "my-build-logic" build
}
For the topic of sharing dependencies and versions, we are also working on general improvements that might make some "custom solutions" unnecessary in the future.
Generally, you should try to avoid using buildscript {} or using resolutionStrategy {} in settings. Instead you can define plugins in included builds. You can then manage all dependencies (also to plugins) in the build files of these builds.
If you want to share constants between all these builds, you can have one build only for these constants that you include in all others. Like the libraries build in this example..
See also the sample about sharing convention plugins with build logic build.
Hope these are some helpful pointers.
-- https://github.com/gradle/gradle/issues/11090#issuecomment-734795353
UPDATE 2
Nowadays (Gradle 7+) you could use Version Catalogs to share dependency versions across buildSrc and the regular build. Please refer to the official documentation and this answer.
AFAIK - no, and that is what aforementioned migration guide says: settings.gradle is the first to be evaluated, thus, at that stage, objects defined in buildSrc don't even exist yet.
I can image some hacky workaround - just for the science, but in real project it would smell so bad that, IMO, not worth it.
P. S.: I guess you could reverse it and try to create instance of some enumeration by going through submodules in buildSrc code. But again, ways to achieve this might be quite exotic and should only be used for the sole purpose of proving this can work )

Conditional plugin dependency based on platform in Nativescript

Is it possible to have a conditional package.json dependency based on the platform being built for, or, some hook that excludes / includes a dependency based on platform, when building a Nativescript 5.1 project?
My original plan was to use a Yarn alias to load 2 separate versions of a given package, then use platform.isIOS or platform.isAndroid to include only the right JS. However, under the hood the C++ shared object that both dependencies contain obviously has the same name - which gets clobbered, and both versions of the plugin end up using the same SO (defeating the point of the alias, as the bug I'm trying to get round is in the SO, not the plugin).

How do I determine which levels are available for a given dependency?

I'm relatively new to Android Studio and find myself very confused about the levels for dependencies in Gradle. Let me explain why, then I am seeking assistance with a specific issue and the broader issue of choosing dependency levels. I should mention that I am using Android Studio 3.1.3 with Gradle 4.4. My Min SDK Level is 24 and my compile level is 27).
I am doing my first experiments with Settings and have skimmed several tutorials (online and in YouTube). They all begin with the advice that you need to add a dependency for Preferences in your Gradle file. (They aren't consistent in WHICH dependency to add but I think that's because there are different approaches to doing preferences.) In any case, once you've chosen which approach you are going to take, you need to add the appropriate dependency to your build.gradle (Module app) file.
So, let's say we decide to add com.android.support:preference. According to the manual - https://developer.android.com/reference/android/support/v7/preference/Preference - the current version is v7:28.0.0-alpha1. If I add that to the Gradle file though and try to sync, Android Studio tells me I should not let the dependency be a higher level than the compile SDK level (which is 27).
So, I imitated the level that I used in other dependencies, like appcompat, and set the level to v7:27.1.1 and tried to sync again. That failed too. Apparently, no such version of the dependency exists.
Most of the tutorials I've seen are two years old and refer to dependencies that are at level 24, which I assume is going to be too low.
And that brings me to my question: How do I determine which versions of a dependency actually exist so that I can choose an appropriate level?
I read through this page on the Android developer site and I suspect you may have the syntax wrong for the dependency. The v7 should be part of the module name, not the version as I understand it.
Try:
dependencies {
implementation "com.support.android-v7:27.1.1"
}
This page makes reference to palette-v7:27.1.1 so I assume the same version exists for preference.

Resources