Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  build.gradle   Sprache: unbekannt

 
plugins {
    id "com.jetbrains.python.envs" version "$python_envs_plugin"
}

if (findProject(":geckoview") != null) {
    buildDir "${topobjdir}/gradle/build/mobile/android/focus-android"
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-parcelize'
apply plugin: 'jacoco'
apply plugin: 'com.google.android.gms.oss-licenses-plugin'

def versionCodeGradle = "$project.rootDir/tools/gradle/versionCode.gradle"
if (findProject(":geckoview") != null) {
    versionCodeGradle = "$project.rootDir/mobile/android/focus-android/tools/gradle/versionCode.gradle"
}
apply from: versionCodeGradle

import com.android.build.api.variant.FilterConfiguration
import groovy.json.JsonOutput
import org.gradle.internal.logging.text.StyledTextOutput.Style
import org.gradle.internal.logging.text.StyledTextOutputFactory
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

import static org.gradle.api.tasks.testing.TestResult.ResultType

android {
    if (project.hasProperty("testBuildType")) {
        // Allowing to configure the test build type via command line flag (./gradlew -PtestBuildType=beta ..)
        // in order to run UI tests against other build variants than debug in automation.
        testBuildType project.property("testBuildType")
    }

    defaultConfig {
        applicationId "org.mozilla"
        minSdkVersion config.minSdkVersion
        compileSdk config.compileSdkVersion
        targetSdkVersion config.targetSdkVersion
        versionCode 11 // This versionCode is "frozen" for local builds. For "release" builds we
                       // override this with a generated versionCode at build time.
        // The versionName is dynamically overridden for all the build variants at build time.
        versionName Config.generateDebugVersionName()
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        testInstrumentationRunnerArguments clearPackageData: 'true'
        // See override in release builds for why it's blank.
        buildConfigField "String", "VCS_HASH", "\"\""

        vectorDrawables.useSupportLibrary = true
    }

    bundle {
        language {
            // Because we have runtime language selection we will keep all strings and languages
            // in the base APKs.
            enableSplit = false
        }
    }

    lint {
        lintConfig file("lint.xml")
        baseline file("lint-baseline.xml")
    }

    // We have a three dimensional build configuration:
    // BUILD TYPE (debug, release) X PRODUCT FLAVOR (focus, klar)

    buildTypes {
        release {
            // We allow disabling optimization by passing `-PdisableOptimization` to gradle. This is used
            // in automation for UI testing non-debug builds.
            shrinkResources !project.hasProperty("disableOptimization")
            minifyEnabled !project.hasProperty("disableOptimization")
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            matchingFallbacks = ['release']

            if (gradle.ext.vcsHashFileContent) {
                buildConfigField "String", "VCS_HASH", "\"hg-${gradle.ext.vcsHashFileContent}\""
            } else {
                buildConfigField "String", "VCS_HASH", "\"${Config.vcsHash}\""
            }

            if (gradle.hasProperty("localProperties.autosignReleaseWithDebugKey")) {
                println ("All builds will be automatically signed with the debug key")
                signingConfig signingConfigs.debug
            }

            if (gradle.hasProperty("localProperties.debuggable")) {
                println ("All builds will be debuggable")
                debuggable true
            }
        }
        debug {
            applicationIdSuffix ".debug"
            matchingFallbacks = ['debug']
        }
        beta {
            initWith release
            applicationIdSuffix ".beta"
            // This is used when the user selects text in other third-party apps. See https://github.com/mozilla-mobile/focus-android/issues/6478
            manifestPlaceholders = [textSelectionSearchAction: "@string/text_selection_search_action_focus_beta"]
        }
        nightly {
            initWith release
            applicationIdSuffix ".nightly"
            // This is used when the user selects text in other third-party apps. See https://github.com/mozilla-mobile/focus-android/issues/6478
            manifestPlaceholders = [textSelectionSearchAction: "@string/text_selection_search_action_focus_nightly"]
        }
    }
    testOptions {
        execution 'ANDROIDX_TEST_ORCHESTRATOR'
        animationsDisabled = true
        unitTests {
            includeAndroidResources = true
        }
    }

    buildFeatures {
        compose true
        viewBinding true
        buildConfig true
    }

    composeOptions {
        kotlinCompilerExtensionVersion = Versions.compose_compiler
    }

    flavorDimensions.add("product")

    productFlavors {
        // In most countries we are Firefox Focus - but in some we need to be Firefox Klar
        focus {
            dimension "product"

            applicationIdSuffix ".focus"

            // This is used when the user selects text in other third-party apps. See https://github.com/mozilla-mobile/focus-android/issues/6478
            manifestPlaceholders = [textSelectionSearchAction: "@string/text_selection_search_action_focus"]
        }
        klar {
            dimension "product"

            applicationIdSuffix ".klar"

            // This is used when the user selects text in other third-party apps. See https://github.com/mozilla-mobile/focus-android/issues/6478
            manifestPlaceholders = [textSelectionSearchAction: "@string/text_selection_search_action_klar"]
        }
    }

    splits {
        abi {
            enable true

            reset()

            include "x86", "armeabi-v7a", "arm64-v8a", "x86_64"
        }
    }

    sourceSets {
        test {
            resources {
                // Make the default asset folder available as test resource folder. Robolectric seems
                // to fail to read assets for our setup. With this we can just read the files directly
                // and do not need to rely on Robolectric.
                srcDir "${projectDir}/src/main/assets/"
            }
        }

        // Release
        focusRelease.root = 'src/focusRelease'
        klarRelease.root = 'src/klarRelease'

        // Debug
        focusDebug.root = 'src/focusDebug'
        klarDebug.root = 'src/klarDebug'

        // Nightly
        focusNightly.root = 'src/focusNightly'
        klarNightly.root = 'src/klarNightly'
    }
    packagingOptions {
        resources {
            pickFirsts += ['META-INF/atomicfu.kotlin_module', 'META-INF/proguard/coroutines.pro']
        }
        jniLibs {
            useLegacyPackaging true
        }
    }

    namespace 'org.mozilla.focus'
}

tasks.withType(KotlinCompile).configureEach {
    kotlinOptions.allWarningsAsErrors = true
    kotlinOptions.freeCompilerArgs += [
            "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
            "-opt-in=kotlin.RequiresOptIn",
            "-Xjvm-default=all"
    ]
}

// -------------------------------------------------------------------------------------------------
// Generate Kotlin code for the Focus Glean metrics.
// -------------------------------------------------------------------------------------------------
ext {
    // Enable expiration by major version.
    gleanExpireByVersion = 1
    gleanNamespace = "mozilla.telemetry.glean"
    gleanPythonEnvDir = gradle.mozconfig.substs.GRADLE_GLEAN_PARSER_VENV
}
apply plugin: "org.mozilla.telemetry.glean-gradle-plugin"
apply plugin: "org.mozilla.appservices.nimbus-gradle-plugin"

nimbus {
    // The path to the Nimbus feature manifest file
    manifestFile = "nimbus.fml.yaml"
    // Map from the variant name to the channel as experimenter and nimbus understand it.
    // If nimbus's channels were accurately set up well for this project, then this
    // shouldn't be needed.
    channels = [
            focusDebug: "debug",
            focusNightly: "nightly",
            focusBeta: "beta",
            focusRelease: "release",
            klarDebug: "debug",
            klarNightly: "nightly",
            klarBeta: "beta",
            klarRelease: "release",
    ]
    // This is generated by the FML and should be checked into git.
    // It will be fetched by Experimenter (the Nimbus experiment website)
    // and used to inform experiment configuration.
    experimenterManifest = ".experimenter.yaml"
}

dependencies {
    implementation ComponentsDependencies.androidx_activity
    implementation ComponentsDependencies.androidx_appcompat
    implementation ComponentsDependencies.androidx_browser
    implementation ComponentsDependencies.androidx_cardview
    implementation ComponentsDependencies.androidx_collection

    implementation platform(ComponentsDependencies.androidx_compose_bom)
    androidTestImplementation platform(ComponentsDependencies.androidx_compose_bom)
    implementation ComponentsDependencies.androidx_compose_foundation
    implementation ComponentsDependencies.androidx_compose_material
    implementation ComponentsDependencies.androidx_compose_material_icons
    implementation ComponentsDependencies.androidx_compose_runtime_livedata
    implementation ComponentsDependencies.androidx_compose_ui
    implementation ComponentsDependencies.androidx_compose_ui_tooling

    implementation ComponentsDependencies.androidx_constraintlayout
    implementation ComponentsDependencies.androidx_constraintlayout_compose
    implementation ComponentsDependencies.androidx_core_ktx
    implementation ComponentsDependencies.androidx_core_splashscreen
    implementation ComponentsDependencies.androidx_datastore_preferences
    implementation ComponentsDependencies.androidx_fragment
    implementation ComponentsDependencies.androidx_lifecycle_process
    implementation ComponentsDependencies.androidx_lifecycle_viewmodel
    implementation ComponentsDependencies.androidx_palette
    implementation ComponentsDependencies.androidx_preferences
    implementation ComponentsDependencies.androidx_recyclerview
    implementation ComponentsDependencies.androidx_savedstate
    implementation ComponentsDependencies.androidx_transition
    implementation ComponentsDependencies.androidx_work_runtime

    // Required for in-app reviews
    implementation ComponentsDependencies.play_review
    implementation ComponentsDependencies.play_review_ktx

    implementation ComponentsDependencies.google_material

    implementation ComponentsDependencies.thirdparty_sentry

    implementation project(':browser-engine-gecko')
    implementation project(':browser-domains')
    implementation project(':browser-errorpages')
    implementation project(':browser-icons')
    implementation project(':browser-menu')
    implementation project(':browser-state')
    implementation project(':browser-toolbar')

    implementation project(':concept-awesomebar')
    implementation project(':concept-engine')
    implementation project(':concept-fetch')
    implementation project(':concept-menu')

    implementation project(':compose-awesomebar')

    implementation project(':feature-awesomebar')
    implementation project(':feature-app-links')
    implementation project(':feature-customtabs')
    implementation project(':feature-contextmenu')
    implementation project(':feature-downloads')
    implementation project(':feature-findinpage')
    implementation project(':feature-intent')
    implementation project(':feature-prompts')
    implementation project(':feature-session')
    implementation project(':feature-search')
    implementation project(':feature-tabs')
    implementation project(':feature-toolbar')
    implementation project(':feature-top-sites')
    implementation project(':feature-sitepermissions')
    implementation project(':lib-crash')
    implementation project(':lib-crash-sentry')
    implementation project(':lib-state')
    implementation project(':feature-media')
    implementation project(':lib-auth')
    implementation project(':lib-publicsuffixlist')

    implementation project(':service-location')
    implementation project(':service-nimbus')

    implementation project(':support-ktx')
    implementation project(':support-utils')
    implementation project(':support-rusthttp')
    implementation project(':support-rustlog')
    implementation project(':support-license')

    implementation project(':ui-autocomplete')
    implementation project(':ui-colors')
    implementation project(':ui-icons')
    implementation project(':ui-tabcounter')
    implementation project(':ui-widgets')
    implementation project(':feature-webcompat')
    implementation project(':feature-webcompat-reporter')
    implementation project(':support-webextensions')
    implementation project(':support-locale')
    implementation project(':compose-cfr')

    implementation project(":service-glean")
    implementation ComponentsDependencies.mozilla_glean, {
        exclude group: 'org.mozilla.telemetry', module: 'glean-native'
    }

    implementation ComponentsDependencies.kotlin_coroutines
    debugImplementation ComponentsDependencies.leakcanary

    focusImplementation FocusDependencies.adjust
    focusImplementation FocusDependencies.install_referrer // Required by Adjust

    testImplementation "org.mozilla.telemetry:glean-native-forUnitTests:${project.ext.glean_version}"

    testImplementation ComponentsDependencies.junit_api
    testImplementation ComponentsDependencies.junit_params
    testRuntimeOnly ComponentsDependencies.junit_engine

    testImplementation ComponentsDependencies.testing_robolectric
    testImplementation ComponentsDependencies.testing_mockito
    testImplementation ComponentsDependencies.testing_coroutines
    testImplementation ComponentsDependencies.androidx_work_testing
    testImplementation ComponentsDependencies.androidx_arch_core_testing
    testImplementation project(':support-test')
    testImplementation project(':support-test-libstate')

    androidTestImplementation ComponentsDependencies.testing_mockwebserver
    testImplementation ComponentsDependencies.testing_mockwebserver
    testImplementation project(':lib-fetch-okhttp')

    androidTestImplementation ComponentsDependencies.testing_fastlane
    androidTestImplementation ComponentsDependencies.testing_falcon

    testImplementation ComponentsDependencies.androidx_test_core
    testImplementation ComponentsDependencies.androidx_test_runner
    testImplementation ComponentsDependencies.androidx_test_rules

    androidTestImplementation ComponentsDependencies.androidx_espresso_core
    androidTestImplementation ComponentsDependencies.androidx_espresso_idling_resource
    androidTestImplementation ComponentsDependencies.androidx_espresso_intents
    androidTestImplementation ComponentsDependencies.androidx_espresso_web
    androidTestImplementation ComponentsDependencies.androidx_test_core
    androidTestImplementation ComponentsDependencies.androidx_test_junit
    androidTestImplementation ComponentsDependencies.androidx_test_monitor
    androidTestImplementation ComponentsDependencies.androidx_test_runner
    androidTestImplementation ComponentsDependencies.androidx_test_uiautomator
    androidTestUtil ComponentsDependencies.androidx_test_orchestrator

    lintChecks project(':tooling-lint')
}
// -------------------------------------------------------------------------------------------------
//  Dynamically set versionCode (See tools/build/versionCode.gradle
// -------------------------------------------------------------------------------------------------

android.applicationVariants.configureEach { variant ->
    def buildType = variant.buildType.name

    println("----------------------------------------------")
    println("Variant name:      " + variant.name)
    println("Application ID:    " + [variant.applicationId, variant.buildType.applicationIdSuffix].findAll().join())
    println("Build type:        " + variant.buildType.name)
    println("Flavor:            " + variant.flavorName)

    if (buildType == "release" || buildType == "nightly" || buildType == "beta") {
        def baseVersionCode = generatedVersionCode
        def versionName = buildType == "nightly" ?
                "${Config.nightlyVersionName(project)}" :
                "${Config.releaseVersionName(project)}"
        println("versionName override: $versionName")

        // The Google Play Store does not allow multiple APKs for the same app that all have the
        // same version code. Therefore we need to have different version codes for our ARM and x86
        // builds. See https://developer.android.com/studio/publish/versioning

        // Our generated version code now has a length of 9 (See tools/gradle/versionCode.gradle).
        // Our x86 builds need a higher version code to avoid installing ARM builds on an x86 device
        // with ARM compatibility mode.

        // AAB builds need a version code that is distinct from any APK builds. Since AAB and APK
        // builds may run in parallel, AAB and APK version codes might be based on the same
        // (minute granularity) time of day. To avoid conflicts, we ensure the minute portion
        // of the version code is even for APKs and odd for AABs.

        variant.outputs.each { output ->
            def abi = output.getFilter(FilterConfiguration.FilterType.ABI.name())
            def aab = project.hasProperty("aab")
            // We use the same version code generator, that we inherited from Fennec, across all channels - even on
            // channels that never shipped a Fennec build.

            // ensure baseVersionCode is an even number
            if (baseVersionCode % 2) {
                baseVersionCode = baseVersionCode + 1
            }

            def versionCodeOverride = baseVersionCode

            if (aab) {
                // AAB version code is odd
                versionCodeOverride = versionCodeOverride + 1
                println("versionCode for AAB = $versionCodeOverride")
            } else {
                if (abi == "x86_64") {
                    versionCodeOverride = versionCodeOverride + 6
                } else if (abi == "x86") {
                    versionCodeOverride = versionCodeOverride + 4
                } else if (abi == "arm64-v8a") {
                    versionCodeOverride = versionCodeOverride + 2
                } else if (abi == "armeabi-v7a") {
                    versionCodeOverride = versionCodeOverride + 0
                } else {
                    throw new RuntimeException("Unknown ABI: " + abi)
                }
                println("versionCode for $abi = $versionCodeOverride")
            }

            if (versionName != null) {
                output.versionNameOverride = versionName
            }
            output.versionCodeOverride = versionCodeOverride

        }

    }
}

// -------------------------------------------------------------------------------------------------
// MLS: Read token from local file if it exists (Only release builds)
// -------------------------------------------------------------------------------------------------

android.applicationVariants.configureEach {
    print("MLS token: ")
    try {
        def token = new File("${rootDir}/.mls_token").text.trim()
        buildConfigField 'String', 'MLS_TOKEN', '"' + token + '"'
        println "(Added from .mls_token file)"
    } catch (FileNotFoundException ignored) {
        buildConfigField 'String', 'MLS_TOKEN', '""'
        println("X_X")
    }
}

// -------------------------------------------------------------------------------------------------
// Adjust: Read token from local file if it exists (Only release builds)
// -------------------------------------------------------------------------------------------------

android.applicationVariants.configureEach { variant ->
    def variantName = variant.getName()

    print("Adjust token: ")

    if (variantName.contains("Release") && variantName.contains("focus")) {
        try {
            def token = new File("${rootDir}/.adjust_token").text.trim()
            buildConfigField 'String', 'ADJUST_TOKEN', '"' + token + '"'
            println "(Added from .adjust_token file)"
        } catch (FileNotFoundException ignored) {
            if (gradle.hasProperty("localProperties.autosignReleaseWithDebugKey")) {
                buildConfigField 'String', 'ADJUST_TOKEN', '"fake"'
                println("fake - only for local development")
            } else {
                buildConfigField 'String', 'ADJUST_TOKEN', 'null'
                println("X_X")
            }
        }
    } else {
        buildConfigField 'String', 'ADJUST_TOKEN', 'null'
        println("--")
    }
}

// -------------------------------------------------------------------------------------------------
// Sentry: Read token from local file if it exists (Only release builds)
// -------------------------------------------------------------------------------------------------

android.applicationVariants.configureEach {
    print("Sentry token: ")
    try {
        def token = new File("${rootDir}/.sentry_token").text.trim()
        buildConfigField 'String', 'SENTRY_TOKEN', '"' + token + '"'
        println "(Added from .sentry_token file)"
    } catch (FileNotFoundException ignored) {
        buildConfigField 'String', 'SENTRY_TOKEN', '""'
        println("X_X")
    }
}

// -------------------------------------------------------------------------------------------------
// L10N: Generate list of locales
// Focus provides its own (Android independent) locale switcher. That switcher requires a list
// of locale codes. We generate that list here to avoid having to manually maintain a list of locales:
// -------------------------------------------------------------------------------------------------

def getEnabledLocales() {
    def resDir = file('src/main/res')

    def potentialLanguageDirs = resDir.listFiles(new FilenameFilter() {
        @Override
        boolean accept(File dir, String name) {
            return name.startsWith("values-")
        }
    })

    def langs = potentialLanguageDirs.findAll {
        // Only select locales where strings.xml exists
        // Some locales might only contain e.g. sumo URLS in urls.xml, and should be skipped (see es vs es-ES/es-MX/etc)
        return  file(new File(it, "strings.xml")).exists()
    } .collect {
        // And reduce down to actual values-* names
        return it.name
    } .collect {
        return it.substring("values-".length())
    } .collect {
        if (it.length() > 3 && it.contains("-r")) {
            // Android resource dirs add an "r" prefix to the region - we need to strip that for java usage
            // Add 1 to have the index of the r, without the dash
            def regionPrefixPosition = it.indexOf("-r") + 1

            return it.substring(0, regionPrefixPosition) + it.substring(regionPrefixPosition + 1)
        } else {
            return it
        }
    }.collect {
        return '"' + it + '"'
    }

    // en-US is the default language (in "values") and therefore needs to be added separately
    langs << "\"en-US\""

    return langs.sort { it }
}

// -------------------------------------------------------------------------------------------------
// Nimbus: Read endpoint from local.properties of a local file if it exists
// -------------------------------------------------------------------------------------------------

print("Nimbus endpoint: ")
android.applicationVariants.configureEach { variant ->
    def variantName = variant.getName()

    if (!variantName.contains("Debug")) {
        try {
            def url = new File("${rootDir}/.nimbus").text.trim()
            buildConfigField 'String', 'NIMBUS_ENDPOINT', '"' + url + '"'
            println "(Added from .nimbus file)"
        } catch (FileNotFoundException ignored) {
            buildConfigField 'String', 'NIMBUS_ENDPOINT', 'null'
            println("X_X")
        }
    } else if (gradle.hasProperty("localProperties.nimbus.remote-settings.url")) {
        def url = gradle.getProperty("localProperties.nimbus.remote-settings.url")
        buildConfigField 'String', 'NIMBUS_ENDPOINT', '"' + url + '"'
        println "(Added from local.properties file)"
    } else {
        buildConfigField 'String', 'NIMBUS_ENDPOINT', 'null'
        println("--")
    }
}

def generatedLocaleListDir = 'src/main/java/org/mozilla/focus/generated'
def generatedLocaleListFilename = 'LocalesList.kt'

tasks.register('generateLocaleList') {
    doLast {
        def dir = file(generatedLocaleListDir)
        dir.mkdir()
        def localeList = file(new File(dir, generatedLocaleListFilename))

        localeList.delete()
        localeList.createNewFile()
        localeList << "package org.mozilla.focus.generated" << "\n" << "\n"
        localeList << "import java.util.Collections" << "\n"
        localeList << "\n"
        localeList << "/**"
        localeList << "\n"
        localeList << " * Provides a list of bundled locales based on the language files in the res folder."
        localeList << "\n"
        localeList << " */"
        localeList << "\n"
        localeList << "object LocalesList {" << "\n"
        localeList << "    " << "val BUNDLED_LOCALES: List<String> = Collections.unmodifiableList("
        localeList << "\n"
        localeList << "        " << "listOf("
        localeList << "\n"
        localeList << "            "
        localeList << getEnabledLocales().join(",\n" + "            ")
        localeList << ",\n"
        localeList << "        )," << "\n"
        localeList << "    )" << "\n"
        localeList << "}" << "\n"
    }
}

tasks.configureEach { task ->
    if (name.contains("compile")) {
        task.dependsOn generateLocaleList
    }
}

clean.doLast {
    file(generatedLocaleListDir).deleteDir()
}

if (project.hasProperty("coverage")) {
    tasks.withType(Test).configureEach {
        jacoco.includeNoLocationClasses = true
        jacoco.excludes = ['jdk.internal.*']
    }

    android.applicationVariants.configureEach { variant ->
        tasks.register("jacoco${variant.name.capitalize()}TestReport", JacocoReport) {

            dependsOn(["test${variant.name.capitalize()}UnitTest"])
            reports {
                html.required = true
                xml.required = true
            }

            def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*',
                              '**/*Test*.*', 'android/**/*.*', '**/*$[0-9].*']
            def kotlinTree = fileTree(dir: "$project.layout.buildDirectory/tmp/kotlin-classes/${variant.name}", excludes: fileFilter)
            def javaTree = fileTree(dir: "$project.layout.buildDirectory/intermediates/classes/${variant.flavorName}/${variant.buildType.name}",
                    excludes: fileFilter)
            def mainSrc = "$project.projectDir/src/main/java"
            sourceDirectories.setFrom(files([mainSrc]))
            classDirectories.setFrom(files([kotlinTree, javaTree]))
            executionData.setFrom(fileTree(dir: project.layout.buildDirectory, includes: [
                    "jacoco/test${variant.name.capitalize()}UnitTest.exec", 'outputs/code-coverage/connected/*coverage.ec'
            ]))
        }
    }

    android {
        buildTypes {
            debug {
                testCoverageEnabled true
                applicationIdSuffix ".coverage"
            }
        }
    }
}

