fixed getValue null bug and gradle cleanups

This commit is contained in:
Xilin Jia 2024-03-13 21:39:17 +00:00
parent 8225b6a9bd
commit 0b75b4c542
14 changed files with 227 additions and 259 deletions

1
.gitignore vendored
View File

@ -39,6 +39,7 @@ contributers.py
# View hierarchy captures
captures
# other
.directory
*.odg#
proguard
libs

View File

@ -2,14 +2,13 @@ plugins {
id('com.android.application')
id 'kotlin-android'
id 'kotlin-kapt'
id 'com.google.devtools.ksp'
id('com.github.triplet.play') version '3.8.3' apply false
}
apply from: "../common.gradle"
apply from: "../playFlavor.gradle"
android {
namespace "ac.mdiq.podcini"
lint {
lintOptions {
disable 'ObsoleteLintCustomCheck', 'CheckResult', 'UnusedAttribute', 'BatteryLife', 'InflateParams',
'RestrictedApi', 'TrustAllX509TrustManager', 'ExportedReceiver', 'AllowBackup', 'VectorDrawableCompat',
'StaticFieldLeak', 'UseCompoundDrawables', 'NestedWeights', 'Overdraw', 'UselessParent', 'TextFields',
@ -22,11 +21,25 @@ android {
buildConfig true
}
defaultConfig {
// Version code schema:
minSdk 21
compileSdk 34
targetSdk 34
kotlinOptions {
jvmTarget = '17'
}
vectorDrawables.useSupportLibrary false
vectorDrawables.generatedDensities = []
testApplicationId "ac.mdiq.podcini.tests"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// Version code schema (not used):
// "1.2.3-beta4" -> 1020304
// "1.2.3" -> 1020395
versionCode 3020106
versionName "4.2.3"
versionCode 3020107
versionName "4.2.4"
def commit = ""
try {
@ -65,33 +78,129 @@ android {
keyPassword project.getProperties().getOrDefault("releaseKeyPassword", "password")
}
}
buildTypes {
debug {
applicationIdSuffix ".debug"
resValue "string", "app_name", "Podcini Debug"
resValue "string", "provider_authority", "ac.mdiq.podcini.debug.provider"
}
release {
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard.cfg"
resValue "string", "app_name", "Podcini"
resValue "string", "provider_authority", "ac.mdiq.podcini.provider"
minifyEnabled true
shrinkResources true
signingConfig signingConfigs.releaseConfig
}
}
applicationVariants.all { variant ->
variant.outputs.all { output ->
flavorDimensions += ["market"]
productFlavors {
free {
dimension "market"
}
play {
dimension "market"
}
}
applicationVariants.configureEach { variant ->
variant.outputs.configureEach { output ->
def applicationName = "Podcini"
outputFileName = "${applicationName}_${variant.buildType.name}_${defaultConfig.versionName}.apk"
}
}
packagingOptions {
resources {
excludes += ["META-INF/LICENSE.txt",
"META-INF/NOTICE.txt",
"META-INF/CHANGES",
"META-INF/README.md"]
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
testOptions {
animationsDisabled = true
unitTests {
includeAndroidResources = true
}
}
lint {
disable "GradleDependency"
checkDependencies true
warningsAsErrors true
abortOnError true
checkGeneratedSources = true
}
buildFeatures {
viewBinding true
}
androidResources {
additionalParameters "--no-version-vectors"
}
}
tasks.withType(Test).configureEach {
testLogging {
exceptionFormat "full"
events "skipped", "passed", "failed"
showStandardStreams true
displayGranularity 2
}
}
gradle.projectsEvaluated {
tasks.withType(JavaCompile).tap {
configureEach {
options.compilerArgs << "-Xlint"
}
}
}
apply plugin: 'com.github.spotbugs'
spotbugs {
effort = 'max'
reportLevel = 'medium'
excludeFilter = rootProject.file('config/spotbugs/exclude.xml')
ignoreFailures = true // Handled by printing task
}
gradle.taskGraph.beforeTask { task ->
if (task.name.toLowerCase().contains('spotbugs')) {
task.doLast {
def reportFile = task.project.file("build/reports/spotbugs/playDebug.xml")
if (!reportFile.exists()) return
def slurped = new groovy.xml.XmlSlurper().parse(reportFile)
def foundErrors = false
slurped['BugInstance'].each { bug ->
logger.error "[SpotBugs] ${bug['LongMessage']} [${bug.@'type'}]"
bug['SourceLine'].each { line ->
logger.error "[SpotBugs] ${line['Message']}"
foundErrors = true
}
}
if (foundErrors) {
throw new TaskExecutionException(task,
new Exception("SpotBugs violations were found. See output above for details."))
}
}
}
}
dependencies {
implementation "androidx.core:core-ktx:$coreVersion"
implementation "androidx.core:core-ktx:1.12.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
constraints {
@ -103,83 +212,87 @@ dependencies {
}
}
kapt "androidx.annotation:annotation:$annotationVersion"
ksp "androidx.annotation:annotation:1.7.1"
implementation "androidx.appcompat:appcompat:$appcompatVersion"
implementation "androidx.appcompat:appcompat:1.6.1"
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0'
implementation "androidx.fragment:fragment-ktx:$fragmentVersion"
implementation "androidx.fragment:fragment-ktx:1.6.2"
implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation "androidx.media:media:$mediaVersion"
implementation "androidx.media3:media3-exoplayer:$media3Version"
implementation "androidx.media3:media3-ui:$media3Version"
implementation "androidx.media3:media3-datasource-okhttp:$media3Version"
implementation "androidx.media3:media3-common:$media3Version"
implementation "androidx.palette:palette-ktx:$paletteVersion"
implementation "androidx.preference:preference-ktx:$preferenceVersion"
implementation "androidx.recyclerview:recyclerview:$recyclerViewVersion"
implementation "androidx.viewpager2:viewpager2:$viewPager2Version"
implementation "androidx.work:work-runtime:$workManagerVersion"
implementation "androidx.media:media:1.7.0"
implementation "androidx.media3:media3-exoplayer:1.2.1"
implementation "androidx.media3:media3-ui:1.2.1"
implementation "androidx.media3:media3-datasource-okhttp:1.2.1"
implementation "androidx.media3:media3-common:1.2.1"
implementation "androidx.palette:palette-ktx:1.0.0"
implementation "androidx.preference:preference-ktx:1.2.1"
implementation "androidx.recyclerview:recyclerview:1.3.2"
implementation "androidx.viewpager2:viewpager2:1.1.0-beta02"
implementation "androidx.work:work-runtime:2.9.0"
implementation "androidx.core:core-splashscreen:1.0.1"
implementation 'androidx.documentfile:documentfile:1.0.1'
implementation "com.google.android.material:material:$googleMaterialVersion"
implementation "com.google.android.material:material:1.11.0"
implementation "org.apache.commons:commons-lang3:$commonslangVersion"
implementation "commons-io:commons-io:$commonsioVersion"
implementation "org.jsoup:jsoup:$jsoupVersion"
implementation "org.apache.commons:commons-lang3:3.14.0"
implementation "commons-io:commons-io:2.15.1"
implementation "org.jsoup:jsoup:1.17.2"
implementation "com.github.bumptech.glide:glide:$glideVersion"
implementation "com.github.bumptech.glide:okhttp3-integration:$glideVersion@aar"
kapt "com.github.bumptech.glide:compiler:$glideVersion"
implementation "com.github.bumptech.glide:glide:4.16.0"
implementation "com.github.bumptech.glide:okhttp3-integration:4.16.0@aar"
ksp "com.github.bumptech.glide:ksp:4.16.0"
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
implementation "com.squareup.okhttp3:okhttp-urlconnection:$okhttpVersion"
implementation "com.squareup.okio:okio:$okioVersion"
implementation "org.greenrobot:eventbus:$eventbusVersion"
kapt "org.greenrobot:eventbus-annotation-processor:$eventbusVersion"
implementation "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
implementation "com.squareup.okhttp3:okhttp:4.12.0"
implementation "com.squareup.okhttp3:okhttp-urlconnection:4.12.0"
implementation "com.joanzapata.iconify:android-iconify-fontawesome:$iconifyVersion"
implementation "com.joanzapata.iconify:android-iconify-material:$iconifyVersion"
implementation 'com.leinardi.android:speed-dial:3.2.0'
implementation "com.squareup.okio:okio:3.7.0"
implementation "org.greenrobot:eventbus:3.3.1"
kapt "org.greenrobot:eventbus-annotation-processor:3.3.1"
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
implementation "io.reactivex.rxjava2:rxjava:2.2.21"
implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.2.2"
implementation "com.joanzapata.iconify:android-iconify-material:2.2.2"
implementation 'com.leinardi.android:speed-dial:3.3.0'
implementation 'com.github.ByteHamster:SearchPreference:v2.5.0'
implementation 'com.github.skydoves:balloon:1.5.3'
implementation 'com.github.skydoves:balloon:1.6.4'
implementation 'com.github.xabaras:RecyclerViewSwipeDecorator:1.3'
implementation "com.annimon:stream:$annimonStreamVersion"
implementation "com.annimon:stream:1.2.2"
// Non-free dependencies:
playImplementation 'com.google.android.play:core-ktx:1.8.0'
compileOnly "com.google.android.wearable:wearable:$wearableSupportVersion"
playImplementation 'com.google.android.play:core-ktx:1.8.1'
compileOnly "com.google.android.wearable:wearable:2.9.0"
// this one can not be updated?
androidTestImplementation 'com.nanohttpd:nanohttpd:2.1.1'
androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"
androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion"
androidTestImplementation "androidx.test:runner:$runnerVersion"
androidTestImplementation "androidx.test:rules:$rulesVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:3.5.1"
androidTestImplementation "androidx.test.espresso:espresso-contrib:3.5.1"
androidTestImplementation "androidx.test.espresso:espresso-intents:3.5.1"
androidTestImplementation "androidx.test:runner:1.5.2"
androidTestImplementation "androidx.test:rules:1.5.0"
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation "org.awaitility:awaitility:$awaitilityVersion"
androidTestImplementation "org.awaitility:awaitility:4.2.0"
implementation "com.annimon:stream:$annimonStreamVersion"
implementation "com.annimon:stream:1.2.2"
implementation 'com.github.mfietz:fyydlin:v0.5.0'
// Non-free dependencies:
testImplementation "androidx.test:core:$testCoreVersion"
testImplementation "org.awaitility:awaitility:$awaitilityVersion"
testImplementation "junit:junit:$junitVersion"
testImplementation "androidx.test:core:1.5.0"
testImplementation "org.awaitility:awaitility:4.2.0"
testImplementation "junit:junit:4.13.2"
testImplementation 'org.mockito:mockito-inline:5.2.0'
testImplementation "org.robolectric:robolectric:$robolectricVersion"
testImplementation "org.robolectric:robolectric:4.11.1"
testImplementation 'javax.inject:javax.inject:1'
playImplementation 'com.google.android.gms:play-services-base:17.5.0'
playImplementation 'com.google.android.gms:play-services-base:18.3.0'
freeImplementation 'org.conscrypt:conscrypt-android:2.5.2'
playApi 'androidx.mediarouter:mediarouter:1.6.0'
playApi "com.google.android.support:wearable:$wearableSupportVersion"
playApi 'com.google.android.gms:play-services-cast-framework:21.2.0'
playApi "com.google.android.support:wearable:2.9.0"
playApi 'com.google.android.gms:play-services-cast-framework:21.4.0'
}
kapt {

View File

@ -1,8 +1,8 @@
package de.test.podcini.util.service.download
import ac.mdiq.podcini.BuildConfig
import android.util.Base64
import android.util.Log
import ac.mdiq.podcini.BuildConfig
import fi.iki.elonen.NanoHTTPD
import fi.iki.elonen.NanoHTTPD.Response.IStatus
import org.apache.commons.io.IOUtils

View File

@ -19,17 +19,17 @@ class Atom : Namespace() {
state.items.add(state.currentItem!!)
state.currentItem!!.feed = state.feed
} else if (localName.matches(isText.toRegex())) {
val type = attributes.getValue(TEXT_TYPE)
val type: String? = attributes.getValue(TEXT_TYPE)
return AtomText(localName, this, type)
} else if (LINK == localName) {
val href = attributes.getValue(LINK_HREF)
val rel = attributes.getValue(LINK_REL)
val href: String? = attributes.getValue(LINK_HREF)
val rel: String? = attributes.getValue(LINK_REL)
val parent = state.tagstack.peek()
if (parent.name.matches(isFeedItem.toRegex())) {
if (rel == null || LINK_REL_ALTERNATE == rel) {
state.currentItem!!.link = href
} else if (LINK_REL_ENCLOSURE == rel) {
val strSize = attributes.getValue(LINK_LENGTH)
val strSize: String? = attributes.getValue(LINK_LENGTH)
var size: Long = 0
try {
if (strSize != null) {
@ -38,7 +38,7 @@ class Atom : Namespace() {
} catch (e: NumberFormatException) {
Log.d(TAG, "Length attribute could not be parsed.")
}
val mimeType = getMimeType(attributes.getValue(LINK_TYPE), href)
val mimeType: String? = getMimeType(attributes.getValue(LINK_TYPE), href)
val currItem = state.currentItem
if (isMediaFile(mimeType) && currItem != null && !currItem.hasMedia()) {
@ -49,7 +49,7 @@ class Atom : Namespace() {
}
} else if (parent.name.matches(isFeed.toRegex())) {
if (rel == null || LINK_REL_ALTERNATE == rel) {
val type = attributes.getValue(LINK_TYPE)
val type: String? = attributes.getValue(LINK_TYPE)
/*
* Use as link if a) no type-attribute is given and
* feed-object has no link yet b) type of link is
@ -60,20 +60,20 @@ class Atom : Namespace() {
state.feed.link = href
} else if (LINK_TYPE_ATOM == type || LINK_TYPE_RSS == type) {
// treat as podlove alternate feed
var title = attributes.getValue(LINK_TITLE)
if (title.isEmpty()) {
title = href
var title: String? = attributes.getValue(LINK_TITLE)
if (title.isNullOrEmpty()) {
title = href?:""
}
state.addAlternateFeedUrl(title!!, href)
if (!href.isNullOrEmpty()) state.addAlternateFeedUrl(title, href)
}
} else if (LINK_REL_ARCHIVES == rel) {
val type = attributes.getValue(LINK_TYPE)
val type: String? = attributes.getValue(LINK_TYPE)
if (LINK_TYPE_ATOM == type || LINK_TYPE_RSS == type) {
var title = attributes.getValue(LINK_TITLE)
if (title.isEmpty()) {
title = href
var title: String? = attributes.getValue(LINK_TITLE)
if (title.isNullOrEmpty()) {
title = href?:""
}
state.addAlternateFeedUrl(title!!, href)
if (!href.isNullOrEmpty()) state.addAlternateFeedUrl(title, href)
} else if (LINK_TYPE_HTML == type || LINK_TYPE_XHTML == type) {
//A Link such as to a directory such as iTunes
}
@ -205,7 +205,7 @@ class Atom : Namespace() {
*/
private const val isText = ("$TITLE|$CONTENT|$SUBTITLE|$SUMMARY")
private const val isFeed = FEED + "|" + ac.mdiq.podcini.feed.parser.namespace.Rss20.CHANNEL
private const val isFeedItem = ENTRY + "|" + ac.mdiq.podcini.feed.parser.namespace.Rss20.ITEM
private const val isFeed = FEED + "|" + Rss20.CHANNEL
private const val isFeedItem = ENTRY + "|" + Rss20.ITEM
}
}

View File

@ -10,14 +10,14 @@ class Itunes : Namespace() {
override fun handleElementStart(localName: String, state: ac.mdiq.podcini.feed.parser.HandlerState,
attributes: Attributes): SyndElement {
if (IMAGE == localName) {
val url = attributes.getValue(IMAGE_HREF)
val url: String? = attributes.getValue(IMAGE_HREF)
if (state.currentItem != null) {
state.currentItem!!.imageUrl = url
} else {
// this is the feed image
// prefer to all other images
if (url.isNotEmpty()) {
if (!url.isNullOrEmpty()) {
state.feed.imageUrl = url
}
}

View File

@ -15,9 +15,9 @@ import java.util.concurrent.TimeUnit
class Media : Namespace() {
override fun handleElementStart(localName: String, state: HandlerState, attributes: Attributes): SyndElement {
if (CONTENT == localName) {
val url = attributes.getValue(DOWNLOAD_URL)
val defaultStr = attributes.getValue(DEFAULT)
val medium = attributes.getValue(MEDIUM)
val url: String? = attributes.getValue(DOWNLOAD_URL)
val defaultStr: String? = attributes.getValue(DEFAULT)
val medium: String? = attributes.getValue(MEDIUM)
var validTypeMedia = false
var validTypeImage = false
val isDefault = "true" == defaultStr
@ -44,7 +44,7 @@ class Media : Namespace() {
if (state.currentItem != null && (state.currentItem!!.media == null || isDefault) && url != null && validTypeMedia) {
var size: Long = 0
val sizeStr = attributes.getValue(SIZE)
val sizeStr: String? = attributes.getValue(SIZE)
if (!sizeStr.isNullOrEmpty()) {
try {
size = sizeStr.toLong()
@ -53,7 +53,7 @@ class Media : Namespace() {
}
}
var durationMs = 0
val durationStr = attributes.getValue(DURATION)
val durationStr: String? = attributes.getValue(DURATION)
if (!durationStr.isNullOrEmpty()) {
try {
val duration = durationStr.toLong()
@ -71,7 +71,7 @@ class Media : Namespace() {
state.currentItem!!.imageUrl = url
}
} else if (IMAGE == localName) {
val url = attributes.getValue(IMAGE_URL)
val url: String? = attributes.getValue(IMAGE_URL)
if (url != null) {
if (state.currentItem != null) {
state.currentItem!!.imageUrl = url
@ -82,7 +82,7 @@ class Media : Namespace() {
}
}
} else if (DESCRIPTION == localName) {
val type = attributes.getValue(DESCRIPTION_TYPE)
val type: String? = attributes.getValue(DESCRIPTION_TYPE)
return AtomText(localName, this, type)
}
return SyndElement(localName, this)

View File

@ -9,13 +9,13 @@ class PodcastIndex : Namespace() {
override fun handleElementStart(localName: String, state: HandlerState,
attributes: Attributes): SyndElement {
if (FUNDING == localName) {
val href = attributes.getValue(URL)
val href: String? = attributes.getValue(URL)
val funding = FeedFunding(href, "")
state.currentFunding = funding
state.feed.addPayment(state.currentFunding!!)
} else if (CHAPTERS == localName) {
val href = attributes.getValue(URL)
if (href.isNotEmpty()) {
val href: String? = attributes.getValue(URL)
if (!href.isNullOrEmpty()) {
state.currentItem!!.podcastIndexChapterUrl = href
}
}

View File

@ -22,14 +22,14 @@ class Rss20 : Namespace() {
state.items.add(state.currentItem!!)
state.currentItem!!.feed = state.feed
} else if (ENCLOSURE == localName && ITEM == state.tagstack.peek()?.name) {
val url = attributes.getValue(ENC_URL)
val mimeType = getMimeType(attributes.getValue(ENC_TYPE), url)
val url: String? = attributes.getValue(ENC_URL)
val mimeType: String? = getMimeType(attributes.getValue(ENC_TYPE), url)
val validUrl = url.isNotEmpty()
val validUrl = !url.isNullOrBlank()
if (state.currentItem?.media == null && isMediaFile(mimeType) && validUrl) {
var size: Long = 0
try {
size = attributes.getValue(ENC_LEN).toLong()
size = attributes.getValue(ENC_LEN)?.toLong() ?: 0
if (size < 16384) {
// less than 16kb is suspicious, check manually
size = 0

View File

@ -12,13 +12,13 @@ class SimpleChapters : Namespace() {
if (currentItem != null) {
if (localName == CHAPTERS) {
currentItem.chapters = mutableListOf()
} else if (localName == CHAPTER && attributes.getValue(START).isNotEmpty()) {
} else if (localName == CHAPTER && !attributes.getValue(START).isNullOrEmpty()) {
// if the chapter's START is empty, we don't need to do anything
try {
val start = parseTimeString(attributes.getValue(START))
val title = attributes.getValue(TITLE)
val link = attributes.getValue(HREF)
val imageUrl = attributes.getValue(IMAGE)
val start= parseTimeString(attributes.getValue(START))
val title: String? = attributes.getValue(TITLE)
val link: String? = attributes.getValue(HREF)
val imageUrl: String? = attributes.getValue(IMAGE)
val chapter = Chapter(start, title, link, imageUrl)
currentItem.chapters?.add(chapter)
} catch (e: NumberFormatException) {

View File

@ -13,6 +13,10 @@ buildscript {
}
}
plugins {
id 'com.google.devtools.ksp' version '1.9.22-1.0.17' apply false
}
allprojects {
repositories {
google()
@ -21,48 +25,6 @@ allprojects {
}
}
project.ext {
// AndroidX
annotationVersion = "1.7.1"
appcompatVersion = "1.6.1"
coreVersion = "1.12.0"
fragmentVersion = "1.6.2"
mediaVersion = "1.7.0"
paletteVersion = "1.0.0"
preferenceVersion = "1.2.1"
recyclerViewVersion = "1.3.2"
viewPager2Version = "1.1.0-beta02"
workManagerVersion = "2.9.0"
googleMaterialVersion = "1.11.0"
// Third-party
commonslangVersion = "3.14.0"
commonsioVersion = "2.15.1"
jsoupVersion = "1.17.2"
glideVersion = "4.16.0"
okhttpVersion = "4.12.0"
okioVersion = "3.7.0"
eventbusVersion = "3.3.1"
rxAndroidVersion = "2.1.1"
rxJavaVersion = "2.2.21"
iconifyVersion = "2.2.2"
annimonStreamVersion = "1.2.2"
media3Version = "1.2.1"
// Google Play build
wearableSupportVersion = "2.6.0"
//Tests
awaitilityVersion = "4.2.0"
junitVersion = "4.13.2"
junit5Version = "5.10.1"
robolectricVersion = "4.11.1"
espressoVersion = "3.5.0"
runnerVersion = "1.5.2"
rulesVersion = "1.5.0"
testCoreVersion = "1.5.0"
}
apply plugin: "checkstyle"
checkstyle {
toolVersion '10.3.1'

View File

@ -62,4 +62,10 @@
* removed info button in FeedItemList header
* added items count in FeedItemList header
* fixed bug in FeedItemList when filtered list has no items
* buildConfig is set in build.gradle instead of gradle.properties
* buildConfig is set in build.gradle instead of gradle.properties
## 4.2.4
* fixed the "getValue() can not be null" bug
* enabled ksp for Kotlin builds
* cleaned up build.gradle files

View File

@ -1,109 +0,0 @@
android {
defaultConfig {
minSdk 21
compileSdk 34
targetSdk 34
kotlinOptions {
jvmTarget = '17'
}
vectorDrawables.useSupportLibrary false
vectorDrawables.generatedDensities = []
testApplicationId "ac.mdiq.podcini.tests"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard.cfg"
resValue "string", "app_name", "Podcini"
}
debug {
resValue "string", "app_name", "Podcini Debug"
}
}
packagingOptions {
resources {
excludes += ["META-INF/LICENSE.txt",
"META-INF/NOTICE.txt",
"META-INF/CHANGES",
"META-INF/README.md"]
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
testOptions {
animationsDisabled = true
unitTests {
includeAndroidResources = true
}
}
lint {
disable "GradleDependency"
checkDependencies true
warningsAsErrors true
abortOnError true
checkGeneratedSources = true
}
buildFeatures {
viewBinding true
}
}
tasks.withType(Test).configureEach {
testLogging {
exceptionFormat "full"
events "skipped", "passed", "failed"
showStandardStreams true
displayGranularity 2
}
}
gradle.projectsEvaluated {
tasks.withType(JavaCompile).tap {
configureEach {
options.compilerArgs << "-Xlint"
}
}
}
apply plugin: 'com.github.spotbugs'
spotbugs {
effort = 'max'
reportLevel = 'medium'
excludeFilter = rootProject.file('config/spotbugs/exclude.xml')
ignoreFailures = true // Handled by printing task
}
gradle.taskGraph.beforeTask { task ->
if (task.name.toLowerCase().contains('spotbugs')) {
task.doLast {
def reportFile = task.project.file("build/reports/spotbugs/playDebug.xml")
if (!reportFile.exists()) return
def slurped = new groovy.xml.XmlSlurper().parse(reportFile)
def foundErrors = false
slurped['BugInstance'].each { bug ->
logger.error "[SpotBugs] ${bug['LongMessage']} [${bug.@'type'}]"
bug['SourceLine'].each { line ->
logger.error "[SpotBugs] ${line['Message']}"
foundErrors = true
}
}
if (foundErrors) {
throw new TaskExecutionException(task,
new Exception("SpotBugs violations were found. See output above for details."))
}
}
}
}

View File

@ -0,0 +1,6 @@
Version 4.2.4 brings several changes:
* fixed the "getValue() can not be null" bug
* enabled ksp for Kotlin builds
* cleaned up build.gradle files

View File

@ -1,11 +0,0 @@
android {
flavorDimensions += ["market"]
productFlavors {
free {
dimension "market"
}
play {
dimension "market"
}
}
}