Multiplayer Notification Fix for random Termination (#2024)

* Reworked Notification service to remove Nullpointer crashes due to non-final static variables being null. Instead moved all state to Worker specific architecture. Also switched to Android based localization because core-based one can be unavailable to worker.

* Added missing blanks

* Added more internationalization
Added missing androidX declaration (neccessary for newer Gradle versions)
Updated Gradle for new Android Studio Version

* Optimization

* Removed missing translations error
This commit is contained in:
wrov 2020-02-27 18:35:40 +01:00 committed by GitHub
parent 3ccd457759
commit 9188c7790f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 116 additions and 89 deletions

1
.gitignore vendored
View file

@ -123,7 +123,6 @@ Thumbs.db
!/ios-moe/xcode/*.xcodeproj/xcshareddata !/ios-moe/xcode/*.xcodeproj/xcshareddata
!/ios-moe/xcode/*.xcodeproj/project.pbxproj !/ios-moe/xcode/*.xcodeproj/project.pbxproj
/ios-moe/xcode/native/ /ios-moe/xcode/native/
gradle.properties
SaveFiles/ SaveFiles/
android/android-release.apk android/android-release.apk
android/assets/GameSettings.json android/assets/GameSettings.json

View file

@ -1747,15 +1747,6 @@ Haka War Dance = Haka-Kriegstanz
Rejuvenation = Verjüngung Rejuvenation = Verjüngung
All healing effects doubled = Alle Heilungseffekte verdoppelt All healing effects doubled = Alle Heilungseffekte verdoppelt
# Multiplayer Turn Checker Service # Multiplayer Turn Checker Service
An error has occured = Ein Fehler ist aufgetreten
Multiplayer turn notifier service terminated = Multiplayer Zug Benachrichtigungsdienst wurde beendet
Your friends are waiting on your turn. = Deine Freunde warten auf deinen Zug.
Unciv - It's your turn! = Unciv - Du bist am Zug!
Unciv will inform you when it's your turn in multiplayer. = Unciv wird dich benachrichtigen, wenn du im Multiplayer am Zug bist.
Last online turn check: [lastTimeChecked] = Letzter online Zug Check: [lastTimeChecked]
Checks ca. every [checkPeriod] minute(s) when Internet available. = Prüft etwa alle [checkPeriod] Minute(n) wenn Internet vorhanden.
Configurable in Unciv options menu. = Konfigurierbar im Unciv Optionsmenü.
Unciv multiplayer turn notifier running = Unciv Multiplayer Zug Benachrichtiger läuft.
Multiplayer options = Multiplayer Einstellungen Multiplayer options = Multiplayer Einstellungen
Enable out-of-game turn notifications = Aktiviere Zug Benachrichtigungen außerhalb des Spiels Enable out-of-game turn notifications = Aktiviere Zug Benachrichtigungen außerhalb des Spiels
Time between turn checks out-of-game (in minutes) = Intervall zwischen Zug Prüfungen (in Minuten) Time between turn checks out-of-game (in minutes) = Intervall zwischen Zug Prüfungen (in Minuten)

View file

@ -1743,15 +1743,6 @@ Haka War Dance =
Rejuvenation = Rejuvenation =
All healing effects doubled = All healing effects doubled =
# Multiplayer Turn Checker Service # Multiplayer Turn Checker Service
An error has occured =
Multiplayer turn notifier service terminated =
Your friends are waiting on your turn. =
Unciv - It's your turn! =
Unciv will inform you when it's your turn in multiplayer. =
Last online turn check: [lastTimeChecked] =
Checks ca. every [checkPeriod] minute(s) when Internet available. =
Configurable in Unciv options menu. =
Unciv multiplayer turn notifier running =
Multiplayer options = Multiplayer options =
Enable out-of-game turn notifications = Enable out-of-game turn notifications =
Time between turn checks out-of-game (in minutes) = Time between turn checks out-of-game (in minutes) =

View file

@ -62,6 +62,9 @@ android {
} }
} }
} }
lintOptions {
disable 'MissingTranslation'
}
} }
@ -123,7 +126,7 @@ task run(type: Exec) {
dependencies { dependencies {
implementation 'androidx.core:core:1.2.0' implementation 'androidx.core:core:1.2.0'
implementation "androidx.work:work-runtime-ktx:2.3.1" implementation "androidx.work:work-runtime-ktx:2.3.2"
} }
// sets up the Android Eclipse project, using the old Ant based build. // sets up the Android Eclipse project, using the old Ant based build.

View file

@ -0,0 +1,2 @@
android.useAndroidX=true
android.enableJetifier=true

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">UnCiv</string>
<string name="Notify_YourTurn_Short">Unciv - Du bist am Zug!</string>
<string name="Notify_YourTurn_Long">Deine Freunde warten auf deinen Zug.</string>
<string name="Notify_Error_Short">Ein Fehler ist aufgetreten</string>
<string name="Notify_Error_Long">Multiplayer Zug Benachrichtigungsdienst wurde beendet</string>
<string name="Notify_Persist_Short">Letzter online Zug Check:</string>
<string name="Notify_Persist_Long_P1">Unciv wird dich benachrichtigen, wenn du im Multiplayer am Zug bist.</string>
<string name="Notify_Persist_Long_P2">Prüft etwa alle</string>
<string name="Notify_Persist_Long_P3">Minute(n) wenn Internet vorhanden.</string>
<string name="Notify_Persist_Long_P4">Konfigurierbar im Unciv Optionsmenü.</string>
<string name="Notify_ChannelInfo_Short">Unciv Multiplayer Zugprüfer Ereignis</string>
<string name="Notify_ChannelInfo_Long">Informiert dich, wenn du im Multiplayer am Zug bist.</string>
<string name="Notify_ChannelService_Short">Unciv Multiplayer Zugprüfer Persistenter Status</string>
<string name="Notify_ChannelService_Long">Permanent angezeigte Benachrichtigung, welche dich über die Hintergrundaktivität des Dienstes informiert.</string>
</resources>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">UnCiv</string>
<string name="Notify_YourTurn_Short">Unciv - C\'est à vous !</string>
<string name="Notify_YourTurn_Long">Vos amis attendent votre action.</string>
<string name="Notify_Error_Long">Service de notification du tour multijoueur terminé</string>
<string name="Notify_Error_Short">Une erreur est survenue</string>
<string name="Notify_Persist_Long_P4">Configurable dans le menu des options de Unciv</string>
</resources>

View file

@ -1,4 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name">UnCiv</string> <string name="app_name">UnCiv</string>
<string name="Notify_YourTurn_Short">Unciv - It\'s your turn!</string>
<string name="Notify_YourTurn_Long">Your friends are waiting on your turn.</string>
<string name="Notify_Error_Short">An error has occurred</string>
<string name="Notify_Error_Long">Multiplayer turn notifier service terminated</string>
<string name="Notify_Persist_Short">Last online turn check:</string>
<string name="Notify_Persist_Long_P1">Unciv will inform you when it\'s your turn in multiplayer.</string>
<string name="Notify_Persist_Long_P2">Checks ca. every</string>
<string name="Notify_Persist_Long_P3">minute(s) when Internet available.</string>
<string name="Notify_Persist_Long_P4">Configurable in Unciv options menu.</string>
<string name="Notify_ChannelInfo_Short">Unciv Multiplayer Turn Checker Alert</string>
<string name="Notify_ChannelInfo_Long">Informs you when it\'s your turn in multiplayer.</string>
<string name="Notify_ChannelService_Short">Unciv Multiplayer Turn Checker Persistent Status</string>
<string name="Notify_ChannelService_Long">Shown constantly to inform you about background checking.</string>
</resources> </resources>

View file

@ -10,12 +10,10 @@ import android.os.Build
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationCompat.DEFAULT_VIBRATE import androidx.core.app.NotificationCompat.DEFAULT_VIBRATE
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat.getSystemService
import androidx.work.* import androidx.work.*
import com.badlogic.gdx.backends.android.AndroidApplication import com.badlogic.gdx.backends.android.AndroidApplication
import com.unciv.logic.GameInfo import com.unciv.logic.GameInfo
import com.unciv.models.metadata.GameSettings import com.unciv.models.metadata.GameSettings
import com.unciv.models.translations.tr
import com.unciv.ui.worldscreen.mainmenu.OnlineMultiplayer import com.unciv.ui.worldscreen.mainmenu.OnlineMultiplayer
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -37,16 +35,15 @@ class MultiplayerTurnCheckWorker(appContext: Context, workerParams: WorkerParame
private const val NOTIFICATION_CHANNEL_ID_INFO = "UNCIV_NOTIFICATION_CHANNEL_INFO" private const val NOTIFICATION_CHANNEL_ID_INFO = "UNCIV_NOTIFICATION_CHANNEL_INFO"
private const val NOTIFICATION_CHANNEL_ID_SERVICE = "UNCIV_NOTIFICATION_CHANNEL_SERVICE_02" private const val NOTIFICATION_CHANNEL_ID_SERVICE = "UNCIV_NOTIFICATION_CHANNEL_SERVICE_02"
private const val FAIL_COUNT = "FAIL_COUNT"
private const val GAME_ID = "GAME_ID"
private const val USER_ID = "USER_ID"
private const val CONFIGURED_DELAY = "CONFIGURED_DELAY"
private const val PERSISTENT_NOTIFICATION_ENABLED = "PERSISTENT_NOTIFICATION_ENABLED"
// These fields need to be volatile because they are set by main thread but later accessed by worker thread. fun enqueue(appContext: Context,
// Classes used here need to be primitive or internally synchronized to avoid visibility issues. delayInMinutes: Int, inputData: Data) {
@Volatile private var failCount = 0
@Volatile private var gameId = ""
@Volatile private var userId = ""
@Volatile private var configuredDelay = 5
@Volatile private var persistentNotificationEnabled = true
fun enqueue(appContext: Context, delayInMinutes: Int) {
val constraints = Constraints.Builder() val constraints = Constraints.Builder()
// If no internet is available, worker waits before becoming active. // If no internet is available, worker waits before becoming active.
.setRequiredNetworkType(NetworkType.CONNECTED) .setRequiredNetworkType(NetworkType.CONNECTED)
@ -56,6 +53,7 @@ class MultiplayerTurnCheckWorker(appContext: Context, workerParams: WorkerParame
.setConstraints(constraints) .setConstraints(constraints)
.setInitialDelay(delayInMinutes.toLong(), TimeUnit.MINUTES) .setInitialDelay(delayInMinutes.toLong(), TimeUnit.MINUTES)
.addTag(WORK_TAG) .addTag(WORK_TAG)
.setInputData(inputData)
.build() .build()
WorkManager.getInstance(appContext).enqueue(checkTurnWork) WorkManager.getInstance(appContext).enqueue(checkTurnWork)
@ -70,8 +68,8 @@ class MultiplayerTurnCheckWorker(appContext: Context, workerParams: WorkerParame
*/ */
fun createNotificationChannelInfo(appContext: Context) { fun createNotificationChannelInfo(appContext: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = "Unciv Multiplayer Turn Checker Alert" val name = appContext.resources.getString(R.string.Notify_ChannelInfo_Short)
val descriptionText = "Informs you when it's your turn in multiplayer." val descriptionText = appContext.resources.getString(R.string.Notify_ChannelInfo_Long)
val importance = NotificationManager.IMPORTANCE_HIGH val importance = NotificationManager.IMPORTANCE_HIGH
val mChannel = NotificationChannel(NOTIFICATION_CHANNEL_ID_INFO, name, importance) val mChannel = NotificationChannel(NOTIFICATION_CHANNEL_ID_INFO, name, importance)
mChannel.description = descriptionText mChannel.description = descriptionText
@ -92,8 +90,8 @@ class MultiplayerTurnCheckWorker(appContext: Context, workerParams: WorkerParame
*/ */
fun createNotificationChannelService(appContext: Context) { fun createNotificationChannelService(appContext: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = "Unciv Multiplayer Turn Checker Persistent Status" val name = appContext.resources.getString(R.string.Notify_ChannelService_Short)
val descriptionText = "Shown constantly to inform you about background checking." val descriptionText = appContext.resources.getString(R.string.Notify_ChannelService_Long)
val importance = NotificationManager.IMPORTANCE_MIN val importance = NotificationManager.IMPORTANCE_MIN
val mChannel = NotificationChannel(NOTIFICATION_CHANNEL_ID_SERVICE, name, importance) val mChannel = NotificationChannel(NOTIFICATION_CHANNEL_ID_SERVICE, name, importance)
mChannel.setShowBadge(false) mChannel.setShowBadge(false)
@ -110,29 +108,28 @@ class MultiplayerTurnCheckWorker(appContext: Context, workerParams: WorkerParame
* It is not technically necessary for the Worker, since it is not a Service. * It is not technically necessary for the Worker, since it is not a Service.
*/ */
fun showPersistentNotification(appContext: Context, lastTimeChecked: String, checkPeriod: String) { fun showPersistentNotification(appContext: Context, lastTimeChecked: String, checkPeriod: String) {
if (persistentNotificationEnabled) { val pendingIntent: PendingIntent =
val pendingIntent: PendingIntent = Intent(appContext, AndroidLauncher::class.java).let { notificationIntent ->
Intent(appContext, AndroidLauncher::class.java).let { notificationIntent -> PendingIntent.getActivity(appContext, 0, notificationIntent, 0)
PendingIntent.getActivity(appContext, 0, notificationIntent, 0) }
}
val notification: NotificationCompat.Builder = NotificationCompat.Builder(appContext, NOTIFICATION_CHANNEL_ID_SERVICE) val notification: NotificationCompat.Builder = NotificationCompat.Builder(appContext, NOTIFICATION_CHANNEL_ID_SERVICE)
.setPriority(NotificationManagerCompat.IMPORTANCE_MIN) // it's only a status .setPriority(NotificationManagerCompat.IMPORTANCE_MIN) // it's only a status
.setContentTitle(("Last online turn check: [$lastTimeChecked]").tr()) .setContentTitle(appContext.resources.getString(R.string.Notify_Persist_Short) + " " + lastTimeChecked)
.setStyle(NotificationCompat.BigTextStyle() .setStyle(NotificationCompat.BigTextStyle()
.bigText("Unciv will inform you when it's your turn in multiplayer.".tr() + " " + .bigText(appContext.resources.getString(R.string.Notify_Persist_Long_P1) + " " +
"Checks ca. every [$checkPeriod] minute(s) when Internet available.".tr() appContext.resources.getString(R.string.Notify_Persist_Long_P2) + " " + checkPeriod + " "
+ " " + "Configurable in Unciv options menu.".tr())) + appContext.resources.getString(R.string.Notify_Persist_Long_P3)
.setSmallIcon(R.drawable.uncivicon2) + " " + appContext.resources.getString(R.string.Notify_Persist_Long_P4)))
.setContentIntent(pendingIntent) .setSmallIcon(R.drawable.uncivicon2)
.setCategory(NotificationCompat.CATEGORY_SERVICE) .setContentIntent(pendingIntent)
.setOnlyAlertOnce(true) .setCategory(NotificationCompat.CATEGORY_SERVICE)
.setOngoing(true) .setOnlyAlertOnce(true)
.setShowWhen(false) .setOngoing(true)
.setShowWhen(false)
with(NotificationManagerCompat.from(appContext)) { with(NotificationManagerCompat.from(appContext)) {
notify(NOTIFICATION_ID_INFO, notification.build()) notify(NOTIFICATION_ID_INFO, notification.build())
}
} }
} }
@ -142,11 +139,11 @@ class MultiplayerTurnCheckWorker(appContext: Context, workerParams: WorkerParame
PendingIntent.getActivity(applicationContext, 0, notificationIntent, 0) PendingIntent.getActivity(applicationContext, 0, notificationIntent, 0)
} }
val contentTitle = "Unciv - It's your turn!".tr() val contentTitle = applicationContext.resources.getString(R.string.Notify_YourTurn_Short)
val notification: NotificationCompat.Builder = NotificationCompat.Builder(applicationContext, NOTIFICATION_CHANNEL_ID_INFO) val notification: NotificationCompat.Builder = NotificationCompat.Builder(applicationContext, NOTIFICATION_CHANNEL_ID_INFO)
.setPriority(NotificationManagerCompat.IMPORTANCE_HIGH) // people are waiting! .setPriority(NotificationManagerCompat.IMPORTANCE_HIGH) // people are waiting!
.setContentTitle(contentTitle) .setContentTitle(contentTitle)
.setContentText("Your friends are waiting on your turn.".tr()) .setContentText(applicationContext.resources.getString(R.string.Notify_YourTurn_Long))
.setTicker(contentTitle) .setTicker(contentTitle)
// without at least vibrate, some Android versions don't show a heads-up notification // without at least vibrate, some Android versions don't show a heads-up notification
.setDefaults(DEFAULT_VIBRATE) .setDefaults(DEFAULT_VIBRATE)
@ -166,15 +163,16 @@ class MultiplayerTurnCheckWorker(appContext: Context, workerParams: WorkerParame
// May be useful to remind a player that he forgot to complete his turn. // May be useful to remind a player that he forgot to complete his turn.
notifyUserAboutTurn(applicationContext) notifyUserAboutTurn(applicationContext)
} else { } else {
gameId = gameInfo.gameId val inputData = workDataOf(Pair(FAIL_COUNT, 0), Pair(GAME_ID, gameInfo.gameId),
userId = settings.userId Pair(USER_ID, settings.userId), Pair(CONFIGURED_DELAY, settings.multiplayerTurnCheckerDelayInMinutes),
configuredDelay = settings.multiplayerTurnCheckerDelayInMinutes Pair(PERSISTENT_NOTIFICATION_ENABLED, settings.multiplayerTurnCheckerPersistentNotificationEnabled))
persistentNotificationEnabled = settings.multiplayerTurnCheckerPersistentNotificationEnabled
showPersistentNotification(applicationContext, if (settings.multiplayerTurnCheckerPersistentNotificationEnabled) {
"", settings.multiplayerTurnCheckerDelayInMinutes.toString()) showPersistentNotification(applicationContext,
"", settings.multiplayerTurnCheckerDelayInMinutes.toString())
}
// Initial check always happens after a minute, ignoring delay config. Better user experience this way. // Initial check always happens after a minute, ignoring delay config. Better user experience this way.
enqueue(applicationContext, 1) enqueue(applicationContext, 1, inputData)
} }
} }
@ -205,47 +203,51 @@ class MultiplayerTurnCheckWorker(appContext: Context, workerParams: WorkerParame
override fun doWork(): Result { override fun doWork(): Result {
try { try {
val latestGame = OnlineMultiplayer().tryDownloadGame(gameId) val latestGame = OnlineMultiplayer().tryDownloadGame(inputData.getString(GAME_ID)!!)
if (latestGame.currentPlayerCiv.playerId == userId) { if (latestGame.currentPlayerCiv.playerId == inputData.getString(USER_ID)!!) {
notifyUserAboutTurn(applicationContext) notifyUserAboutTurn(applicationContext)
with(NotificationManagerCompat.from(applicationContext)) { with(NotificationManagerCompat.from(applicationContext)) {
cancel(NOTIFICATION_ID_SERVICE) cancel(NOTIFICATION_ID_SERVICE)
} }
} else { } else {
enqueue(applicationContext, configuredDelay) updatePersistentNotification(inputData)
updatePersistentNotification() // We have to reset the fail counter since no exception appeared
val inputDataFailReset = Data.Builder().putAll(inputData).putInt(FAIL_COUNT, 0).build()
enqueue(applicationContext, inputData.getInt(CONFIGURED_DELAY, 5), inputDataFailReset)
} }
failCount = 0
} catch (ex: Exception) { } catch (ex: Exception) {
if (failCount++ > 3) { val failCount = inputData.getInt(FAIL_COUNT, 0)
if (failCount > 3) {
showErrorNotification() showErrorNotification()
with(NotificationManagerCompat.from(applicationContext)) { with(NotificationManagerCompat.from(applicationContext)) {
cancel(NOTIFICATION_ID_SERVICE) cancel(NOTIFICATION_ID_SERVICE)
} }
failCount = 0 // Otherwise the notification service would be forever stuck in error mode.
return Result.failure() return Result.failure()
} else { } else {
// If check fails, retry in one minute. // If check fails, retry in one minute.
// Makes sense, since checks only happen if Internet is available in principle. // Makes sense, since checks only happen if Internet is available in principle.
// Therefore a failure means either a problem with the GameInfo or with Dropbox. // Therefore a failure means either a problem with the GameInfo or with Dropbox.
enqueue(applicationContext, 1) val inputDataFailIncrease = Data.Builder().putAll(inputData).putInt(FAIL_COUNT, failCount + 1).build()
updatePersistentNotification() enqueue(applicationContext, 1, inputDataFailIncrease)
// Persistent Notification is not updated, because user may think check succeed.
} }
} }
return Result.success() return Result.success()
} }
private fun updatePersistentNotification() { private fun updatePersistentNotification(inputData: Data) {
val cal = GregorianCalendar.getInstance() if (inputData.getBoolean(PERSISTENT_NOTIFICATION_ENABLED, true)) {
val hour = cal.get(GregorianCalendar.HOUR_OF_DAY).toString() val cal = GregorianCalendar.getInstance()
var minute = cal.get(GregorianCalendar.MINUTE).toString() val hour = cal.get(GregorianCalendar.HOUR_OF_DAY).toString()
if (minute.length == 1) { var minute = cal.get(GregorianCalendar.MINUTE).toString()
minute = "0$minute" if (minute.length == 1) {
} minute = "0$minute"
val displayTime = "$hour:$minute" }
val displayTime = "$hour:$minute"
showPersistentNotification(applicationContext, displayTime, showPersistentNotification(applicationContext, displayTime,
configuredDelay.toString()) inputData.getInt(CONFIGURED_DELAY, 5).toString())
}
} }
private fun showErrorNotification() { private fun showErrorNotification() {
@ -256,8 +258,8 @@ class MultiplayerTurnCheckWorker(appContext: Context, workerParams: WorkerParame
val notification: NotificationCompat.Builder = NotificationCompat.Builder(applicationContext, NOTIFICATION_CHANNEL_ID_INFO) val notification: NotificationCompat.Builder = NotificationCompat.Builder(applicationContext, NOTIFICATION_CHANNEL_ID_INFO)
.setPriority(NotificationManagerCompat.IMPORTANCE_DEFAULT) // No direct user action expected .setPriority(NotificationManagerCompat.IMPORTANCE_DEFAULT) // No direct user action expected
.setContentTitle("An error has occured".tr()) .setContentTitle(applicationContext.resources.getString(R.string.Notify_Error_Short))
.setContentText("Multiplayer turn notifier service terminated".tr()) .setContentText(applicationContext.resources.getString(R.string.Notify_Error_Long))
.setSmallIcon(R.drawable.uncivicon2) .setSmallIcon(R.drawable.uncivicon2)
// without at least vibrate, some Android versions don't show a heads-up notification // without at least vibrate, some Android versions don't show a heads-up notification
.setDefaults(DEFAULT_VIBRATE) .setDefaults(DEFAULT_VIBRATE)

View file

@ -1,6 +1,6 @@
buildscript { buildscript {
ext.kotlinVersion = '1.3.50' ext.kotlinVersion = '1.3.61'
repositories { repositories {
// Chinese mirrors for quicker loading for chinese devs - uncomment if you're chinese // Chinese mirrors for quicker loading for chinese devs - uncomment if you're chinese
@ -18,7 +18,7 @@ buildscript {
dependencies { dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath 'de.richsource.gradle.plugins:gwt-gradle-plugin:0.6' classpath 'de.richsource.gradle.plugins:gwt-gradle-plugin:0.6'
classpath 'com.android.tools.build:gradle:3.5.3' classpath 'com.android.tools.build:gradle:3.6.0'
classpath 'com.mobidevelop.robovm:robovm-gradle-plugin:2.3.1' classpath 'com.mobidevelop.robovm:robovm-gradle-plugin:2.3.1'
// This is for wrapping the .jar file into a standalone executable // This is for wrapping the .jar file into a standalone executable

View file

@ -1,6 +1,6 @@
#Sat Aug 24 11:02:13 CST 2019 #Thu Feb 27 10:30:48 CET 2020
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip