Подтвердить что ты не робот

Android Gradle: динамическое изменение имени версии во время сборки

Я пытаюсь подражать плагину релиза Maven в Android с помощью настраиваемой версии gradle -release плагин: https://github.com/townsfolk/gradle-release

Интересными шагами являются:

  • Проверить незафиксированные изменения
  • Код шага версии и удалить -SNAPSHOT суффикс от имени версии
  • Построить
  • Название версии шага и добавьте -SNAPSHOT суффикс для следующей версии разработки

Однако сгенерированный APK всегда имеет предыдущие версии (то есть 1.0.0-SNAPSHOT вместо 1.0.0).

Номера версий сохраняются и корректно обновляются в gradle.properties, поэтому я предполагаю, что мне нужно обновить версии в модели данных, а также чтобы изменения вступили в силу.

Моя конфигурация плагина для Android:

defaultConfig {
    versionCode versionCode as int  // taken from gradle.properties
    versionName versionName // taken from gradle.properties
    minSdkVersion 10
    targetSdkVersion 19
}

Вещи, которые я пробовал:

preBuild << {
    android.applicationVariants.each { variant ->
        variant.versionName = versionName
    }
}

Но в варианте нет версииName.

preBuild << {
    android.buildTypes.each { type ->
        type.versionName = versionName
    }
}

Но нет типаName в типе.

preBuild << {
    android.productFlavors.each { flavor ->
        flavor.versionName = versionName
    }
}

Но в моем приложении нет вкусов (только простые типы отладки и выпуска).

Моей альтернативой является написать bash/bat script, чтобы поменять версии перед вызовом Gradle, что в значительной степени поражает цель использования Groovy для улучшения настройки сборки.

Как я могу динамически обновлять версии в плагине Android Gradle на этапе выполнения?

4b9b3361

Ответ 1

Для чего предназначены buildTypes. То, что вы описываете, это сборка release, IMO.

Вот пример: при выполнении assembleDebug он даст вам сборку моментальных снимков, а выполнение assembleRelease даст вам чистую сборку без какого-либо суффикса и увеличенного номера версии. Следующая сборка отладки также будет использовать увеличивающийся номер.

Ниже приведена полная функциональная сборка, когда файлы создаются в папке. Он также должен работать с ароматами, но это только побочный продукт:). Gradle 2.2.1, Android-плагин 1.1.3

build.gradle

apply plugin: 'com.android.application'
apply from: 'auto-version.gradle'

buildscript {
    repositories { jcenter() }
    dependencies { classpath 'com.android.tools.build:gradle:1.1.3' }
}

android {
    buildToolsVersion = "21.1.2"
    compileSdkVersion = "android-21"

    buildTypes {
        debug {
            versionNameSuffix "-SNAPSHOT"
        }
    }
}

println "config code: ${calculateVersionCode()}, name: ${calculateVersionName()}"

SRC/основные/AndroidManifest.xml

<manifest package="com.example" />

авто-version.gradle

ext {
    versionFile = new File(project.rootDir, 'version.properties')
    calculateVersionName = {
        def version = readVersion()
        return "${version['major']}.${version['minor']}.${version['build']}"
    }
    calculateVersionCode = {
        def version = readVersion()
        def major = version['major'] as int // 1..∞
        def minor = version['minor'] as int // 0..99
        def build = version['build'] as int // 0..999
        return (major * 100 + minor) * 1000 + build
    }
}


Properties readVersion() {
    def version = new Properties()
    def stream
    try {
        stream = new FileInputStream(versionFile)
        version.load(stream)
    } catch (FileNotFoundException ignore) {
    } finally {
        if (stream != null) stream.close()
    }
    // safety defaults in case file is missing
    if(!version['major']) version['major'] = "1"
    if(!version['minor']) version['minor'] = "0"
    if(!version['build']) version['build'] = "0"
    return version
}

void incrementVersionNumber() {
    def version = readVersion()

    // careful with the types, culprits: "9"++ = ":", "9" + 1 = "91"
    def build = version['build'] as int
    build++
    version['build'] = build.toString()

    def stream = new FileOutputStream(versionFile)
    try {
        version.store(stream, null)
    } finally {
        stream.close()
    }
}

task incrementVersion {
    description "Increments build counter in ${versionFile}"
    doFirst {
        incrementVersionNumber()
    }
}

if (plugins.hasPlugin('android') || plugins.hasPlugin('android-library')) {
    android {
        defaultConfig {
            versionName = calculateVersionName()
            versionCode = calculateVersionCode()
        }

        afterEvaluate {
            def autoIncrementVariant = { variant ->
                if (variant.buildType.name == buildTypes.release.name) { // don't increment on debug builds
                    variant.preBuild.dependsOn incrementVersion
                    incrementVersion.doLast {
                        variant.mergedFlavor.versionName = calculateVersionName()
                        variant.mergedFlavor.versionCode = calculateVersionCode()
                    }
                }
            }
            if (plugins.hasPlugin('android')) {
                applicationVariants.all { variant -> autoIncrementVariant(variant) }
            }
            if (plugins.hasPlugin('android-library')) {
                libraryVariants.all { variant -> autoIncrementVariant(variant) }
            }
        }
    }
}

