plugins { id 'com.android.application' id 'com.google.devtools.ksp' // to download blocklists for the headless variant id "de.undercouch.download" version "5.3.0" id 'kotlin-android' id 'com.google.gms.google-services' id 'com.google.firebase.crashlytics' } def keystorePropertiesFile = rootProject.file("keystore.properties") def keystoreProperties = new Properties() // https://github.com/celzero/rethink-app/issues/1032 // https://docs.gradle.org/8.2/userguide/configuration_cache.html#config_cache:requirements:external_processes // get the git version from the command line def gitVersion = providers.exec { commandLine("git", "describe", "--tags", "--always") }.standardOutput.asText.get().toString().trim() // for github builds, the version code is set in the github action via env // for local builds, the version code is set in gradle.properties def getVersionCode = { def code = 0 try { // parseInt throws NumberFormatException if the string does not contain a parsable integer // but "as Integer" is a wrapper class, which silently returns null code = Integer.parseInt(System.getenv("VERSION_CODE")) logger.info("env version code: $code") } catch (NumberFormatException ex) { logger.info("missing env version code: $ex.message") } if (code == 0) { code = project.properties['VERSION_CODE'] as Integer logger.info("project properties version code: $code") } return code } try { keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) } catch (Exception ex) { logger.info("missing keystore prop: $ex.message") keystoreProperties['keyAlias'] = '' keystoreProperties['keyPassword'] = '' keystoreProperties['storeFile'] = '/dev/null' keystoreProperties['storePassword'] = '' } android { compileSdk 34 // https://developer.android.com/studio/build/configure-app-module namespace 'com.celzero.bravedns' defaultConfig { applicationId "com.celzero.bravedns" minSdkVersion 23 targetSdkVersion 34 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } signingConfigs { config { keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storeFile file(keystoreProperties['storeFile']) storePassword keystoreProperties['storePassword'] } // archive.is/wlwD8 alpha { keyAlias System.getenv("ALPHA_KS_ALIAS") // rdnsAlpha keyPassword System.getenv("ALPHA_KS_PASSPHRASE") // https://stackoverflow.com/a/34640602 storeFile file(String.valueOf(System.getenv("ALPHA_KS_FILE"))) // rdnsAlpha.jks in app/ storePassword System.getenv("ALPHA_KS_STORE_PASSPHRASE") } } buildTypes { release { // modified as part of #352, now webview is removed from app, flipping back // the setting to true minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } leakCanary { matchingFallbacks = ['debug'] initWith buildTypes.debug } alpha { // archive.is/y8uCB applicationIdSuffix ".alpha" minifyEnabled true shrinkResources true signingConfig signingConfigs.alpha proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } buildFeatures { viewBinding true buildConfig true } compileOptions { coreLibraryDesugaringEnabled true sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 } packagingOptions { jniLibs { keepDebugSymbols += ['**/*.so'] } } variantFilter { variant -> def releaseChannel = variant.getFlavors().get(0).name def releaseType = variant.getFlavors().get(1).name if (releaseType == 'headless' && releaseChannel != 'fdroid') { variant.setIgnore(true) } } flavorDimensions = ["releaseChannel", "releaseType"] productFlavors { play { dimension "releaseChannel" } fdroid { dimension "releaseChannel" } website { dimension "releaseChannel" } headless { dimension "releaseType" minSdkVersion 31 // stackoverflow.com/a/60560178 // buildConfigField 'string', 'timestamp', '1662384683026' } full { dimension "releaseType" // getPackageInfo().versionCode not returning the correct value (in prod builds) when // value is set in AndroidManifest.xml so setting it here // for buildtype alpha, versionCode is set in env overriding gradle.properties versionCode = getVersionCode() versionName = gitVersion vectorDrawables.useSupportLibrary = true } } lint { abortOnError false } tasks.configureEach { task -> if (task.name.toLowerCase().contains('headless')) { task.dependsOn downloadBlocklists if (task.name.endsWith("BuildConfig")) { task.enabled false } } } } configurations { download { transitive false } } dependencies { implementation 'com.google.firebase:firebase-crashlytics-ktx:19.0.0' androidTestImplementation 'androidx.test:rules:1.5.0' def room_version = "2.6.1" def paging_version = "3.2.1" implementation 'com.google.guava:guava:32.1.1-android' // https://developer.android.com/studio/write/java8-support // included to fix issues with Android 6 support, issue#563 coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4") fullImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.21' fullImplementation 'androidx.appcompat:appcompat:1.6.1' fullImplementation 'androidx.core:core-ktx:1.12.0' implementation 'androidx.preference:preference-ktx:1.2.1' fullImplementation 'androidx.constraintlayout:constraintlayout:2.1.4' fullImplementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' fullImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3' fullImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3' // LiveData implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.7.0' implementation 'com.google.code.gson:gson:2.10.1' implementation "androidx.room:room-runtime:$room_version" ksp "androidx.room:room-compiler:$room_version" implementation "androidx.room:room-ktx:$room_version" implementation "androidx.room:room-paging:$room_version" fullImplementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' fullImplementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0' fullImplementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0' // Pagers Views implementation "androidx.paging:paging-runtime-ktx:$paging_version" fullImplementation 'androidx.fragment:fragment-ktx:1.6.2' implementation 'com.google.android.material:material:1.11.0' fullImplementation 'androidx.viewpager2:viewpager2:1.0.0' fullImplementation 'com.squareup.okhttp3:okhttp:4.12.0' fullImplementation 'com.squareup.okhttp3:okhttp-dnsoverhttps:4.12.0' fullImplementation 'com.squareup.retrofit2:retrofit:2.9.0' fullImplementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.okio:okio-jvm:3.9.0' // Glide fullImplementation('com.github.bumptech.glide:glide:4.16.0') { exclude group: 'glide-parent' } fullImplementation('com.github.bumptech.glide:okhttp3-integration:4.16.0') { exclude group: 'glide-parent' } // Ref: https://stackoverflow.com/a/46638213 kspFull 'com.github.bumptech.glide:compiler:4.16.0' // Swipe button animation fullImplementation 'com.facebook.shimmer:shimmer:0.5.0' // Koin core download 'io.insert-koin:koin-core:3.5.6' implementation 'io.insert-koin:koin-core:3.5.6' // Koin main (Scope, ViewModel ...) download 'io.insert-koin:koin-android:3.5.6' implementation 'io.insert-koin:koin-android:3.5.6' download 'hu.autsoft:krate:2.0.0' implementation 'hu.autsoft:krate:2.0.0' // viewBinding without reflection fullImplementation 'com.github.kirich1409:viewbindingpropertydelegate:1.5.9' fullImplementation 'com.github.kirich1409:viewbindingpropertydelegate-noreflection:1.5.9' // from: https://jitpack.io/#celzero/firestack download 'com.github.celzero:firestack:d92f398622@aar' implementation 'com.github.celzero:firestack:d92f398622@aar' // Work manager implementation('androidx.work:work-runtime-ktx:2.9.0') { modules { module("com.google.guava:listenablefuture") { replacedBy("com.google.guava:guava", "listenablefuture is part of guava") } } } // for handling IP addresses and subnets, both IPv4 and IPv6 // https://seancfoley.github.io/IPAddress/ipaddress.html download 'com.github.seancfoley:ipaddress:5.4.0' implementation 'com.github.seancfoley:ipaddress:5.4.0' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' leakCanaryImplementation 'com.squareup.leakcanary:leakcanary-android:2.14' fullImplementation 'androidx.navigation:navigation-fragment-ktx:2.7.7' fullImplementation 'androidx.navigation:navigation-ui-ktx:2.7.7' fullImplementation 'androidx.biometric:biometric:1.1.0' playImplementation 'com.google.android.play:app-update:2.1.0' playImplementation 'com.google.android.play:app-update-ktx:2.1.0' // for encrypting wireguard configuration files implementation("androidx.security:security-crypto:1.1.0-alpha06") implementation("androidx.security:security-app-authenticator:1.0.0-alpha03") androidTestImplementation("androidx.security:security-app-authenticator:1.0.0-alpha03") // barcode scanner for wireguard fullImplementation 'com.journeyapps:zxing-android-embedded:4.3.0' playImplementation 'com.google.firebase:firebase-crashlytics:19.0.0' playImplementation 'com.google.firebase:firebase-crashlytics-ndk:19.0.0' } // github.com/michel-kraemer/gradle-download-task/issues/131#issuecomment-464476903 tasks.register('downloadBlocklists', Download) { // def assetsDir = new File(projectDir, 'src/main/assets' def assetsDir = android.sourceSets.headless.assets.srcDirs[0] // the filenames are ignored by dl, but acts as a hint for the output // filename for the download-plugin, which does not respect the // content-disposition http header, but rather guesses dest file names // from the final segment of url's path // github.com/michel-kraemer/gradle-download-task/blob/64d1ce32/src/main/java/de/undercouch/gradle/tasks/download/DownloadAction.java#L731 def sources = [ 'https://dl.rethinkdns.com/blocklists/filetag.json', 'https://dl.rethinkdns.com/basicconfig/basicconfig.json', 'https://dl.rethinkdns.com/rank/rd.txt', 'https://dl.rethinkdns.com/trie/td.txt', ] src(sources) dest assetsDir // download files only if last-modified of the local file is less than // the last-modified http header returned by the server onlyIfModified true // or if etag mismatches useETag true // overwrite older files as determined by last-modified, always overwrite true } tasks.register('downloadDependencies', Copy) { dependsOn downloadBlocklists from configurations.download into "libs" }