Getting the Android SDK directory within a gradle task - android

Recently the gradle plugin for android got updated (with android studio), after which the previous way of getting to the SDK directory ceased to work. The expression
${android.plugin.sdkDirectory}
which worked in an older version now returns the error
Error:(42, 0) No such property: sdkDirectory for class: com.android.build.gradle.LibraryPlugin
What would be the proper way of getting the android SDK directory being used, preferably independent of the user's configuration such as plugin and gradle version? The script needs to be shareable with several users.

Since all the previous answers depend on the environment or specific user intervention on top of normal configuration, I'll just post my technically messy fix.
if (android.hasProperty('plugin')) {
if (android.plugin.hasProperty('sdkHandler')) {
androidPath = android.plugin.sdkHandler.sdkFolder
} else {
androidPath = android.plugin.sdkDirectory
}
} else {
androidPath = android.sdkDirectory
}
Unlike all previous methods, this actually works, but it still looks hacky.

In gradle.properties set location sdkdir=/home/user/android-sdk and then in gradle you can use $sdkdir

I'm using Android gradle plugin v1.2.3 and this works fine:
${android.sdkDirectory}

You can use
$System.env.ANDROID_HOME

export ANDROID_HOME=/xxx/xxx/ in shell, then use it by System.env.ANDROID_HOME in gradle file.

Related

How to generate OpenAPI sources from gradle when building Android app

What I'm trying to achieve
I'm trying to generate my REST API client for Android using OpenAPI Generator from the build.gradle script. That way, I wouldn't have to run the generator command line every time the specs change. Ideally, this would be generated when I build/assemble my app, and the sources would end up in the java (generated) folder, where generated sources are then accessible from the code (this is what happens with the BuildConfig.java file for example).
What I've tried so far
Following this link from their official GitHub, here's the build.gradle file I ended up with:
apply plugin: 'com.android.application'
apply plugin: 'org.openapi.generator'
...
openApiValidate {
inputSpec = "$rootDir/app/src/main/openapi/my-api.yaml"
recommend = true
}
openApiGenerate {
generatorName = "java"
inputSpec = "$rootDir/app/src/main/openapi/my-api.yaml"
outputDir = "$buildDir/generated/openapi"
groupId = "$project.group"
id = "$project.name-openapi"
version = "$project.version"
apiPackage = "com.example.mypackage.api"
invokerPackage = "com.example.mypackage.invoker"
modelPackage = "com.example.mypackage.model"
configOptions = [
java8 : "true",
dateLibrary : "java8",
library : "retrofit2"
]
}
...
First, I've never managed to get the API generated with the build/assemble task, even when I tried adding:
compileJava.dependsOn tasks.openApiGenerate
or
assemble.dependsOn tasks.openApiGenerate
The only way I could generate the sources was by manually triggering the openApiGenerate task:
Then, when I do generate my sources this way, they end up in the build folder but aren't accessible from my code, and aren't visible in the java (generated) folder:
I then have to manually copy/paste the generated source files to my project sources in order to use the API.
Even though I'm able to work around these issues by adding manual procedures, it would be way more maintainable if the whole process was simply automatic. I was able to achieve a similar result with another tool, Protobuf. Indeed, my gradle task gets triggered every time I build the app, and the sources end up in the java (generated) folder, so I don't have to do any additional work. The task is much simpler though, so I assume the main work that I'm not able to replicate with OpenAPI Generator is handled by the Protobuf plugin itself.
You have to specify path to the generated sources as a custom source set for your Gradle module, which is app in this case, as described here – https://developer.android.com/studio/build/build-variants#configure-sourcesets. That way Gradle will treat your sources as accessible from your code.
Something like this:
android {
...
sourceSets {
main {
java.srcDirs = ['build/generated/openapi/src/main/java']
}
}
...
}
I solved the issue you described like this, I'm using gradle.kts however.
See my build.gradle.kts
plugins {
// Your other plugins
id("org.openapi.generator") version "5.3.0"
}
openApiGenerate {
generatorName.set("kotlin")
inputSpec.set("$rootDir/app/src/main/openapi/my-api.yaml")
outputDir.set("$buildDir/generated/api")
// Your other specification
}
application {
// Your other code
sourceSets {
main {
java {
// TODO: Set this path according to what was generated for you
srcDir("$buildDir/generated/api/src/main/kotlin")
}
}
}
}
tasks.compileKotlin {
dependsOn(tasks.openApiGenerate)
}
You need to build the application at least once for the IDE to detect the library (at least this is the case for me in Intellij)
Your build should automatically generate the open api classes , to refer the generated classes in your java project you should add the generated class path to your source directory like it was mentioned in the other answers
https://developer.android.com/studio/build/build-variants#configure-sourcesets
As far as the task dependency goes , in android tasks are generated after configuration thus for gradle to recognize the task , wrap it inside afterEvaluate block like
afterEvaluate {
tasks.compileDebugJavaWithJavac.dependsOn(tasks.openApiGenerate)
}
I had this issue, and this answer https://stackoverflow.com/a/55646891/14111809 led me to a more informative error:
error: incompatible types: Object cannot be converted to Annotation
#java.lang.Object()
Taking a look at the generated files that were causing this error, noticed:
import com.squareup.moshi.Json;
After including a Moshi in the app build.gradle, the build succeeded and the generated code was accessible.
implementation("com.squareup.moshi:moshi-kotlin:1.13.0")