Выполняйте gradle assembleDebug, чтобы нормально строить, gradle assembleRelease, чтобы увеличивать и строить, и gradle incrementVersion просто увеличивать. Примечание: будьте осторожны с gradle assemble, потому что порядок assembleDebug и assembleRelease даст разные результаты.

Проверьте сгенерированные файлы в каталоге build, чтобы увидеть, соответствуют ли значения.

Ручное исполнение (из комментариев)

Возможно, у вас есть несколько вариантов, в этом случае версия увеличивается несколько раз, потому что несколько вариантов соответствуют типу выпуска. Первоначальный вопрос не вызывал никаких неприятностей. Если вы хотите получить больше контроля при увеличении номера версии, просто удалите блок afterEvaluate и вызовите задачу incrementVersion всякий раз, когда вы хотите:

gradle incrementVersion assembleFreeRelease assemblePaidRelease

(Вышеприведенное ручное выполнение является непроверенной идеей.)

Проверить незафиксированные изменения

"Проверить незафиксированные изменения" в этом ответе не рассматриваются, это другая игра. Если я правильно понял, вы можете подключиться к tasks.preBuild.doFirst { /*fail here if uncommited changes*/ }. Но это сильно зависит от вашего контроля версий. Задайте еще один вопрос!

Ответ 2

Это не напрямую касается вашего вопроса о том, как полностью изменить имя versionName, но это то, что я использую для добавления суффикса для моих buildTypes:

defaultConfig {
    versionName "1.0"
}

buildTypes {
    debug {
        versionNameSuffix "-SNAPSHOT"
    }
}

Ответ 3

Мне нужно было добавить текущий номер git commit для проверки версии кода на имя версии. Это очень удобно во многих ситуациях. Я закончил с ниже простого файла gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.2"

    def gitCommitCount = "git rev-list HEAD --count".execute().text.trim()

    defaultConfig {
        applicationId "my.app.package.name"
        minSdkVersion 16
        targetSdkVersion 21
        versionCode 6
        versionName "0.8"
    }

    buildTypes {

        debug {
            versionNameSuffix ".${gitCommitCount}"
        }

        release {
            versionNameSuffix ".${gitCommitCount}"
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

        }
    }
}

Подобно gitCommitCount, вы можете создавать собственные переменные для настройки имени версии. Поскольку я просто выполняю команду терминала, чтобы сохранить ее результат в переменной.

Ответ 4

Я только что использовал ответ Javanator и немного изменил его, так что фиксация commit не только помогает в изменении имени, но также гарантирует, что код версии также остается уникальным. Вот пример того, что я сделал (может быть, несколько вещей можно оптимизировать, но тем не менее выполняет эту работу для меня):

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    def gitCommitCount = "git rev-list HEAD --count".execute().text.trim().toBigInteger()
    project.ext.set("versionCode", gitCommitCount)
    project.ext.set("versionNameSuffix", "(${gitCommitCount})")

    defaultConfig {
        applicationId "my.app.package.name"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode  project.versionCode
        versionName "1.0"
        versionNameSuffix project.versionNameSuffix
        setProperty("archivesBaseName", "MyProject-$versionName")
        ....
    }

    signingConfigs {
        config {
            .........
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.config
        }
    }

    packagingOptions {
        .....
    }

    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            output.outputFile = new File(
                    output.outputFile.parent,
                    output.outputFile.name.replace(".apk", "-${variant.versionName}.apk"))
        }
    }
}

Ответ 5

Я столкнулся с аналогичной необходимостью иметь отдельную логику сборки для релизов и выпусков. Помимо разных версий, мне пришлось использовать другой набор зависимостей, даже разные репозитории.

Ни один из доступных плагинов не имел всех необходимых мне функций, поэтому я разработал собственное решение на основе простого подхода - аргумент командной строки.

Вы можете передать параметр командной строки при вызове gradle build script следующим образом:

gradle build -PmyParameter=myValue

или в моем случае

gradle build -PisRelease=true

Gradle будет анализировать его, и он автоматически будет доступен как свойство объекта проекта. Затем вы можете использовать его следующим образом:

if (project.isRelease) {
        // Here be the logic!
}

Я извлек эту логику в отдельный плагин, и я успешно использовал его в разных проектах.

Хотя это не отвечает на ваш вопрос напрямую, я надеюсь, что я дал вам еще один поворот, чтобы подумать о проблеме и о другом возможном решении.