Jak ustawić nazwę wersji w nazwie pliku APK za pomocą Gradle?

169

Próbuję ustawić konkretny numer wersji w automatycznie generowanej przez Gradle nazwie pliku APK.

Teraz gradle generuje, myapp-release.apkale chcę, żeby wyglądało jak myapp-release-1.0.apk.

Próbowałem zmienić nazwy opcji, które wydają się niechlujne. Czy jest na to prosty sposób?

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"))
    }
}

Wypróbowałem powyższy kod bez powodzenia. Jakieś sugestie? (przy użyciu klasy 1.6)

codaR0y
źródło

Odpowiedzi:

225

Wystarczy, że zmienię nazwę wersji w jednym miejscu. Kod też jest prosty.

Poniższe przykłady utworzą pliki apk o nazwach MyCompany-MyAppName-1.4.8-debug.apk lub MyCompany-MyAppName-1.4.8-release.apk w zależności od wybranego wariantu kompilacji.

Pamiętaj, że to rozwiązanie działa zarówno w przypadku pakietów APK, jak i pakietów aplikacji (pliki .aab) .

Zobacz też: Jak zmienić nazwę pliku mapowania proguard w Gradle dla projektu Android

Rozwiązanie dla najnowszej wtyczki 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")
    }
}

Powyższe rozwiązanie zostało przetestowane z następującymi wersjami wtyczek Android Gradle:

  • 3.5.2 (listopad 2019 r.)
  • 3.3.0 (styczeń 2019 r.)
  • 3.1.0 (marzec 2018 r.)
  • 3.0.1 (listopad 2017)
  • 3.0.0 (październik 2017)
  • 2.3.2 (maj 2017)
  • 2.3.1 (kwiecień 2017)
  • 2.3.0 (luty 2017)
  • 2.2.3 (grudzień 2016 r.)
  • 2.2.2
  • 2.2.0 (wrzesień 2016 r.)
  • 2.1.3 (sierpień 2016 r.)
  • 2.1.2
  • 2.0.0 (kwiecień 2016 r.)
  • 1.5.0 (2015/11/12)
  • 1.4.0-beta6 (2015/10/05)
  • 1.3.1 (2015/08/11)

Zaktualizuję ten post, gdy pojawią się nowe wersje.

Rozwiązanie przetestowane tylko w wersjach 1.1.3-1.3.0

Następujące rozwiązanie zostało przetestowane z następującymi wersjami wtyczek Android Gradle:

  • 1.3.0 (30.07.2015) - Nie działa, błąd zaplanowany do naprawienia w 1.3.1
  • 1.2.3 (21.07.2015)
  • 1.2.2 (28.04.2015)
  • 1.2.1 (27.04.2015)
  • 1.2.0 (26.04.2015)
  • 1.2.0-beta1 (2015/03/25)
  • 1.1.3 (2015/03/06)

plik oceny aplikacji:

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"
    }
}
Jon
źródło
11
Myślę, że jest to właściwe podejście zamiast pisać kolejne zadanie zmiany nazw plików.
Nandish A
5
po prostu zmień na archivesBaseName = "MyCompany-MyAppName- $ versionName", jeśli masz OCD i nie chcesz, aby AS ostrzegał Cię o +
ligi
4
Świetne znalezisko, ale nie działa dobrze ze smakami z różnymi kodami wersji. Wszystkie kończą się tym samym kodem wersji.
weston
2
Czy jest jakiś sposób, aby dodać coś variant.buildType.namedo nazwy? Wiem, że to nie jest tak naprawdę związane z domyślną konfiguracją, ale próbuję wymyślić, jak usunąć przestarzałe variantOutput.getAssemble()ostrzeżenie
Allan W
2
Czy można usunąć z nazwy apk last „-debug” / „-release”?
ilyamuromets
173

To rozwiązało mój problem: używanie applicationVariants.allzamiastapplicationVariants.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")) 
        }
    }       
}

Aktualizacja:

Wygląda więc na to, że nie działa to z wersjami 0.14+ wtyczki Android Studio Gradle.

To załatwia sprawę (odniesienie do tego pytania ):

android {
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            output.outputFile = new File(
                    output.outputFile.parent,
                    output.outputFile.name.replace(".apk", "-${variant.versionName}.apk"))
        }
    }
}
codaR0y
źródło
3
Czy wiesz, jak to uruchomić, jeśli mam versionNamezdefiniowaną AndroidManifest.xmlkonfigurację w zamiast gradle? Daje mi to myapp-release-null.apkteraz.
Iwo Banas
1
Ta odpowiedź nie działa z wersjami 0.14+ wtyczki Gradle. Jakieś aktualizacje do pracy z nimi?
Argyle
1
@withoutclass Zadałem to jako własne pytanie i otrzymałem odpowiedź tutaj: stackoverflow.com/questions/27068505/ ...
Argyle
2
Dla osób aktualizujących do Gradle 4: zmień eachna alli output.outputFilena outputFileName. Jeśli ktoś potwierdzi, że to działa, można to zmienić w odpowiedzi :)
PHPirate
6
@PHPirate: prawie działa:Error:(34, 0) Cannot set the value of read-only property 'name'
Mooing Duck,
47

