Comment définir le nom de version dans le nom de fichier APK en utilisant Gradle?

169

J'essaie de définir un numéro de version spécifique dans le nom de fichier APK généré automatiquement par gradle.

Maintenant, gradle génère myapp-release.apkmais je veux qu'il ressemble à quelque chose comme myapp-release-1.0.apk.

J'ai essayé de renommer des options qui semblent désordonnées. Existe-t-il un moyen simple de le faire?

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

J'ai essayé le code ci-dessus sans succès. Aucune suggestion? (en utilisant gradle 1.6)

codaR0y
la source

Réponses:

225

Je n'ai qu'à changer le nom de la version à un seul endroit. Le code est également simple.

Les exemples ci-dessous créeront des fichiers apk nommés MyCompany-MyAppName-1.4.8-debug.apk ou MyCompany-MyAppName-1.4.8-release.apk en fonction de la variante de construction sélectionnée.

Notez que cette solution fonctionne à la fois sur les fichiers APK et sur les bundles d'applications (fichiers .aab) .

Voir aussi: Comment changer le nom du fichier de mappage proguard dans le projet gradle pour Android

Solution pour le plugin Gradle récent

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

La solution ci-dessus a été testée avec les versions suivantes du plug-in Android Gradle:

  • 3.5.2 (novembre 2019)
  • 3.3.0 (janvier 2019)
  • 3.1.0 (mars 2018)
  • 3.0.1 (novembre 2017)
  • 3.0.0 (octobre 2017)
  • 2.3.2 (mai 2017)
  • 2.3.1 (avril 2017)
  • 2.3.0 (février 2017)
  • 2.2.3 (décembre 2016)
  • 2.2.2
  • 2.2.0 (septembre 2016)
  • 2.1.3 (août 2016)
  • 2.1.2
  • 2.0.0 (avril 2016)
  • 1.5.0 (12/11/2015)
  • 1.4.0-bêta6 (05/10/2015)
  • 1.3.1 (11/08/2015)

Je mettrai à jour ce post au fur et à mesure que de nouvelles versions sortiront.

Solution testée uniquement sur les versions 1.1.3-1.3.0

La solution suivante a été testée avec les versions suivantes du plug-in Android Gradle:

fichier de gradle d'application:

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
la source
11
Je pense que c'est la bonne approche au lieu d'écrire une autre tâche pour renommer les fichiers.
Nandish A
5
il suffit de changer pour archivesBaseName = "MyCompany-MyAppName- $ versionName" si vous avez un TOC et que vous ne voulez pas que AS vous avertisse du +
ligi
4
Bonne trouvaille, mais ne fonctionne pas bien avec les saveurs avec différents codes de version. Ils finissent tous avec le même code de version.
weston
2
Y a-t-il un moyen d'ajouter variant.buildType.nameau nom? Je sais que ce n'est pas vraiment lié à la configuration par défaut, mais j'essaie de comprendre comment supprimer l' variantOutput.getAssemble()avertissement obsolète
Allan W
2
Est-il possible de supprimer du nom apk le dernier '-debug' / '-release'?
ilyamuromets
173

Cela a résolu mon problème: utiliser applicationVariants.allau lieu deapplicationVariants.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")) 
        }
    }       
}

Mettre à jour:

Il semble donc que cela ne fonctionne pas avec les versions 0.14+ du plugin android studio gradle.

Cela fait l'affaire (référence de cette question ):

android {
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            output.outputFile = new File(
                    output.outputFile.parent,
                    output.outputFile.name.replace(".apk", "-${variant.versionName}.apk"))
        }
    }
}
codaR0y
la source
3
Savez-vous comment le faire fonctionner si j'ai une configuration versionNamedéfinie dans AndroidManifest.xmlau lieu de gradle? Ça me donne myapp-release-null.apkmaintenant.
Iwo Banas
1
Cette réponse ne fonctionne pas avec les versions 0.14+ du plugin gradle. Des mises à jour pour travailler avec celles-ci?
Argyle
1
@withoutclass J'ai posé cette question comme sa propre question et j'ai obtenu une réponse ici: stackoverflow.com/questions/27068505/…
Argyle
2
Pour les personnes qui passent à Gradle 4: changez eachen allet output.outputFileen outputFileName. Si quelqu'un confirme que cela fonctionne, il peut être modifié dans la réponse :)
PHPirate
6
@PHPirate: fonctionne presque:Error:(34, 0) Cannot set the value of read-only property 'name'
Mooing Duck
47

