Как установить versionName в APK-файле, используя gradle?

169

Я пытаюсь установить конкретный номер версии в автоматически сгенерированном имени файла APK.

Теперь Gradle генерирует, myapp-release.apkно я хочу, чтобы это выглядело примерно так myapp-release-1.0.apk.

Я попытался переименовать варианты, которые кажутся грязными. Есть ли простой способ сделать это?

buildTypes {
    release {
       signingConfig signingConfigs.release
       applicationVariants.each { variant ->
       def file = variant.outputFile
       variant.outputFile = new File(file.parent, file.name.replace(".apk", "-" +    defaultConfig.versionName + ".apk"))
    }
}

Я попробовал код выше без удачи. Какие-либо предложения? (используя Gradle 1.6)

codaR0y
источник

Ответы:

225

Мне нужно только изменить название версии в одном месте. Код тоже прост.

В приведенных ниже примерах будут создаваться файлы apk с именем MyCompany-MyAppName-1.4.8-debug.apk или MyCompany-MyAppName-1.4.8-release.apk в зависимости от выбранного варианта сборки.

Обратите внимание, что это решение работает как с APK, так и с пакетами приложений (файлы .aab) .

См. Также: Как изменить имя файла отображения Proguard в Gradle для проекта Android

Решение для недавних плагинов Gradle

android {
    compileSdkVersion 22
    buildToolsVersion "22.0.1"
    defaultConfig {
        applicationId "com.company.app"
        minSdkVersion 13
        targetSdkVersion 21
        versionCode 14       // increment with every release
        versionName '1.4.8'   // change with every release
        setProperty("archivesBaseName", "MyCompany-MyAppName-$versionName")
    }
}

Вышеупомянутое решение было протестировано со следующими версиями плагина Android Gradle:

  • 3.5.2 (ноябрь 2019 г.)
  • 3.3.0 (январь 2019 г.)
  • 3.1.0 (март 2018 г.)
  • 3.0.1 (ноябрь 2017 г.)
  • 3.0.0 (октябрь 2017 г.)
  • 2.3.2 (май 2017 г.)
  • 2.3.1 (апрель 2017 г.)
  • 2.3.0 (февраль 2017 г.)
  • 2.2.3 (декабрь 2016 г.)
  • 2.2.2
  • 2.2.0 (сентябрь 2016 г.)
  • 2.1.3 (август 2016 г.)
  • 2.1.2
  • 2.0.0 (апрель 2016 г.)
  • 1.5.0 (2015/11/12)
  • 1.4.0-бета6 (2015/10/05)
  • 1.3.1 (2015/08/11)

Я буду обновлять этот пост по мере выхода новых версий.

Решение протестировано только на версиях 1.1.3-1.3.0

Следующее решение было протестировано со следующими версиями плагина Android Gradle:

файл приложения Gradle:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.2"
    defaultConfig {
        applicationId "com.company.app"
        minSdkVersion 13
        targetSdkVersion 21
        versionCode 14       // increment with every release
        versionName '1.4.8'   // change with every release
        archivesBaseName = "MyCompany-MyAppName-$versionName"
    }
}
Джон
источник
11
Я думаю, что это правильный подход вместо написания другой задачи для переименования файлов.
Нандиш А,
5
просто измените на archivesBaseName = "MyCompany-MyAppName- $ versionName", если у вас есть OCD и вы не хотите, чтобы AS предупреждал вас о +
ligi
4
Отличная находка, но не очень хорошо работает со вкусами с разными кодами версий. Все они в конечном итоге с одинаковым кодом версии.
Уэстон
2
Есть ли способ добавить variant.buildType.nameк имени? Я знаю, что это не относится к конфигурации по умолчанию, но я пытаюсь выяснить, как удалить устаревшее variantOutput.getAssemble()предупреждение
Аллан W
2
Можно ли удалить из apk name последнюю '-debug' / '-release'?
ильяуромец
173

Это решило мою проблему: использование applicationVariants.allвместоapplicationVariants.each

buildTypes {
      release {
        signingConfig signingConfigs.release
        applicationVariants.all { variant ->
            def file = variant.outputFile
            variant.outputFile = new File(file.parent, file.name.replace(".apk", "-" + defaultConfig.versionName + ".apk")) 
        }
    }       
}

Обновить:

Таким образом, кажется, что это не работает с 0.14+ версиями плагина для Android Studio Gradle.

Это делает трюк (ссылка на этот вопрос ):