(ZMIENIONO do pracy z Android Studio 3.0 i Gradle 4)

Szukałem bardziej złożonej opcji zmiany nazwy pliku apk i napisałem tę w nadziei, że będzie pomocna dla każdego innego. Zmienia nazwę apk z następującymi danymi:

  • smak
  • typ kompilacji
  • wersja
  • data

Zajęło mi to trochę badań w klasach i trochę kopiowania / wklejania z innych odpowiedzi. Używam gradle 3.1.3 .

W pliku 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)
        }
    }
}

Jeśli skompilujesz dzisiaj (13-10-2016) o 10:47, otrzymasz następujące nazwy plików w zależności od wybranego smaku i typu kompilacji:

  • dev debug : myProject_ dev_debug_1.3.6 _131016_1047.apk
  • wersja deweloperska: myProject_ dev_release_1.3.6 _131016_1047.apk
  • debugowanie prod : myProject_ prod_debug_1.2.0 _131016_1047.apk
  • wydanie prod : myProject_ prod_release_1.2.0 _131016_1047.apk

Uwaga: niewyrównana nazwa apk wersji jest nadal domyślną.

Fer
źródło
Świetne rozwiązanie. Wypróbowałem to i jest to idealne rozwiązanie dla mojego problemu. Dzięki!
Pabel
czy można zastosować to samo podejście w Xamarin Studio?
Alessandro Caliaro
Byłoby wspaniale, gdyby to było możliwe, ale zaczynam teraz kurs Xamarin i nadal nie mam z nim wystarczającej praktyki, aby wiedzieć, czy jest to możliwe, czy nie. Zadam to pytanie i wrócę tu ponownie.
Fer
Komentarz prowadzącego kurs: „istnieje możliwość wykorzystania poleceń do zmiany nazwy generowanych plików”. Dlatego podejście do korzystania z Xamarina musi być inne niż to, które napisałem dla Android Studio, przepraszam.
Fer
3
Aby rozwiązać problem Nie można ustawić wartości właściwości tylko do odczytu „outputFile” - jak wspomniano we wcześniejszym komentarzu dotyczącym konieczności „zmiany eachna alli output.outputFilena outputFileName - ten post zawiera szczegółowe informacje na ten temat: stackoverflow.com/a/44265374/2162226
Gene Bo,
19

Podsumowując, dla tych, którzy nie wiedzą, jak zaimportować paczkę build.gradle(tak jak ja), użyj następującego 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")) 
        }
    }       
}

===== EDYCJA =====

Jeśli ustawisz versionCodei versionNamew build.gradlepliku jak poniżej:

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

Powinieneś to ustawić tak:

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"))
            }
        }
}


====== EDYCJA w Android Studio 1.0 ======

Jeśli korzystasz z Android Studio 1.0, pojawi się następujący błąd:

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

Powinieneś zmienić build.Typesczęść na następującą:

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
źródło
To działa świetnie. Jednak ponieważ zwiększam moją wersję manifestu w kompilacji Gradle, utworzy plik APK ze starszą (przed inkrementacją) wartością. Czy jest jakiś sposób, aby upewnić się, że nastąpi to po zwiększeniu numeru wersji przez skrypt gradle?
Guy
1
@Guy Przepraszamy, zajęło to tak dużo czasu. Zmieniłem odpowiedź, zobacz, czy może rozwiązać twój problem.
Wesley,
17

Jeśli nie określisz versionName w bloku defaultConfig, defaultConfig.versionNamespowoduje tonull

aby pobrać versionName z manifestu, możesz napisać następujący kod w build.gradle:

import com.android.builder.DefaultManifestParser

def manifestParser = new DefaultManifestParser()
println manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile)
Arkadiusz Konior
źródło
7
Uważam, że w późniejszych wersjach gradle jest teraz com.android.builder.core.DefaultManifestParser
Ryan S
8

W moim przypadku chciałem tylko znaleźć sposób na zautomatyzowanie generowania różnych apknazw releasei debugwariantów. Udało mi się to łatwo zrobić, umieszczając ten fragment jako dziecko 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)
    }
}