(MODIFIÉ pour fonctionner avec Android Studio 3.0 et Gradle 4)

Je cherchais une option de changement de nom de fichier apk plus complexe et j'ai écrit celle-ci dans l'espoir qu'elle soit utile pour quelqu'un d'autre. Il renomme l'apk avec les données suivantes:

  • saveur
  • type de construction
  • version
  • Date

Il m'a fallu un peu de recherche dans les classes Gradle et un peu de copier / coller d'autres réponses. J'utilise gradle 3.1.3 .

Dans le 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)
        }
    }
}

Si vous compilez aujourd'hui (13-10-2016) à 10:47, vous obtenez les noms de fichiers suivants en fonction de la saveur et du type de construction que vous avez choisis:

  • débogage de développement : myProject_ dev_debug_1.3.6 _131016_1047.apk
  • version de développement : myProject_ dev_release_1.3.6 _131016_1047.apk
  • débogage prod : myProject_ prod_debug_1.2.0 _131016_1047.apk
  • version de production : myProject_ prod_release_1.2.0 _131016_1047.apk

Remarque: le nom apk de la version non alignée est toujours celui par défaut.

Fer
la source
Excellente solution. Je l'ai essayé, et c'est parfait pour mon problème. Merci!
Pabel
est-il possible d'utiliser la même approche dans Xamarin Studio?
Alessandro Caliaro
Ce serait génial si c'était possible, mais je commence en ce moment un cours Xamarin et je n'ai toujours pas assez de pratique pour savoir si c'est possible ou non. Je vais poser cette question et revenir ici.
Fer
Commentaire du professeur du cours: "il existe une option où vous pouvez utiliser des commandes pour changer le nom des fichiers générés". Par conséquent, l'approche à utiliser à partir de Xamarin doit être différente de celle que j'ai écrite pour Android Studio, désolé.
Fer
3
Pour résoudre l'erreur Impossible de définir la valeur de la propriété en lecture seule 'outputFile' - comme mentionné dans un commentaire précédent pour avoir à "changer eachen allet output.outputFileen outputFileName" - cet article fournit quelques détails à ce sujet: stackoverflow.com/a/44265374/2162226
Gene Bo
19

Pour résumer, pour ceux qui ne savent pas comment importer un package dans build.gradle(comme moi), utilisez ce qui suit 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")) 
        }
    }       
}

===== MODIFIER =====

Si vous définissez votre versionCodeet versionNamedans votre build.gradlefichier comme ceci:

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

Vous devriez le définir comme ceci:

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


====== MODIFIER avec Android Studio 1.0 ======

Si vous utilisez Android Studio 1.0, vous obtiendrez une erreur comme celle-ci:

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

Vous devriez changer la build.Typespièce en ceci:

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
la source
Cela fonctionne très bien. Cependant, puisque j'incrémente ma version manifeste dans la version gradle, cela créera un APK avec la valeur la plus ancienne (pré-incrémentation). Un moyen de s'assurer que cela prend effet après que le script gradle incrémente le numéro de version?
Guy
1
@Guy Désolé a pris si longtemps. J'ai édité la réponse, voyez si cela peut résoudre votre problème.
Wesley le
17

Si vous ne spécifiez pas versionName dans le bloc defaultConfig, defaultConfig.versionNamecela entraîneranull

pour obtenir versionName à partir du manifeste, vous pouvez écrire le code suivant dans build.gradle:

import com.android.builder.DefaultManifestParser

def manifestParser = new DefaultManifestParser()
println manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile)
Arkadiusz Konior
la source
7
Je pense qu'avec les versions ultérieures de gradle, c'est maintenant com.android.builder.core.DefaultManifestParser
Ryan S
8

Dans mon cas, je voulais juste trouver un moyen d'automatiser la génération de différents apknoms releaseet debugvariantes. J'ai réussi à le faire facilement en mettant cet extrait de code en tant qu'enfant de 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)
    }
}

Pour le nouveau plugin Android gradle 3.0.0, vous pouvez faire quelque chose comme ça:

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

