Why must $kotlin_version be explicitly specified in Android? - android

Supporting Kotlin in an Android studio project requires two dependencies: kotlin-gradle-plugin in Project/build.gradle and kotlin-stdlib-jdk7 in Project/app/build.gradle, and these two need to have the same version. The common method seems to be using a single kotlin_version variable which you then have to manually change when the IDE updates its Kotlin plugin — as of Android Studio 3.1.3, the IDE is still not able to automatically update the dependencies if you use a $variable as the version.
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
In non-Android Kotlin projects i.e. those using apply: 'kotlin' instead of apply plugin: 'kotlin-android', it is possible to simply omit the version from the kotlin-stdlib-jdk7 dependency, which will then be automatically resolved from the plugin.
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7'
This even works on non-Android modules within Android projects. My question is, why is this not possible in Android modules? Why can't the $kotlin_version simply be omitted? If the feature has been present since Kotlin 1.1.2, why is it still causing compile errors on Android even on Kotlin 1.2.51? Or is it actually possible to do this, and if so, how can it be done?

In fact this is not Kotlin specific but has to do with how Gradle manages dependencies.
See https://docs.gradle.org/current/userguide/declaring_dependencies.html on how to specify the version of a dependency in Gradle.
In this case
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
is the standard way of setting the version. As the this version number is the same for several dependency it is declared in a variable in order to make it easy to change the version for all Kotlin libraries.
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7'
Uses dependency constraints which are available since Gradle 4.6. It is used for the same purpose. One can set the version of a library in a central place and this way keep the version at a common value without having to go through all gradle.properties files of a larger project.

Related

Library not adding its dependencies when used

I made a library, but when I tried to use it with implementation 'com.example:mylibrary:1.3.0' in my app's build.gradle, I keep getting an error saying the ConstraintLayout dependency (which the library uses but not the app) is not found. However it was explicitly defined in the library's build.gradle with implementation.
When I ran gradlew app:dependencies on the terminal, it shows that the library has no dependencies, even though it actually has 2. This seems to be the source of the problem, Gradle can't detect the dependencies of the library.
I didn't run into this problem for a while but when I decided to remove the ConstraintLayout dependency from my app an error appears during build.
When you're using implementation for the dependencies in your library, the project which is dependent with it will not see the dependencies. You need to use api instead of implementation.

What is the correct way to move gradle dependency versions to a variable?

In order to maintain the version numbers of my gradle dependencies, I chose the below pattern.
In my project level build.gradle I added:
ext.versions = [
'kotlin_version' : '1.2.30',
'dagger' : '2.16'
]
And in my app module's build.gradle I added:
implementation "com.google.dagger:dagger:${versions.dagger}"
implementation "com.google.dagger:dagger-android-support:${versions.dagger}"
implementation "com.google.dagger:dagger-android:${versions.dagger}"
kapt "com.google.dagger:dagger-compiler:${versions.dagger}"
kapt "com.google.dagger:dagger-android-processor:${versions.dagger}"
But my problem is after doing this, I lost the lint warnings of "Newer Library versions available".
What is the correct way to do this without missing the lint checks?
Note: I have also tried other ways like moving these versions to gradle.properties file (for global variables).
I am looking for a solution inside Android Studio. There is one solution which I already found:
Analyze -> Run Inspection by name... -> Type "Newer Library Versions Available"
But my concern is, it is easy to miss on updates until we run some or the other script. That is why I am trying to find a way where dependency versions can be put in a variable and get lint warning for new updates.
See this answer: https://stackoverflow.com/a/46296198/2053763
There is a link to a gradle plugin which can check for dependency updates.
Android Studio 3.1.2 offers some lint checks while using version variables, but still misses some of the updates. See image below:
You can extract dependencies versions into variables stored in a separate Gradle file and then check and update them from the Project Structure (ctrl+alt+shift+S) (screenshot from Android Studio 3.6.3):

Issue with DJI SDK gradle 4.4.0, provided keyword in gradle not working