W przypadku nowej wtyczki Gradle dla Androida 3.0.0 możesz zrobić coś takiego:

 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
    }
}

To daje coś takiego: My_nice_name_3.2.31_dbg.apk

yshahak
źródło
6

Inną alternatywą jest użycie:

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
}

Spowoduje to ustawienie „appname-1.0.0” na wszystkie wyjścia apk.

Marco RS
źródło
Przepraszamy, nie działa (już): No such property: archivesBaseName for class: org.gradle.api.internal.project.DefaultProject_Decorated
Martin
Jakiej wersji Gradle używasz?
Marco RS
6

Gradle 6+

Teraz używam następujących w Android Studio 4.0 i 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

Składnia nieco się zmieniła w Gradle 4 (Android Studio 3+) (od output.outputFiledo outputFileName, idea z tej odpowiedzi jest teraz:

android {
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def newName = outputFileName
            newName.replace(".apk", "-${variant.versionName}.apk")
            outputFileName = new File(newName)
        }
    }
}
PHPirate
źródło
Masz jakiś pomysł, jak to naprawić dla gradle 6?
spartygw
@spartygw Zaktualizowano odpowiedź
PHPirate
5

Właściwy sposób na zmianę nazwy apk, zgodnie z odpowiedzią @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')}"
    }   

Lub w inny sposób możesz osiągnąć te same wyniki za pomocą

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"
        }
    }
}
Qamar
źródło
Niezły w tym! Podoba mi się to bardziej niż inne sposoby, w jakie obecnie to robię.
Droid Chris,
3

Istnieje wiele odpowiedzi, które są poprawne w całości lub po pewnych modyfikacjach. Ale i tak mam zamiar dodać swoje, ponieważ miałem problem z nimi wszystkimi, ponieważ używałem skryptów do dynamicznego generowania VersionName i VersionCode, podłączając się dopreBuild zadania.

Jeśli używasz podobnego podejścia, oto kod, który będzie działał:

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"))
        }
    }
}

Wyjaśnienie: ponieważ nadpisuję kod wersji i nazwę w pierwszej akcji preBuild muszę dodać zmianę nazwy pliku na koniec tego zadania. Więc to, co zrobi gradle w tym przypadku, to:

Wstaw kod / nazwę wersji -> wykonaj akcje preBuild -> zamień nazwę na apk

Igor Čordaš
źródło
Gdzie ustawiasz wygenerowane zmienne versionCode i versionName?
Mars
O ile pamiętam, zostało to zrobione w naszej niestandardowej wtyczce gradle. Jego wykonanie zostało nazwane ostatnią czynnością zadania preBuild.
Igor Čordaš
2
    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            output.outputFileName = output.outputFileName.replace(".apk", "-${variant.versionName}.apk")
        }
    }
czas na
źródło
Chociaż ten fragment kodu może rozwiązać problem, dołączenie wyjaśnienia naprawdę pomaga poprawić jakość Twojego posta. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a osoby te mogą nie znać powodów, dla których zaproponowałeś kod.
Rosário Pereira Fernandes
1

W moim przypadku rozwiązuję ten błąd w ten sposób

dodanie SUFFIX do wersji debugowania, w tym przypadku dodam tekst "-DEBUG" do mojego wdrożenia debugowania

 buildTypes {
        release {

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


        }
        debug {

            defaultConfig {
                debuggable true

                versionNameSuffix "-DEBUG"
            }
        }
    }
exequielc
źródło
Nie zmienia to nazwy pliku APK.
Tom
1
Właściwie to fajna wskazówka. Nie we właściwym, ale dobrym pytaniu. Gdzie mogę przeczytać więcej na ten temat? Czy można korzystać w versionNameSuffixoparciu o gałąź GIT? Na przykład, jeśli nie ma go w pozycji „master”, zawsze ma sufiks, nawet jeśli jest to wersja wydana
programista Androida
0

W przypadku najnowszych wersji Gradle możesz użyć następującego fragmentu:

Najpierw ustaw lokalizację manifestu aplikacji

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

A później w 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"))
    }
}

Dostosuj, jeśli masz różne manifesty w zależności od typu kompilacji. ale skoro mam jedyny - u mnie działa idealnie.

Alfishe
źródło
czy można dodać ciąg z pliku klasy do nazwy apk?
Upendra Shah
0

Od wersji Android Studio 1.1.0 stwierdziłem, że ta kombinacja działa w treści pliku Androidabuild.gradle . Dzieje się tak, jeśli nie możesz dowiedzieć się, jak zaimportować dane pliku manifestu xml. Chciałbym, żeby był bardziej obsługiwany przez Android Studio, ale po prostu baw się wartościami, aż uzyskasz żądaną nazwę pliku 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
źródło