apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-parcelize' apply plugin: 'androidx.navigation.safeargs.kotlin' apply plugin: 'jacoco' def environmentExtractor = { File path -> def rawJson = path.text def escapedJson = rawJson.replace("\"", "\\\"").replace("\n", "").replace("\r", "") return "\"${escapedJson}\"" } android { println("Current VERSION_MAJOR: ${VERSION_MAJOR}") println("Current VERSION_MINOR: ${VERSION_MINOR}") println("Current VERSION_PATCH: ${VERSION_PATCH}") println("Current VERSION_BUILD: ${VERSION_BUILD}") compileSdkVersion 29 buildToolsVersion "29.0.3" defaultConfig { applicationId 'de.rki.coronawarnapp' minSdkVersion 23 targetSdkVersion 29 ndkVersion "21.2.6472646" versionCode( VERSION_MAJOR.toInteger() * 1000000 + VERSION_MINOR.toInteger() * 10000 + VERSION_PATCH.toInteger() * 100 + VERSION_BUILD.toInteger() ) println("Used versionCode: $versionCode") versionName "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}" println("Used versionName: $versionName") testInstrumentationRunner "testhelpers.TestApplicationUIRunner" resConfigs "de", "en", "tr", "bg", "pl", "ro" def prodEnvJson = environmentExtractor(file("../prod_environments.json")) buildConfigField "String", "ENVIRONMENT_JSONDATA", prodEnvJson if (project.hasProperty("commit_hash")) { buildConfigField "String", "GIT_COMMIT_SHORT_HASH", "\"$commit_hash\"" } else { buildConfigField "String", "GIT_COMMIT_SHORT_HASH", "\"no commit hash\"" } def devEnvironmentFile = file("../test_environments.json") if (devEnvironmentFile.exists()) { def devEnvJson = environmentExtractor(devEnvironmentFile) buildConfigField "String", "ENVIRONMENT_JSONDATA", devEnvJson } javaCompileOptions { annotationProcessorOptions { arguments += ["room.schemaLocation": "$projectDir/schemas".toString()] } } } def signingPropFile = file("../keystore.properties") if (signingPropFile.canRead()) { Properties signingProps = new Properties() signingProps.load(new FileInputStream(signingPropFile)) signingConfigs { deviceRelease { if (signingProps['deviceRelease.storePath'] != null) { storeFile file(signingProps['deviceRelease.storePath']) keyAlias signingProps['deviceRelease.keyAlias'] storePassword signingProps['deviceRelease.storePassword'] keyPassword signingProps['deviceRelease.keyPassword'] } } deviceForTestersRelease { if (signingProps['deviceForTestersRelease.storePath'] != null) { storeFile file(signingProps['deviceForTestersRelease.storePath']) keyAlias signingProps['deviceForTestersRelease.keyAlias'] storePassword signingProps['deviceForTestersRelease.storePassword'] keyPassword signingProps['deviceForTestersRelease.keyPassword'] } } } } buildTypes { debug { } release { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } flavorDimensions "version" productFlavors { device { dimension "version" resValue "string", "app_name", "Corona-Warn" ext { envTypeDefault = [debug: "INT", release: "PROD"] } if (signingPropFile.canRead()) { signingConfig signingConfigs.deviceRelease } } deviceForTesters { // Contains test fragments dimension "version" resValue "string", "app_name", "CWA TEST" applicationIdSuffix '.test' ext { envTypeDefault = [debug: "INT", release: "WRU-XD"] } if (signingPropFile.canRead()) { signingConfig signingConfigs.deviceForTestersRelease } } } applicationVariants.all { variant -> def flavor = variant.productFlavors[0] def typeName = variant.buildType.name // debug/release variant.buildConfigField "String", "ENVIRONMENT_TYPE_DEFAULT", "\"${flavor.envTypeDefault[typeName]}\"" if (flavor.name == "deviceForTesters") { def adjustedVersionName = "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-RC${VERSION_BUILD}" variant.outputs.each { output -> output.versionNameOverride = adjustedVersionName } println("deviceForTesters adjusted versionName: $adjustedVersionName") } if (flavor.name != "device") { variant.outputs.each { output -> def apkName = "Corona-Warn-App-${output.versionNameOverride}-${flavor.name}-${variant.buildType.name}.apk" println("Override APK Name: $apkName") output.outputFileName = apkName } } } buildFeatures { dataBinding true viewBinding true } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { kotlinOptions { jvmTarget = "1.8" freeCompilerArgs += [ "-Xno-kotlin-nothing-value-exception", "-Xuse-experimental=kotlinx.coroutines.ExperimentalCoroutinesApi", "-Xuse-experimental=kotlinx.coroutines.FlowPreview", "-Xuse-experimental=kotlin.time.ExperimentalTime" ] } } lintOptions { checkAllWarnings = true } testOptions { unitTests.all { useJUnitPlatform() if (project.hasProperty('testFilter')) { List<String> props = project.getProperties().get("testFilter").split("\\s+") props.each { def replaced = it .replaceFirst("^(Corona-Warn-App/src/test.*/java/)(.+)\$", "**/\$2") .replace(".kt", ".class") project.logger.lifecycle("testFilter File: before=$it, after=$replaced") include(replaced) } } } unitTests { includeAndroidResources = true returnDefaultValues = true } // Using orchestration together with mockk on x86 (32bit) emulator images crashes // Leaving this in here as reminder // https://github.com/android/android-test/issues/352 // https://github.com/mockk/mockk/issues/466 // execution 'ANDROIDX_TEST_ORCHESTRATOR' } kapt { useBuildCache true includeCompileClasspath = false } dexOptions { preDexLibraries true } packagingOptions { exclude "**/module-info.class" exclude 'NOTICE' exclude 'LICENSE' exclude 'CODEOWNERS' exclude 'README.md' exclude 'CODE_OF_CONDUCT.md' exclude 'META-INF/AL2.0' exclude 'META-INF/LGPL2.1' } sourceSets { deviceForTesters { kotlin { srcDirs = ['src/deviceForTesters'] } res { srcDirs 'src/deviceForTesters/res', 'src/deviceForTesters/res/navigation' } } device { kotlin { srcDirs = ['src/device'] } } test { java.srcDirs += "$projectDir/src/testShared/java" } androidTest { java.srcDirs += "$projectDir/src/testShared/java" androidTest.assets.srcDirs += files("$projectDir/schemas".toString()) } } } task jacocoTestReportDeviceRelease(type: JacocoReport, dependsOn: 'testDeviceReleaseUnitTest') { group = "Reporting" description = "Generate Jacoco coverage reports for the DeviceRelease build." reports { html.enabled = false xml { enabled = true destination file("$buildDir/reports/jacoco/deviceRelease/jacoco.xml") } } def excludes = [ '**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*', '**/*$$*', ] def classPaths = [ "**/intermediates/classes/deviceRelease/**", "**/intermediates/javac/deviceRelease/*/classes/**", // Android Gradle Plugin 3.2.x support. "**/intermediates/javac/deviceRelease/classes/**", // Android Gradle Plugin 3.4 and 3.5 support. "**/tmp/kotlin-classes/deviceRelease/**" ] def debugTree = fileTree(dir: "$buildDir", includes: classPaths, excludes: excludes) def mainSrc = "src/main/java" getSourceDirectories().from(files([mainSrc])) getClassDirectories().from(files([debugTree])) getExecutionData().from(fileTree(dir: "$buildDir", includes: ["jacoco/testDeviceReleaseUnitTest.exec"])) } configurations.all { resolutionStrategy { force "androidx.test:monitor:1.3.0" } } dependencies { // KOTLIN def coroutineVersion = "1.4.2" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutineVersion" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutineVersion" // ANDROID STANDARD def nav_version = "2.3.3" implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.core:core-ktx:1.3.2' implementation 'com.google.android.material:material:1.2.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" implementation "androidx.navigation:navigation-ui-ktx:$nav_version" implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.preference:preference-ktx:1.1.1' implementation 'androidx.work:work-runtime-ktx:2.5.0' implementation 'androidx.lifecycle:lifecycle-common-java8:2.2.0' implementation 'androidx.lifecycle:lifecycle-process:2.2.0' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0' implementation 'androidx.annotation:annotation:1.1.0' implementation "androidx.recyclerview:recyclerview:1.1.0" implementation "androidx.recyclerview:recyclerview-selection:1.1.0" // DAGGER def dagger_version = "2.31.2" implementation "com.google.dagger:dagger:$dagger_version" implementation "com.google.dagger:dagger-android:$dagger_version" implementation "com.google.dagger:dagger-android-support:$dagger_version" kapt "com.google.dagger:dagger-compiler:$dagger_version" kaptTest "com.google.dagger:dagger-compiler:$dagger_version" kaptAndroidTest "com.google.dagger:dagger-compiler:$dagger_version" kapt "com.google.dagger:dagger-android-processor:$dagger_version" kaptTest "com.google.dagger:dagger-android-processor:$dagger_version" kaptAndroidTest "com.google.dagger:dagger-android-processor:$dagger_version" // QR implementation('com.journeyapps:zxing-android-embedded:4.1.0') { transitive = false } // noinspection GradleDependency - needed for SDK 23 compatibility, in combination with com.journeyapps:zxing-android-embedded:4.1.0 implementation 'com.google.zxing:core:3.3.0' //ENA implementation files('libs/play-services-nearby-exposurenotification-18.0.3.aar') // Testing testImplementation "androidx.arch.core:core-testing:2.1.0" testImplementation('org.robolectric:robolectric:4.4') { exclude group: 'com.google.protobuf' } testImplementation "io.mockk:mockk:1.10.4" testImplementation "com.squareup.okhttp3:mockwebserver:4.9.0" testImplementation 'org.hamcrest:hamcrest-library:2.2' // Testing - jUnit4 testImplementation 'junit:junit:4.13.1' testImplementation "org.junit.vintage:junit-vintage-engine:5.7.0" testImplementation "androidx.test:core-ktx:1.3.0" // Testing - jUnit5 def jupiter_version = "5.7.0" testImplementation "org.junit.jupiter:junit-jupiter-api:$jupiter_version" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$jupiter_version" testImplementation "org.junit.jupiter:junit-jupiter-params:$jupiter_version" def kotest_version = "4.3.2" testImplementation "io.kotest:kotest-runner-junit5:$kotest_version" testImplementation "io.kotest:kotest-assertions-core-jvm:$kotest_version" testImplementation "io.kotest:kotest-property-jvm:$kotest_version" androidTestImplementation "io.kotest:kotest-assertions-core-jvm:$kotest_version" androidTestImplementation "io.kotest:kotest-property-jvm:$kotest_version" testImplementation "io.github.classgraph:classgraph:4.8.90" // Testing - Instrumentation androidTestImplementation 'junit:junit:4.13.1' androidTestImplementation 'androidx.test:runner:1.3.0' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' androidTestImplementation 'androidx.test:rules:1.3.0' androidTestImplementation 'androidx.test.ext:truth:1.3.0' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.work:work-testing:2.5.0' androidTestImplementation "io.mockk:mockk-android:1.10.4" debugImplementation 'androidx.fragment:fragment-testing:1.2.5' debugImplementation 'androidx.test:core-ktx:1.3.0' androidTestImplementation 'tools.fastlane:screengrab:2.0.0' androidTestImplementation "androidx.navigation:navigation-testing:$nav_version" // Play Services implementation 'com.google.android.play:core:1.9.0' implementation 'com.google.android.gms:play-services-base:17.5.0' implementation 'com.google.android.gms:play-services-basement:17.5.0' implementation 'com.google.android.gms:play-services-safetynet:17.0.0' implementation 'com.google.android.gms:play-services-tasks:17.2.0' // HTTP implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation('com.squareup.retrofit2:converter-protobuf:2.9.0') { exclude group: 'com.google.protobuf', module: 'protobuf-java' } implementation("com.squareup.okhttp3:logging-interceptor:4.9.0") implementation 'com.squareup.okhttp3:okhttp:4.9.0' // PERSISTENCE def room_version = "2.2.6" implementation "androidx.sqlite:sqlite-ktx:2.1.0" implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-ktx:$room_version" implementation "androidx.room:room-guava:$room_version" kapt "androidx.room:room-compiler:$room_version" androidTestImplementation "androidx.room:room-testing:$room_version" // UTILS implementation project(":Server-Protocol-Buffer") implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.guava:guava:30.0-android' implementation 'joda-time:joda-time:2.10.6' // SECURITY implementation "androidx.security:security-crypto:1.0.0-rc03" implementation 'net.zetetic:android-database-sqlcipher:4.4.0' implementation 'org.conscrypt:conscrypt-android:2.5.1' // LOGGING implementation 'com.jakewharton.timber:timber:4.7.1@aar' // ANIMATIONS implementation "com.airbnb.android:lottie:3.5.0" }