android {
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            output.outputFile = new File(
                    output.outputFile.parent,
                    output.outputFile.name.replace(".apk", "-${variant.versionName}.apk"))
        }
    }
}
codaR0y
источник
3
Вы знаете, как заставить это работать, если у меня есть versionNameопределенный в AndroidManifest.xmlвместо конфигурации gradle? Это дает мне myapp-release-null.apkсейчас.
Иво Банас
1
Этот ответ не работает с версиями Gradle 0.14+. Какие-нибудь обновления для работы с ними?
Аргайл
1
@withoutclass Я задал это как собственный вопрос и получил ответ здесь: stackoverflow.com/questions/27068505/…
Argyle
2
Для людей, переходящих eachна Gradle 4: измените на allи output.outputFileна outputFileName. Если кто-то подтвердит, что это работает, его можно отредактировать в ответ :)
PHPirate
6
@PHPirate: почти работает:Error:(34, 0) Cannot set the value of read-only property 'name'
Mooing Duck
47

(ИЗМЕНЕНО для работы с Android Studio 3.0 и Gradle 4)

Я искал более сложную опцию переименования файлов apk, и я написал эту в надежде, что она будет полезна для всех остальных. Переименовывает apk со следующими данными:

  • аромат
  • тип сборки
  • версия
  • Дата

Мне потребовалось немного исследований в классах Gradle и немного копирования / вставки из других ответов. Я использую Gradle 3.1.3 .

В build.gradle:

android {

    ...

    buildTypes {
        release {
            minifyEnabled true
            ...
        }
        debug {
            minifyEnabled false
        }
    }

    productFlavors {
        prod {
            applicationId "com.feraguiba.myproject"
            versionCode 3
            versionName "1.2.0"
        }
        dev {
            applicationId "com.feraguiba.myproject.dev"
            versionCode 15
            versionName "1.3.6"
        }
    }

    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            def project = "myProject"
            def SEP = "_"
            def flavor = variant.productFlavors[0].name
            def buildType = variant.variantData.variantConfiguration.buildType.name
            def version = variant.versionName
            def date = new Date();
            def formattedDate = date.format('ddMMyy_HHmm')

            def newApkName = project + SEP + flavor + SEP + buildType + SEP + version + SEP + formattedDate + ".apk"

            outputFileName = new File(newApkName)
        }
    }
}

Если вы скомпилируете сегодня (13-10-2016) в 10:47, вы получите следующие имена файлов в зависимости от выбранной вами разновидности и типа сборки:

  • dev debug : myProject_ dev_debug_1.3.6 _131016_1047.apk
  • релиз разработчика : myProject_ dev_release_1.3.6 _131016_1047.apk
  • Отладка prod : myProject_ prod_debug_1.2.0 _131016_1047.apk
  • релиз prod : myProject_ prod_release_1.2.0 _131016_1047.apk

Примечание. Имя apk версии без выравнивания по-прежнему остается именем по умолчанию.

Фер
источник
Отличное решение. Я попробовал, и это идеально подходит для моей проблемы. Спасибо!
Пейбл
Можно ли использовать тот же подход в Xamarin Studio?
Алессандро Кальяро
Было бы здорово, если бы это было возможно, но сейчас я начинаю курс ксамарина, и у меня все еще недостаточно практики, чтобы знать, возможно это или нет. Я задам этот вопрос и приду сюда снова.
Фер
Комментарий преподавателя курса: «есть опция, в которой вы можете использовать команды для изменения имени сгенерированных файлов». Поэтому подход к использованию в Xamarin должен отличаться от того, который я написал для Android Studio, извините.
Fer
3
Для устранения ошибки Невозможно установить значение свойства «только для чтения» outputFile - как упоминалось в предыдущем комментарии о необходимости «перейти eachна allи output.outputFileна outputFileName» - этот пост содержит некоторые подробности об этом: stackoverflow.com/a/44265374/2162226
Джин Бо
19

Подводя итог, для тех, кто не знает, как импортировать пакет build.gradle(как я), используйте следующее buildTypes,

buildTypes {
      release {
        signingConfig signingConfigs.release
        applicationVariants.all { variant ->
            def file = variant.outputFile
            def manifestParser = new com.android.builder.core.DefaultManifestParser()
            variant.outputFile = new File(file.parent, file.name.replace(".apk", "-" + manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile) + ".apk")) 
        }
    }       
}

===== РЕДАКТИРОВАТЬ =====

Если вы установите свой versionCodeи versionNameв вашем build.gradleфайле, как это:

defaultConfig {
    minSdkVersion 15
    targetSdkVersion 19
    versionCode 1
    versionName "1.0.0"
}

Вы должны установить это так:

buildTypes {   
        release {
            signingConfig signingConfigs.releaseConfig
            applicationVariants.all { variant ->
                def file = variant.outputFile
                variant.outputFile = new File(file.parent, file.name.replace(".apk", "-" + defaultConfig.versionName + ".apk"))
            }
        }
}


====== РЕДАКТИРОВАТЬ с Android Studio 1.0 ======

Если вы используете Android Studio 1.0, вы получите такую ​​ошибку:

Error:(78, 0) Could not find property 'outputFile' on com.android.build.gradle.internal.api.ApplicationVariantImpl_Decorated@67e7625f.

Вы должны изменить build.Typesчасть на это:

buildTypes {
        release {
            signingConfig signingConfigs.releaseConfig
            applicationVariants.all { variant ->
                variant.outputs.each { output ->
                    output.outputFile = new File(output.outputFile.parent, output.outputFile.name.replace(".apk", "-" + defaultConfig.versionName + ".apk"))
                }
            }
        }
    }
Wesley
источник
Это прекрасно работает. Однако, поскольку я увеличиваю свою версию манифеста в сборке Gradle, он создает APK с более старым значением (до увеличения). Есть ли способ убедиться, что это вступит в силу после того, как скрипт gradle увеличит номер версии?
Парень
1
@ Гай Извините, что так долго. Я отредактировал ответ, посмотрим, сможет ли он решить вашу проблему.
Уэсли
17

Если вы не укажете versionName в блоке defaultConfig, defaultConfig.versionNameэто приведет кnull

чтобы получить versionName из манифеста, вы можете написать следующий код в build.gradle:

import com.android.builder.DefaultManifestParser

def manifestParser = new DefaultManifestParser()
println manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile)
Аркадиуш Конор
источник
7
Я полагаю, что с более поздними версиями gradle теперь это com.android.builder.core.DefaultManifestParser
Райан С
8

В моем случае я просто хотел найти способ автоматизировать генерацию разных apkназваний releaseи debugвариантов. Мне удалось сделать это легко, поместив этот фрагмент в детство android:

applicationVariants.all { variant ->
    variant.outputs.each { output ->
        def appName = "My_nice_name_"
        def buildType = variant.variantData.variantConfiguration.buildType.name
        def newName
        if (buildType == 'debug'){
            newName = "${appName}${defaultConfig.versionName}_dbg.apk"
        } else {
            newName = "${appName}${defaultConfig.versionName}_prd.apk"
        }
        output.outputFile = new File(output.outputFile.parent, newName)
    }
}

Для нового плагина Android Gradle 3.0.0 вы можете сделать что-то вроде этого:

 applicationVariants.all { variant ->
    variant.outputs.all {
        def appName = "My_nice_name_"
        def buildType = variant.variantData.variantConfiguration.buildType.name
        def newName
        if (buildType == 'debug'){
            newName = "${appName}${defaultConfig.versionName}_dbg.apk"
        } else {
            newName = "${appName}${defaultConfig.versionName}_prd.apk"
        }
        outputFileName = newName
    }
}

Это производит что-то вроде: My_nice_name_3.2.31_dbg.apk

yshahak
источник
6

Другой альтернативой является использование следующего:

String APK_NAME = "appname"
int VERSION_CODE = 1
String VERSION_NAME = "1.0.0"

project.archivesBaseName = APK_NAME + "-" + VERSION_NAME;

    android {
      compileSdkVersion 21
      buildToolsVersion "21.1.1"

      defaultConfig {
        applicationId "com.myapp"
        minSdkVersion 15
        targetSdkVersion 21
        versionCode VERSION_CODE
        versionName VERSION_NAME
      }

       .... // Rest of your config
}

Это установит "appname-1.0.0" для всех ваших выходных apk.

Марко РС
источник
Извините, не работает (больше): No such property: archivesBaseName for class: org.gradle.api.internal.project.DefaultProject_Decorated
Мартин
Какую версию Gradle вы используете?
Марко Р.С.
6

Gradle 6+

Сейчас я использую следующее в Android Studio 4.0 и Gradle 6.4:

android {
    defaultConfig {
        applicationId "com.mycompany.myapplication"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 15
        versionName "2.1.1"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            applicationVariants.all { variant ->
                variant.outputs.all {
                    outputFileName = "ApplicationName-${variant.name}-${variant.versionName}.apk"
                }
            }
        }
    }
}

Gradle 4

Синтаксис немного изменился в Gradle 4 (Android Studio 3+) (от output.outputFileдо outputFileName, идея из этого ответа теперь:

android {
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def newName = outputFileName
            newName.replace(".apk", "-${variant.versionName}.apk")
            outputFileName = new File(newName)
        }
    }
}
PHPirate
источник
Любая идея, как это исправить для Gradle 6?
spartygw
@spartygw Обновил ответ
PHPirate
5