// -------------------------------------------------------------------------------------------------
// Task for printing APK information for the requested variant
// Taskgraph Usage: "./gradlew printVariants
// -------------------------------------------------------------------------------------------------
tasks.register('printVariants') {
    doLast {
        def variants = android.applicationVariants.collect { variant -> [
            apks: variant.outputs.collect { output -> [
                abi: output.getFilter(FilterConfiguration.FilterType.ABI.name()),
                fileName: output.outputFile.name
            ]},
            build_type: variant.buildType.name,
            name: variant.name,
        ]}
        // AndroidTest is a special case not included above
        variants.add([
            apks: [[
                abi: 'noarch',
                fileName: 'app-debug-androidTest.apk',
            ]],
            build_type: 'androidTest',
            name: 'androidTest',
        ])
        println 'variants: ' + JsonOutput.toJson(variants)
    }
}

afterEvaluate {

    // Format test output. Copied from Fenix, which was ported from AC #2401
    tasks.withType(Test).configureEach {
        systemProperty "robolectric.logging", "stdout"
        systemProperty "logging.test-mode", "true"

        testLogging.events = []

        def out = services.get(StyledTextOutputFactory).create("tests")

        beforeSuite { descriptor ->
            if (descriptor.getClassName() != null) {
                out.style(Style.Header).println("\nSUITE: " + descriptor.getClassName())
            }
        }

        beforeTest { descriptor ->
            out.style(Style.Description).println("  TEST: " + descriptor.getName())
        }

        onOutput { descriptor, event ->
            logger.lifecycle("    " + event.message.trim())
        }

        afterTest { descriptor, result ->
            switch (result.getResultType()) {
                case ResultType.SUCCESS:
                    out.style(Style.Success).println("  SUCCESS")
                    break

                case ResultType.FAILURE:
                    def testId = descriptor.getClassName() + "." + descriptor.getName()
                    out.style(Style.Failure).println("  TEST-UNEXPECTED-FAIL | " + testId + " | " + result.getException())
                    break

                case ResultType.SKIPPED:
                    out.style(Style.Info).println("  SKIPPED")
                    break
            }
            logger.lifecycle("")
        }
    }
}

[ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge