Android Studio 3.1.2 + Gradle 4.4 + libGDX 1.9.8 Setup

libGDX machte nach dem Update von Android Studio und Gradle Probleme. Das hat mir den Spaß am Framework genommen. Aber am Ende hat eine ganz bestimmte Konfiguration zum Erfolg geführt und meine Stimmung wieder angehoben.

für libGDX wird eine Android Studio Version empfohlen, die den Gradle-Wrapper 3.0.1 verwendet. Dieser ist aber inkompatibel mit Gradle 4.4. Sagt man also zu, ein Gradle-Update durchzuführen, führte das in meinem Fall zu einer Sackgasse. Das Projekt ließ sich nicht mehr bauen. Was tun?

Folgendes Setup lässt mich mein Demo anstandslos starten... und es fühl sich flott und lebendig an. Das ist ein perfektes Setup für den Start an Argh! Earthlings! für Android (und anderen Systemen).

Das Projekt habe ich zunächst mit dem libGDX-setup.jar, wie in der Doku angegeben, aufgesetzt. Keine Sonderlocken. Es sollte für Android, Desktop und iOS verfügbar sein.

Da kürzlich die Entwicklung von RoboVM eingestellt wurde, das für den Bau der iOS-Version zuständig war, habe ich mich in dieser Konfiguration kurzerhand gegen RoboVM und somit zunächst auch gegen iOS entschieden. Eine Option scheint die Multi-OS Engine zu sein, aber das ist ein Blog-Artikel für sich.

In der settings.gradle muss zuerst also der include ios raus.

include 'desktop', 'android', 'core'

Dann muss der Gradle-Wrapper unter gradle/wrapper/gradlw-wrapper.properties angepasst werden. Hier muss die distributionUrl auf gradle-4.7-all.zip gestellt werden.

#Wed May 16 20:12:31 CEST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-all.zip

Aktuell ist v4.7 der neuste finale Wrapper. Unter https://services.gradle.org/distributions/ findet man alle verfügbaren Versionen. Eine v4.8 ist in Entwicklung.

Weil nun Gradle in der Version 4.4 mit dem 4.7er Wrapper verwendet wird und dieses keine org.gradle.configureondemand mehr kennt, muss man diese ausschalten. Es gibt zwei Stellen im System wo dieses Flag steht.

Zuerst muss man die Konfiguration in den IDE Einstellungen vornehmen. Unter Preferences > Build, Execution, Deployment > Compiler gibt es die Checkbox Configure on demand, die abgehakt werden muss.

Android Studio Preferences

Damit wird die Konfiguration zentral in der ${HOME}/.gradle/gradle.properties vorgenommen.

Weiter geht es mit der gradle.properties im Projekt Root. Hier muss org.gradle.configureondemand auf false gesetzt, bzw. auskommentiert werden.

#org.gradle.configureondemand=false
org.gradle.daemon=true
org.gradle.jvmargs=-Xms128m -Xmx1500m

Für besseres Debugging habe ich mir die Warnings eingeschaltet:

org.gradle.warning.mode=all

Als nächstes knöpft man sich die build.gradle vor. Wie oben aufgeführt ist RoboVM rausgeflogen. Ein Kommentar vor classpath:com.mobidevelop.robovm reicht.

Im Classpath muss für com.android.tools.build:gradle die Version 3.1.2 eingestellt werden. Damit aber muss auch google() in die Repos unter buildscript/repositories aufgenommen werden.

buildscript {
	repositories {
		mavenLocal()
		mavenCentral()
		maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
		jcenter()
		google()
	}
	dependencies {
		classpath 'com.android.tools.build:gradle:3.1.2'
		//classpath 'com.mobidevelop.robovm:robovm-gradle-plugin:2.3.3'
	}
}

Auch unter allprojects/ext fliegt roboVMVersion aus. Wie oben kommt google() zu den Repos unter allprojects/repositories hinzu.

allprojects {
	apply plugin: "eclipse"
	apply plugin: "idea"

	version = '1.0'
	ext {
		appName = "Argh! Earthlings!"
		gdxVersion = '1.9.8'
		//roboVMVersion = '2.3.3'
		box2DLightsVersion = '1.4'
		ashleyVersion = '1.7.0'
		aiVersion = '1.8.0'
	}

	repositories {
		mavenLocal()
		mavenCentral()
		maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
		maven { url "https://oss.sonatype.org/content/repositories/releases/" }
		google()
	}
}

Ab Gradle 4.4 wird die Anweisung compile gegen das Äquivalent implementation ausgetauscht.

project(":desktop") {
	apply plugin: "java"

	dependencies {
		implementation project(":core")
		implementation "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion"
		implementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
		implementation "com.badlogicgames.gdx:gdx-tools:$gdxVersion"
		implementation "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"
	}
}

project(":android") {
	apply plugin: "android"

	configurations { natives }

	dependencies {
		implementation project(":core")
		implementation "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion"
		natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi"
		natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi-v7a"
		natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-arm64-v8a"
		natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86"
		natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86_64"
		implementation "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
		natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-armeabi"
		natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-armeabi-v7a"
		natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-arm64-v8a"
		natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86"
		natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86_64"
	}
}

project(":core") {
	apply plugin: "java"

	dependencies {
		implementation "com.badlogicgames.gdx:gdx:$gdxVersion"
		implementation "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
	}
}

Der Rest bleibt wie gehabt.

tasks.eclipse.doLast {
	delete ".project"
}

Ist das Setup komplett, kann man nun einige Run/Debug Configurations in Android Studio konfigurieren. Folgende Einstellung ist für mich prima:

Configuration: Gradle
Name: Desktop Build and Run Detailed
Gradle Project: ~/projects/libgdx/arghearthlings/desktop
Tasks: run
Arguments: --stacktrace --debug --scan
Before launch: Run Gradle task: 'desktop: build'

Android Studio Run/Debug Configurations

Wenn ich nun die Run-Configuration "Desktop Build and Run Detailed" erhalte ich folgenden Output:

22:35:14: Executing task 'build'...

Executing tasks: [build]

> Configure project :desktop
Gradle now uses separate output directories for each JVM language, but this build assumes a single directory for all classes from a source set. This behaviour has been deprecated and is scheduled to be removed in Gradle 5.0
	at build_clk0ex61op6nh8kq2zgcbgeaf$_run_closure4.doCall(~/projects/libgdx/arghearthlings/desktop/build.gradle:37)
	(Run with --stacktrace to get the full stack trace of this deprecation warning.)

> Task :core:compileJava UP-TO-DATE
> Task :core:processResources NO-SOURCE
> Task :core:classes UP-TO-DATE
> Task :core:jar UP-TO-DATE
> Task :desktop:compileJava UP-TO-DATE
> Task :desktop:processResources NO-SOURCE
> Task :desktop:classes UP-TO-DATE
> Task :desktop:jar UP-TO-DATE
> Task :desktop:assemble UP-TO-DATE
> Task :desktop:compileTestJava NO-SOURCE
> Task :desktop:processTestResources NO-SOURCE
> Task :desktop:testClasses UP-TO-DATE
> Task :desktop:test NO-SOURCE
> Task :desktop:check UP-TO-DATE
> Task :desktop:build UP-TO-DATE

BUILD SUCCESSFUL in 2s
4 actionable tasks: 4 up-to-date
22:35:17: Task execution finished 'build'.

Daneben erhalte ich eine weitere Log-Ausgabe:

22:35:17: Executing task 'run --stacktrace --debug --scan'...

Executing tasks: [run]

22:35:17.356 [INFO] [org.gradle.launcher.daemon.server.exec.LogToClient] The client will now receive all logging from the daemon (pid: 49300). The daemon log file: ~/.gradle/daemon/4.7/daemon-49300.out.log
22:35:17.364 [INFO] [org.gradle.launcher.daemon.server.exec.LogAndCheckHealth] Starting 19th build in daemon [uptime: 1 hrs 18 mins 40.038 secs, performance: 99%]
22:35:17.364 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has started executing the build.
22:35:17.365 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] Executing build with daemon context: DefaultDaemonContext[uid=dd3eadf5-ecdd-47f9-8bdd-4fe562234688,
...
22:35:23.548 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-artifact.bin (~/.gradle/caches/modules-2/metadata-2.56/module-artifact.bin)
22:35:23.549 [DEBUG] [org.gradle.cache.internal.btree.BTreePersistentIndexedCache] Closing cache module-metadata.bin (~/.gradle/caches/modules-2/metadata-2.56/module-metadata.bin)
22:35:23.549 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Releasing lock on artifact cache (~/.gradle/caches/modules-2).
22:35:23.550 [DEBUG] [org.gradle.launcher.daemon.server.exec.ExecuteBuild] The daemon has finished executing the build.
22:35:23: Task execution finished 'run --stacktrace --debug --scan'.

Das Ergebnis für den Desktop-Launch ist das übliche libGDX-Demo-Fenster:

Laufende libGDX-Demo

Optimierung

Der Bau der App (ohne Änderungen) ist bereits mit den teuren Log-Optionen --stacktrace, --denug und --scan schnell, aber verzichtet man auf diese geht der Bau noch schneller von der Hand.