apply plugin: 'com.android.application' apply plugin: 'com.google.devtools.ksp' apply plugin: 'kotlin-android' apply plugin: 'kotlin-parcelize' def commitSHA1 = 'COMMIT_SHA1' def gitRemote = 'GIT_REMOTE' def envValue(String primary, String legacy = null) { def value = System.getenv(primary) if (value) { return value } return legacy ? System.getenv(legacy) : null } def releaseSigningEnv = [ [primary: 'QSFERA_RELEASE_KEYSTORE', legacy: 'OC_RELEASE_KEYSTORE'], [primary: 'QSFERA_RELEASE_KEYSTORE_PASSWORD', legacy: 'OC_RELEASE_KEYSTORE_PASSWORD'], [primary: 'QSFERA_RELEASE_KEY_ALIAS', legacy: 'OC_RELEASE_KEY_ALIAS'], [primary: 'QSFERA_RELEASE_KEY_PASSWORD', legacy: 'OC_RELEASE_KEY_PASSWORD'], ] def missingReleaseSigningEnvKeys = { releaseSigningEnv.findAll { !envValue(it.primary, it.legacy) } .collect { "${it.primary} (${it.legacy} legacy fallback)" } } dependencies { // Data and domain modules implementation project(':qsferaDomain') implementation project(':qsferaData') // Kotlin implementation libs.kotlin.stdlib implementation libs.kotlinx.coroutines.core // Android X implementation libs.androidx.activity implementation libs.androidx.annotation implementation libs.androidx.appcompat implementation libs.androidx.biometric implementation libs.androidx.constraintlayout implementation libs.androidx.core.ktx implementation libs.androidx.fragment.ktx implementation libs.androidx.legacy.support implementation libs.androidx.lifecycle.common.java8 implementation libs.androidx.lifecycle.extensions implementation libs.androidx.lifecycle.livedata.ktx implementation libs.androidx.lifecycle.runtime.ktx implementation libs.androidx.lifecycle.viewmodel.ktx implementation libs.androidx.preference.ktx implementation libs.androidx.room.runtime implementation libs.androidx.sqlite.ktx implementation libs.androidx.work.runtime.ktx implementation(libs.androidx.browser) { because "CustomTabs required for OAuth2 and OIDC" } implementation(libs.androidx.enterprise.feedback) { because "MDM feedback" } // Image loading implementation libs.coil implementation libs.glide implementation libs.glide.vector // Zooming Android ImageView. implementation libs.photoview // Koin dependency injector implementation libs.koin.androidx.workmanager implementation libs.koin.core // Miscellaneous implementation libs.disklrucache implementation libs.media3.exoplayer implementation libs.media3.ui implementation libs.floatingactionbutton implementation libs.material implementation libs.patternlockview // Markdown Preview implementation libs.bundles.markwon // Timber implementation libs.timber // Tests testImplementation project(":qsferaTestUtil") testImplementation libs.androidx.arch.core.testing testImplementation libs.junit4 testImplementation libs.kotlinx.coroutines.test testImplementation libs.mockk // Instrumented tests androidTestImplementation project(":qsferaTestUtil") androidTestImplementation libs.androidx.annotation androidTestImplementation libs.androidx.arch.core.testing androidTestImplementation libs.androidx.test.core androidTestImplementation libs.androidx.test.ext.junit androidTestImplementation libs.androidx.test.rules androidTestImplementation libs.androidx.test.runner androidTestImplementation libs.androidx.test.uiautomator androidTestImplementation libs.bundles.espresso androidTestImplementation libs.dexopener androidTestImplementation(libs.mockk.android) { exclude module: "objenesis" } // Kaspresso androidTestImplementation libs.kaspresso // Debug debugImplementation libs.androidx.fragment.testing debugImplementation libs.androidx.test.monitor debugImplementation libs.stetho // Detekt detektPlugins libs.detekt.formatting detektPlugins libs.detekt.libraries } configurations.all { resolutionStrategy { force "androidx.test:core:1.6.1" force "androidx.test:core-ktx:1.6.1" force "androidx.test:monitor:1.7.2" force "androidx.test:runner:1.6.2" force "androidx.test:rules:1.6.1" force "androidx.test.espresso:espresso-core:3.6.1" } } android { compileSdkVersion sdkCompileVersion defaultConfig { minSdkVersion sdkMinVersion targetSdkVersion sdkTargetVersion testInstrumentationRunner "eu.qsfera.android.utils.OCTestAndroidJUnitRunner" versionCode = 42 versionName = "1.3.14" buildConfigField "String", gitRemote, "\"" + getGitOriginRemote() + "\"" buildConfigField "String", commitSHA1, "\"" + getLatestGitHash() + "\"" // 2. If the caller (GitHub) provided a specific number, overwrite the versionCode. if (project.hasProperty('versionCode')) { versionCode project.property('versionCode').toInteger() } } compileOptions { sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { jvmTarget = JavaVersion.VERSION_17.toString() } sourceSets { androidTest.java.srcDirs += "src/test-common/java" test.java.srcDirs += "src/test-common/java" androidTest { java.srcDirs += ['src/integrationTest/java'] } } lint { abortOnError false htmlOutput file('../lint-app-report.html') ignoreWarnings false xmlReport false } signingConfigs { release { def releaseKeystore = envValue('QSFERA_RELEASE_KEYSTORE', 'OC_RELEASE_KEYSTORE') if (releaseKeystore) { storeFile file(releaseKeystore) // use an absolute path storePassword envValue('QSFERA_RELEASE_KEYSTORE_PASSWORD', 'OC_RELEASE_KEYSTORE_PASSWORD') keyAlias envValue('QSFERA_RELEASE_KEY_ALIAS', 'OC_RELEASE_KEY_ALIAS') keyPassword envValue('QSFERA_RELEASE_KEY_PASSWORD', 'OC_RELEASE_KEY_PASSWORD') } } } buildTypes { release { if (envValue('QSFERA_RELEASE_KEYSTORE', 'OC_RELEASE_KEYSTORE')) { signingConfig signingConfigs.release } } debug { applicationIdSuffix ".debug" } } flavorDimensions "management" productFlavors { original { dimension "management" } //mdm { // dimension "management" //} qa { dimension "management" applicationIdSuffix ".qa" // replace stuff from setup.xml resValue "string", "app_name", "КуСфера QA" resValue "string", "account_type", "eu.qsfera.qa" resValue "string", "authority", "eu.qsfera.qa" resValue "string", "document_provider_authority", "eu.qsfera.qa.documents" resValue "string", "file_provider_authority", "eu.qsfera.qa.files" resValue "string", "search_suggest_authority", "eu.qsfera.qa.search.users_and_groups" resValue "string", "search_suggest_intent_action", "eu.qsfera.qa.search.users_and_groups.action.SHARE_WITH" } } applicationVariants.all { variant -> def appName = envValue('QSFERA_APP_NAME', 'OC_APP_NAME') setOutputFileName(variant, appName, project) } testOptions { packagingOptions { jniLibs { useLegacyPackaging = true } } unitTests.returnDefaultValues = true animationsDisabled = true } buildFeatures { viewBinding true buildConfig true } packagingOptions { resources.excludes.add("META-INF/*") } namespace "eu.qsfera.android" testNamespace "eu.qsfera.android.test" } gradle.taskGraph.whenReady { taskGraph -> def releaseBuildRequested = taskGraph.allTasks.any { task -> def taskName = task.name.toLowerCase() taskName.endsWith("release") && (taskName.startsWith("assemble") || taskName.startsWith("bundle") || taskName.startsWith("package")) } def missingSigningEnvKeys = missingReleaseSigningEnvKeys() if (releaseBuildRequested && !missingSigningEnvKeys.isEmpty()) { throw new GradleException( "Release builds must be signed. Missing env vars: ${missingSigningEnvKeys.join(', ')}" ) } } // Updates output file names of a given variant to format // [appName].[variant.versionName].[QSFERA_BUILD_NUMBER]-[variant.name].apk. // // QSFERA_BUILD_NUMBER is an environment variable read directly in this method. If undefined, it's not added. // OC_BUILD_NUMBER is still accepted as a legacy fallback. // // @param variant Build variant instance which output file name will be updated. // @param appName String to use as first part of the new file name. May be undefined, the original // project.archivesBaseName property will be used instead. // @param callerProject Caller project. def setOutputFileName(variant, appName, callerProject) { logger.info("Setting new name for output of variant $variant.name") def originalFile = variant.outputs[0].outputFile def originalName = originalFile.name println "originalName is $originalName" def newName = "" if (appName) { newName += appName } else { newName += "QSfera" } def versionName = "$variant.mergedFlavor.versionName" if (variant.mergedFlavor.manifestPlaceholders.versionName != null) { versionName = "$variant.mergedFlavor.manifestPlaceholders.versionName" } if (variant.buildType.manifestPlaceholders.versionName != null) { versionName = "$variant.buildType.manifestPlaceholders.versionName" } newName += "_$versionName" def buildNumber = envValue('QSFERA_BUILD_NUMBER', 'OC_BUILD_NUMBER') if (buildNumber) { newName += "_$buildNumber" } newName += originalName.substring(callerProject.archivesBaseName.length()) println "$variant.name: newName is $newName" variant.outputs.all { outputFileName = newName } } static def getLatestGitHash() { def process = "git rev-parse --short HEAD".execute() return process.text.toString().trim() } static def getGitOriginRemote() { def process = "git remote -v".execute() def values = process.text.toString().trim().split("\\r\\n|\\n|\\r") def found = values.find { it.startsWith("origin") && it.endsWith("(push)") } return found.replace("origin", "").replace("(push)", "").replace(".git", "").trim() } tasks.withType(io.gitlab.arturbosch.detekt.Detekt).configureEach { jvmTarget = "17" }