Previously my gradle used to look like this and worked fine (apart from few registered bugs)
implementation 'com.dji:dji-sdk:4.3.2'
Now, after changing to
implementation 'com.dji:dji-sdk:4.4.0'
the Camera and other files cannot be recognized anymore. I am attaching a screenshot of the unrecognized imports.
However when I am trying to add
//dji-drones-sdk
implementation 'com.dji:dji-sdk:4.4.0'
provided 'com.dji:dji-sdk-provided:4.4.0'
I am getting "could not download dji-sdk-provided.jar"
Screenshot attached
All the examples and github codes are in version 4.3.2. Can anyone help me out?
Here is the link to the dji sdk
I have found the issue. After Gradle 3.4, the "provided" is replaced by "compileOnly"
I quote,
Gradle adds the dependency to the compilation classpath only (it is not added to the build output). This is useful when you're creating an Android library module and you need the dependency during compilation, but it's optional to have present at runtime. That is, if you use this configuration, then your library module must include a runtime condition to check whether the dependency is available, and then gracefully change its behavior so it can still function if it's not provided. This helps reduce the size of the final APK by not adding transient dependencies that aren't critical. This configuration behaves just like provided (which is now deprecated).
Hence using compileOnly in place of provided will do the trick.
Here is a link to the gradle changes documentation

How does Gradle choose between more than 1 versions of the same library in a gradle tree?

Let say I have added Facebook and Twitter dependencies in my app.
com.facebook.android:facebook-android-sdk:4.22.1
com.twitter.sdk.android:twitter:2.1.0
When i look at Gradle tree, They come up with bunch of other transitive dependencies.
Now If Facebook uses com.android.support:support-annotations:24.1.1 and twitter uses com.android.support:support-annotations:25.0.3
Then which version gradle will use.
In gradle tree, It shows -> in front of older version of dependency. I learnt that this means gradle will use the newer version, and will not use the older version.
But this can be a problem, because some libraries are meant to run on the specific versions, and i have faced this problem.
In one of article i found out how npm manages these dependencies conflicts, but i am still unsure how gradle will manage between different version of same library.
You can't have different versions of the same library inside an apk.
As you mentioned, by default, Gradle puts the newest one to the build. If you want to specify a concrete version of the library that should be used in your project, you can add a direct compile (or implementation / api for Android Gradle Plugin v3+) statement with a required version to get one.
Also, you can force version using a special syntax, but it can lead to some problems later. You can find more information about version conflicts resolution in this post

Gradle dependency configuration : implementation vs api vs runtimeonly vs compileonly

Unable to understand the latest gradle dependency configurations which are introduced in Android Studio 3.0 i.e. implementation, api , compileonly and runtimeonly.
Please refer the link : Android Studio 3.0 New Gradle Configuration available at android developers official site.
Based on description mentioned in above link:
implementation: When your module configures an implementation dependency, it's letting Gradle know that the module does not want to
leak the dependency to other modules at compile time. That is, the
dependency is available to other modules only at runtime. Using this
dependency configuration instead of api or compile can result in
significant build time improvements because it reduces the amount of
projects that the build system needs to recompile. For example, if an
implementation dependency changes its API, Gradle recompiles only that
dependency and the modules that directly depend on it. Most app and
test modules should use this configuration.
api: When a module includes an api dependency, it's letting Gradle know that the module wants to transitively export that
dependency to other modules, so that it's available to them at both
runtime and compile time. This configuration behaves just like compile
(which is now deprecated), and you should typically use this only in
library modules. That's because, if an api dependency changes its
external API, Gradle recompiles all modules that have access to that
dependency at compile time. So, having a large number of api
dependencies can significantly increase build times. Unless you want
to expose a dependency's API to a separate test module, app modules
should instead use implementation dependencies.
compileOnly: Gradle adds the dependency to the compilation classpath only (it is not added to the build output). This is useful
when you're creating an Android library module and you need the
dependency during compilation, but it's optional to have present at
runtime. That is, if you use this configuration, then your library
module must include a runtime condition to check whether the
dependency is available, and then gracefully change its behavior so it
can still function if it's not provided. This helps reduce the size of
the final APK by not adding transient dependencies that aren't
critical. This configuration behaves just like provided (which is now
deprecated).
runtimeonly: Gradle adds the dependency to the build output only, for use during runtime. That is, it is not added to the compile
classpath. This configuration behaves just like apk (which is now
deprecated).

Categories

Resources