Cela produit quelque chose comme: My_nice_name_3.2.31_dbg.apk

yshahak
la source
6

Une autre alternative consiste à utiliser ce qui suit:

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
}

Cela définira "appname-1.0.0" sur toutes vos sorties apk.

Marco RS
la source
Désolé ne fonctionne pas (plus): No such property: archivesBaseName for class: org.gradle.api.internal.project.DefaultProject_Decorated
Martin
Quelle version de gradle utilisez-vous?
Marco RS
6

6e année et plus

J'utilise maintenant ce qui suit dans Android Studio 4.0 et 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

La syntaxe a un peu changé dans Gradle 4 (Android Studio 3+) (de output.outputFileà outputFileName, l'idée de cette réponse est maintenant:

android {
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def newName = outputFileName
            newName.replace(".apk", "-${variant.versionName}.apk")
            outputFileName = new File(newName)
        }
    }
}
PHPirate
la source
Une idée de comment résoudre ce problème pour Gradle 6?
spartygw
@spartygw Mise à jour de la réponse
PHPirate
5

La bonne façon de renommer apk, selon @Jon answer

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

Ou une autre façon d'obtenir les mêmes résultats avec

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
la source
Gentil à ce sujet! J'aime mieux cela que d'autres façons dont je le fais actuellement.
Droid Chris
3

Il existe de nombreuses réponses correctes soit dans leur intégralité, soit après quelques modifications. Mais je vais quand même ajouter le mien car j'avais le problème avec tous parce que j'utilisais des scripts pour générer dynamiquement VersionName et VersionCode en m'accrochant à la preBuildtâche.

Si vous utilisez une approche similaire, c'est le code qui fonctionnera:

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

Pour expliquer: Puisque je remplace le code et le nom de la version dans la première action de, preBuildje dois ajouter le changement de nom du fichier à la fin de cette tâche. Donc ce que gradle fera dans ce cas est:

Injecter le code / le nom de la version-> faire des actions de pré-construction -> remplacer le nom pour apk

Igor Čordaš
la source
Où définissez-vous les variables versionCode et versionName générées?
Mars
Si je me souviens bien, cela a été fait dans notre plugin gradle personnalisé. Son exécution a été appelée comme dernière action de la tâche preBuild.
Igor Čordaš
2
    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            output.outputFileName = output.outputFileName.replace(".apk", "-${variant.versionName}.apk")
        }
    }
il est temps
la source
Bien que cet extrait de code puisse résoudre la question, inclure une explication contribue vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondez à la question aux lecteurs à l'avenir, et que ces personnes pourraient ne pas connaître les raisons de votre suggestion de code.
Rosário Pereira Fernandes
1

Dans mon cas, je résous cette erreur de cette façon

ajouter un SUFFIXE à la version de débogage, dans ce cas j'ajoute le texte "-DEBUG" à mon déploiement de débogage

 buildTypes {
        release {

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


        }
        debug {

            defaultConfig {
                debuggable true

                versionNameSuffix "-DEBUG"
            }
        }
    }
exequielc
la source
Cela ne change pas le nom du fichier APK.
Tom
1
C'est un bon conseil, en fait. Pas dans la bonne question, mais la bonne. Où puis-je en savoir plus? Est-il possible d'utiliser versionNameSuffixbasé sur la branche GIT? Par exemple, si ce n'est pas sur "master", ayez toujours un suffixe, même s'il s'agit d'une version
finale
0

Pour les dernières versions de Gradle, vous pouvez utiliser l'extrait suivant:

Définissez d'abord l'emplacement du manifeste de votre application

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

Et plus tard dans 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"))
    }
}

Ajustez si vous avez différents manifestes par type de build. mais depuis que j'ai le seul - fonctionne parfaitement pour moi.

Alfishe
la source
est-il possible d'ajouter une chaîne d'un fichier de classe au nom apk ??
Upendra Shah
0

Depuis Android Studio 1.1.0, j'ai trouvé que cette combinaison fonctionnait dans le corps Android du build.gradlefichier. C'est si vous ne pouvez pas comprendre comment importer les données du fichier manifeste xml. J'aimerais qu'il soit plus pris en charge par Android Studio, mais jouez simplement avec les valeurs jusqu'à ce que vous obteniez la sortie de nom apk souhaitée:

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
la source