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 } // from common.gradle android { defaultConfig { minSdk 23 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 { exclude 'META-INF/DEPENDENCIES' exclude 'META-INF/LICENSE' exclude 'META-INF/NOTICE' exclude 'META-INF/CHANGES' exclude 'META-INF/README.md' exclude 'META-INF/NOTICE.txt' exclude 'META-INF/LICENSE.txt' exclude 'META-INF/MANIFEST.MF' // 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.")) } } } } // from playFlavor.gradle android { flavorDimensions += ["market"] productFlavors { free { dimension "market" } play { dimension "market" } } } // start of the app build.gradle android { namespace "ac.mdiq.podcini" lintOptions { disable 'ObsoleteLintCustomCheck', 'CheckResult', 'UnusedAttribute', 'BatteryLife', 'InflateParams', 'RestrictedApi', 'TrustAllX509TrustManager', 'ExportedReceiver', 'AllowBackup', 'VectorDrawableCompat', 'StaticFieldLeak', 'UseCompoundDrawables', 'NestedWeights', 'Overdraw', 'UselessParent', 'TextFields', 'AlwaysShowAction', 'Autofill', 'ClickableViewAccessibility', 'ContentDescription', 'KeyboardInaccessibleWidget', 'LabelFor', 'SetTextI18n', 'HardcodedText', 'RelativeOverlap', 'RtlCompat', 'RtlHardcoded', 'MissingMediaBrowserServiceIntentFilter', 'VectorPath', 'InvalidPeriodicWorkRequestInterval', 'NotifyDataSetChanged', 'RtlEnabled' } buildFeatures { buildConfig true } defaultConfig { // Version code schema (not used): // "1.2.3-beta4" -> 1020304 // "1.2.3" -> 1020395 versionCode 3020136 versionName "4.9.5" def commit = "" try { def hashStdOut = new ByteArrayOutputStream() exec { commandLine "git", "rev-parse", "--short", "HEAD" standardOutput = hashStdOut } commit = hashStdOut.toString().trim() } catch (Exception ignore) { } buildConfigField "String", "COMMIT_HASH", ('"' + (commit.isEmpty() ? "Unknown commit" : commit) + '"') if (project.hasProperty("podcastindexApiKey")) { buildConfigField "String", "PODCASTINDEX_API_KEY", '"' + podcastindexApiKey + '"' buildConfigField "String", "PODCASTINDEX_API_SECRET", '"' + podcastindexApiSecret + '"' } else { buildConfigField "String", "PODCASTINDEX_API_KEY", '"QT2RYHSUZ3UC9GDJ5MFY"' buildConfigField "String", "PODCASTINDEX_API_SECRET", '"Zw2NL74ht5aCtx5zFL$#MY$##qdVCX7x37jq95Sz"' } } signingConfigs { releaseConfig { enableV1Signing true enableV2Signing true storeFile file(project.getProperties().getOrDefault("releaseStoreFile", "keystore")) storePassword project.getProperties().getOrDefault("releaseStorePassword", "password") keyAlias project.getProperties().getOrDefault("releaseKeyAlias", "alias") keyPassword project.getProperties().getOrDefault("releaseKeyPassword", "password") } } buildTypes { debug { applicationIdSuffix ".debug" resValue "string", "provider_authority", "ac.mdiq.podcini.debug.provider" } release { resValue "string", "provider_authority", "ac.mdiq.podcini.provider" minifyEnabled true shrinkResources true signingConfig signingConfigs.releaseConfig } } applicationVariants.configureEach { variant -> variant.outputs.configureEach { output -> def applicationName = "Podcini" outputFileName = "${applicationName}_${variant.buildType.name}_${defaultConfig.versionName}.apk" } } androidResources { additionalParameters "--no-version-vectors" } } dependencies { implementation "androidx.core:core-ktx:1.12.0" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" constraints { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version") { because("kotlin-stdlib-jdk7 is now a part of kotlin-stdlib") } implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version") { because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib") } } kapt "androidx.annotation:annotation:1.7.1" implementation "androidx.appcompat:appcompat:1.6.1" implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0' implementation "androidx.fragment:fragment-ktx:1.6.2" implementation 'androidx.gridlayout:gridlayout:1.0.0' implementation "androidx.media:media:1.7.0" implementation "androidx.media3:media3-exoplayer:1.3.1" implementation "androidx.media3:media3-ui:1.3.1" implementation "androidx.media3:media3-datasource-okhttp:1.3.1" implementation "androidx.media3:media3-common:1.3.1" implementation "androidx.media3:media3-session:1.3.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 'androidx.webkit:webkit:1.9.0' implementation "com.google.android.material:material:1.11.0" 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:4.16.0" implementation "com.github.bumptech.glide:okhttp3-integration:4.16.0@aar" kapt "com.github.bumptech.glide:ksp:4.16.0" implementation "com.squareup.okhttp3:okhttp:4.12.0" implementation "com.squareup.okhttp3:okhttp-urlconnection:4.12.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.6.4' implementation 'com.github.xabaras:RecyclerViewSwipeDecorator:1.3' implementation "com.annimon:stream:1.2.2" implementation "net.dankito.readability4j:readability4j:1.0.8" // Non-free dependencies: 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: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:4.2.0" implementation 'com.github.mfietz:fyydlin:v0.5.0' // Non-free dependencies: 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:4.11.1" testImplementation 'javax.inject:javax.inject:1' 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:2.9.0" playApi 'com.google.android.gms:play-services-cast-framework:21.4.0' } kapt { arguments { arg('eventBusIndex', 'ac.mdiq.podcini.ApEventBusIndex') } } if (project.hasProperty("podciniPlayPublisherCredentials")) { apply plugin: 'com.github.triplet.play' play { track.set('alpha') serviceAccountCredentials.set(file(podciniPlayPublisherCredentials)) } } tasks.register('copyLicense', Copy) { from "../LICENSE" into "src/main/assets/" rename { String fileName -> fileName + ".txt" } } preBuild.dependsOn copyLicense