Правильный способ переименовать apk, как в ответе @Jon

defaultConfig {
        applicationId "com.irisvision.patientapp"
        minSdkVersion 24
        targetSdkVersion 22
        versionCode 2  // increment with every release
        versionName "0.2" // change with every release
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        //add this line
        archivesBaseName = "AppName-${versionName}-${new Date().format('yyMMdd')}"
    }   

Или другим способом вы можете достичь тех же результатов с

android {
    ...

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            def formattedDate = new Date().format('yyMMdd')
            outputFileName = "${outputFileName.replace(".apk","")}-v${defaultConfig.versionCode}-${formattedDate}.apk"
        }
    }
}
Камар
источник
Хороший на этом! Мне нравится это лучше, чем другие способы, которыми я сейчас занимаюсь.
Droid Chris
3

Есть много ответов, которые являются правильными либо в полном объеме, либо после некоторых изменений. Но я все равно добавлю свой, поскольку у меня возникла проблема со всеми из них, потому что я использовал сценарии для динамического генерирования VersionName и VersionCode, подключившись к preBuildзадаче.

Если вы используете какой-то похожий подход, это код, который будет работать:

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

Объяснить: так как я переопределяю код версии и имя в первом действии, preBuildмне нужно добавить переименование файла в конец этой задачи. Так что Gradle будет делать в этом случае:

Введите код версии / имя-> выполнить действия preBuild -> заменить имя для apk

Игорь Чордаш
источник
Где вы устанавливаете сгенерированные переменные versionCode и versionName?
Марс
Насколько я помню, это было сделано внутри нашего пользовательского плагина Gradle. Его выполнение было названо последним действием задачи preBuild.
Игорь Чордаш
2
    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            output.outputFileName = output.outputFileName.replace(".apk", "-${variant.versionName}.apk")
        }
    }
Timeon
источник
Хотя этот фрагмент кода может решить вопрос, в том числе объяснение действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин, по которым вы предлагаете код.
Росарио Перейра Фернандес
1

В моем случае я решаю эту ошибку таким образом

добавив SUFFIX к версии Debug, в этом случае я добавляю текст "-DEBUG" в мое развертывание Debug

 buildTypes {
        release {

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


        }
        debug {

            defaultConfig {
                debuggable true

                versionNameSuffix "-DEBUG"
            }
        }
    }
exequielc
источник
Это не меняет имя файла APK.
Том
1
На самом деле это хороший совет. Не в правильном вопросе, но в хорошем. Где я могу прочитать больше об этом? Можно ли использовать versionNameSuffixна основе ветки GIT? Например, если это не на «master», всегда есть суффикс, даже если это
Android-разработчик
0

Для последних версий Gradle вы можете использовать следующий фрагмент:

Сначала установите местоположение манифеста приложения

 sourceSets {
        main {
            manifest.srcFile 'src/main/AndroidManifest.xml'
        {
    }

И позже в build.gradle

import com.android.builder.core.DefaultManifestParser

def getVersionName(manifestFile) {
    def manifestParser = new DefaultManifestParser();
    return manifestParser.getVersionName(manifestFile);
}

def manifestFile = file(android.sourceSets.main.manifest.srcFile);
def version = getVersionName(manifestFile)

buildTypes {
    release {
       signingConfig signingConfigs.release
       applicationVariants.each { variant ->
       def file = variant.outputFile
       variant.outputFile = new File(file.parent, file.name.replace(".apk", "-" +    versionName + ".apk"))
    }
}

Отрегулируйте, если у вас есть разные манифесты для типа сборки. но так как у меня есть один - отлично работает для меня.

Alfishe
источник
Можно ли добавить строку из файла класса к имени apk ??
Упендра Шах
0

Начиная с Android Studio 1.1.0, эта комбинация работала в теле андроидаbuild.gradle файла . Это если вы не можете понять, как импортировать данные XML-файла манифеста. Хотелось бы, чтобы Android Studio больше его поддерживал, но просто поиграйте со значениями, пока не получите желаемый вывод имени apk:

defaultConfig {
        applicationId "com.package.name"
        minSdkVersion 14
        targetSdkVersion 21
        versionCode 6
        versionName "2"
    }
    signingConfigs {
        release {
            keyAlias = "your key name"
        }
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

            signingConfig signingConfigs.release
            applicationVariants.all { variant ->
                variant.outputs.each { output ->
                    output.outputFile = new File(output.outputFile.parent, output.outputFile.name.replace("app-release.apk", "appName_" + versionName + ".apk"))
                }
            }
        }
    }
A13X
источник