How to resolve "Obsolete custom lint check" for my custom IssueRegistry written in Kotlin and make it work (Android)

I am trying to implement custom lint checks (using Kotlin). I have set up a module for my custom checks and added classes to test my first lew lint check, mostly following these two tutorials here and here.
So I now have a module, I have a custom IssueRegistry, I've created an issue and a Detector class for it. So far it seems complete. I've added a test to check if my lint check works and it looks alright.
I have added my module to the project by referencing it in settings.gradle like this: include ':app', ':somemodule', ':mylintmodule'
Now if I run the linter using ./gradlew lint I get a lint result file telling me this:
Lint found an issue registry (com.myproject.mylintmodule) which requires a newer API level. That means that the custom lint checks are intended for a newer lint version; please upgrade
Lint can be extended with "custom checks": additional checks implemented by developers and libraries to for example enforce specific API usages required by a library or a company coding style guideline.
The Lint APIs are not yet stable, so these checks may either cause a performance degradation, or stop working, or provide wrong results.
This warning flags custom lint checks that are found to be using obsolete APIs and will need to be updated to run in the current lint environment.
It may also flag issues found to be using a newer version of the API, meaning that you need to use a newer version of lint (or Android Studio or Gradle plugin etc) to work with these checks.
To suppress this error, use the issue id "ObsoleteLintCustomCheck" as explained in the Suppressing Warnings and Errors section.
So it tells me that I am using a newer API verion in my custom lint check, right? This is my custom IssueRegistry (minus some parts not relevant for this problem):
class MyCustomIssueRegistry : IssueRegistry() {
override val issues: List<Issue>
get() = listOf(ISSUE_NAMING_PATTERN)
override val api: Int = com.android.tools.lint.detector.api.CURRENT_API
override val minApi: Int = 1
}
From googling this problem and finding this issue I figured I have to override and set the right API version (and maybe the min API?) by overriding these properties like I did above (this version is my last attempt, directly taken from that issue).
So this property can be set to values between -1 and 5, meaning this (taken right out of the lint.detector.api class):
/** Describes the given API level */
fun describeApi(api: Int): String {
return when (api) {
5 -> "3.5+" // 3.5.0-alpha07
4 -> "3.4" // 3.4.0-alpha03
3 -> "3.3" // 3.3.0-alpha12
2 -> "3.2" // 3.2.0-alpha07
1 -> "3.1" // Initial; 3.1.0-alpha4
0 -> "3.0 and older"
-1 -> "Not specified"
else -> "Future: $api"
}
I have tried all of them, plus the one above adding a minApi override too, and I keep getting the exact same result for each of them.
Also I am unable to locate what other API version this is compared with. Is there a place where this is set for the regular linter in an Android project?
It's also unclear to me what I have to do to make sure my changes got applied - is it enough to change some code, then run lint, or do I have to compile the project first, or build & clean?
Following the tutorials, I added my custom lint check by adding this to the app's build.gradle: lintChecks project(":mylintmodule")
Is that even right? The API issue on my registry class shows up no matter if my lint check is referenced (and hopefully used) like that or not. I have also tried the other method described in the first tutorial, adding this task to the linter module build.gradle:
defaultTasks 'assemble'
task copyLintJar(type: Copy) {
description = 'Copies the lint jar file into the {user.home}/.android/lint folder.'
from('build/libs/')
into(System.getProperty("user.home") + '/.android/lint')
include("*.jar")
}
// Runs the copyLintJar task after build has completed.
build.finalizedBy(copyLintJar)
But since I can't figure out how to see if my custom checks are actually run, I don't know if that works as intended either.
So how do I get this warning resolved (since I interpret the text as "As long as the versions don't match I will not try to run your lint check"), and how can I make sure my lint check is actually run by the linter?

Is there a way to change the gradle.properties file in Unity

Unity has a default gradle.properties file that gets added during the build process. While its possible to change the build.gradle and the settings.gradle files as mentioned
here https://docs.unity3d.com/Manual/android-gradle-overview.html
there is no mention of being able to change gradle.properties within the unity docs. The file also gets recreated every build attempt so editing it within the temp/gradleOut after a build and building again doesn't work. I know exporting the project is possible as well, but I'm looking for a solution where the project can be run directly from unity.
Btw this question is NOT a duplicate of this question How to use Gradle in Unity
The answer here has nothing to do with modifying the gradle.properties file.
This is a duplicate of this question that got incorrectly marked as a duplicate how to change default gradle.properties of Unity?
Maybe my answer is a bit outdated but in Unity 2020 you can do it in:
Player Settings -> Tab Android (with robot obviously) -> Publishing Settings -> Custom Gradle Properties Template (checkbox).
After enabling the checkbox you will see the path to gradleTemplate.properties (usually it appears in Assets/Plugins/Android directory) file which will be merged with final gradle.properties.
Everything you need you can write to the end of file after **ADDITIONAL_PROPERTIES** string.
Example:
org.gradle.jvmargs=-Xmx**JVM_HEAP_SIZE**M
org.gradle.parallel=true
android.enableR8=**MINIFY_WITH_R_EIGHT**
**ADDITIONAL_PROPERTIES**
android.useAndroidX = true // I added this property to fix error: This project uses AndroidX dependencies, but the 'android.useAndroidX' property is not enabled. Set this property to true in the gradle.properties file and retry.
Also on screenshot:
This was something that was slightly hard to discover. I was going to do a regular post build processor like I had for my iOS build, but as I was searching for a manner to load and determine where the properties file was, I ran across the following interface in the documentation : IPostGenerateGradleAndroidProject.
According to the documentation:
Implement this interface to receive a callback after the Android
Gradle project is generated.
So below is my initial brute force implementation for turning on androidX and jetifier.
public class AndroidPostBuildProcessor : IPostGenerateGradleAndroidProject
{
public int callbackOrder
{
get
{
return 999;
}
}
void IPostGenerateGradleAndroidProject.OnPostGenerateGradleAndroidProject(string path)
{
Debug.Log("Bulid path : " + path);
string gradlePropertiesFile = path + "/gradle.properties";
if (File.Exists(gradlePropertiesFile))
{
File.Delete(gradlePropertiesFile);
}
StreamWriter writer = File.CreateText(gradlePropertiesFile);
writer.WriteLine("org.gradle.jvmargs=-Xmx4096M");
writer.WriteLine("android.useAndroidX=true");
writer.WriteLine("android.enableJetifier=true");
writer.Flush();
writer.Close();
}
}
Theoretically you should be able to manipulate the generated gradle project in any manner to your choosing during the post build processor. Some additional tools might be helpful, like the PBXProject support on iOS, but until then, this will do.
IPostGenerateGradleAndroidProject is a new Interface added after Unity2018.
As my project based on Unity2017, it's not a good solution. Then I found this. A solution with Gradle.
([rootProject] + (rootProject.subprojects as List)).each {
ext {
it.setProperty("android.useAndroidX", true)
it.setProperty("android.enableJetifier", true)
}
}
Although this is not a perfect solution, you can use the "Export Project" option.
Build Settings
After exporting the project, you can modify gradle.properties and build using AndroidStudio or command line.
In the newer Unity versions (2019.4+) it is possible to generate a custom gradle properties template by going to Project Settings > Player > (Android Tab) > Other Settings > and marking "Custom Gradle Properties Template".
After selecting that a gradleTemplate.properties file is generated at "Assets/Plugins/Android/gradleTemplate.properties".
This is the best way of generating the file since it is git friendly and preserves other settings.

include.gradle file being generated is causing problems

When building a project I get the following error:
Flavor 'nativescript-telerik-ui' has unknown dimension 'nativescript-telerik-ui'.
It happens only when using the pro version through the #progress registry. Doesn't happen with the local .tgz pro version.
I noticed the error has to do with the include.gradle file it generates. I read the following article: https://docs.nativescript.org/plugins/plugins#includegradle-specification
It says that when the plugin doesn't have the include.gradle, at build time gradle creates a default one with default elements. When I saw the include.gradle it generated for the plugin it seems to have generated a default one like so:
android {
productFlavors {
"nativescript-telerik-ui" {
dimension "nativescript-telerik-ui"
}
}
}
The include.gradle generated for the local .tgz version of the plugin is like this:
android {
productFlavors {
"F6" {
dimension "nativescripttelerikuipro"
}
}
}
I replaced the default include.gradle with the latter and it got past the error. You can recreate the problem by following these steps:
create a new hello world app
use the command npm login --registry=https://registry.npm.telerik.com/ --scope=#progress to log in if you're a paying customer.
use the command npm install --save #progress/nativescript-telerik-ui-pro to install the plugin
use tns run android
Is there anything I can do to solve this problem? Really need help on this.
My name is Vladimir and I am part of the nativescript-telerik-ui-pro team. Thank you for logging this issue in our feedback portal. We are going to review it as soon as possible and update you regarding its status, but from what I currently see there is some incorrect "parameters" passed to the 'pro' version of the plugin that are going to be resolved very fast.
We apologize for any inconvenience that this is causing.

Android Unit Tests - no such property: bootClasspath

I'm trying to execute a simple test case for Android following just announced unit testing support - http://tools.android.com/tech-docs/unit-testing-support
After carefully following the walkthrough I'm trying to run ./gradlew test.
I'm getting this error:
Execution failed for task ':app:compileDebugGroovy'.
> No such property: bootClasspath for class: com.android.build.gradle.AppPlugin
while using com.android.tools.build:gradle:1.1.0-rc1.
Anyone else got stuck on that?
The problem is that Groovy Android Gradle plugin (to have Groovy working on Android) isn't simply working with Android plugin in version 1.1.0-rcX.
Here's a very interesting piece of code directly from groovyx.grooid.GroovyAndroidPlugin, version 0.3.5 (current latest, here's the source)
def getRuntimeJars(Project project, plugin) {
int index
switch (getAndroidPluginVersion(project)) {
case ~/0\.9\..*/:
index = 0
break
case ~/0\.10\..*/:
case ~/0\.11\..*/:
case ~/0\.12\..*/:
case ~/0\.13\..*/:
case ~/0\.14\..*/:
case ~/1\.0\..*/:
index = 1
break
default:
index = RUNTIMEJARS_COMPAT.size()-1
}
def fun = RUNTIMEJARS_COMPAT[index]
fun(plugin)
}
and definition of RUNTIMEJARS_COMPAT:
private static List RUNTIMEJARS_COMPAT = [
{ it.runtimeJars },
{ it.bootClasspath }
]
So that API must have changed in Android Gradle between 0.9.x and 0.10.0 (yeah, I know - those Google devs change everything there :[ ). So let's take a look at that problem making class in Android Plugin version 1.0.0:
> javap -cp [path to proper jar] com.android.build.gradle.AppPlugin:
public class com.android.build.gradle.AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradle.api.Plugin<org.gradle.api.Project> {
...
public java.util.List super$2$getBootClasspath();
...
Yup! There's the method we need (coming from parent com.android.build.gradle.BasePlugin class). Now there's nothing like that in version 1.1.0-rc3. What's more, the API of com.android.build.gradle.AppPlugin is completely changed, so it's not a matter of simple if(version) to fix that.
I guess there's no chance to have Groovy Android Gradle plugin working with Unit Tests (since 1.1.0) until authors update the plugin.
Let's wait then.
That Testing Support feature is experimental. That said maybe there is no quick solution to your issue or might be a bug.
However, I would dig deeper into this, reading the message:
This line Execution failed for task ':app:compileDebugGroovy'. mentions the task, so I would go and figure what that task does. I suppose it's a delivered task. The error being that in that task there is a property missing > No such property: bootClasspath for class: com.android.build.gradle.AppPlugin
So maybe try to find that task and make sure the bootClasspath property is set for the AppPlugin class.
Try to upgrade to the new version (RC3)
dependencies {
classpath 'com.android.tools.build:gradle:1.1.0-rc3'
// ..
}
You can also take a look here in order to compare your current setup with a working example.

Categories

Resources