Código de la versión de incremento automático en la aplicación para Android

¿Hay una manera de auto-incrementar el código de la versión cada vez que construyes una aplicación de Android en Eclipse?

De acuerdo con http://developer.android.com/guide/publishing/versioning.html , tiene que incrementar manualmente su código de versión en AndroidManifest.xml .

Entiendo, tienes que ejecutar un script antes de cada compilación que, por ejemplo, analizar el archivo AndroidManifest.xml, encontrar el número de versión, incrementarlo y guardar el archivo antes de que se inicie la compilación. Sin embargo, no pude averiguar cómo y si Eclipse soporta scripts runnings antes / después de las compilaciones.

He encontrado este artículo sobre la configuración de hormigas constructor, pero esto no es exactamente sobre Android y me temo que esto va a estropear demasiado los pasos de construcción predefinidos para Android?

Debe ser un problema común, ¿cómo lo resolvió?

Bueno, se puede hacer esto manualmente, pero tan pronto como se olvide de hacer esta tarea, obtendrá diferentes versiones con el mismo número y el versionado todo tiene poco sentido.

Así que lo veo así:

Dependiendo del artículo que presente, utilice ant para estas tareas (targets?).

  1. Parse Manifest (analizar XML)
  2. Obtener versión antigua formulario manifiesto y aumentarlo / obtener la versión de repo
  3. Almacenar nueva versión en el manifiesto
  4. Construir la aplicación de Android.

Pero im mi caso por lo general llenar este campo por el valor basado en la revisión de la etiqueta cuando implemento o distribuir la aplicación.

Logré esto. Y aquí es cómo lo hice para el próximo chico (usando Eclipse):

1) Crear un ejecutable de consola externa que va a escribir un nuevo código de versión en el AndroidManifest.xml: (el mío está en C #)

 using System.IO; using System.Text.RegularExpressions; namespace AndroidAutoIncrementVersionCode { class Program { static void Main(string[] args) { try { string FILE = @"AndroidManifest.xml"; string text = File.ReadAllText(FILE); Regex regex = new Regex(@"(?<A>android:versionCode="")(?<VER>\d+)(?<B>"")", RegexOptions.IgnoreCase); Match match = regex.Match(text); int verCode = int.Parse(match.Groups["VER"].Value) + 1; string newText = regex.Replace(text, "${A}" + verCode + "${B}", 1); File.WriteAllText(FILE, newText); } catch { } } } } 

Aparte: cualquier compilador c-sharp puede construir esta aplicación, no es necesario que Visual Studio ni Windows

  1. Si no lo tienes ya, instale .NET runtime ( Mono funcionará, link ) ( enlace a .NET Framework 2.0, 2.0 es la más pequeña descarga, cualquier versión> = 2.0 está bien )
  2. Copiar este código a un archivo *.cs (i named mine: AndroidAutoIncrementVersionCode.cs )
  3. Abra una línea de comandos y navegue hasta donde ha creado su archivo *.cs
  4. Construya el archivo usando este comando (en Windows, similar para Mono pero cambie la ruta al compilador): c:\Windows\Microsoft.NET\Framework\v2.0.50727\csc AndroidAutoIncrementVersionCode.cs (consulte: .NET o Mono para más información)
  5. Congrats, que acaba de construir una aplicación C # sin herramientas, debería haber generado AndroidAutoIncrementVersionCode.exe en el mismo directorio de forma automática

    ** el kilometraje puede variar, las rutas pueden ser diferentes, no se requiere compra, anular donde está prohibido, he añadido esto porque C # es impresionante, y la gente piensa erróneamente que tiene bloqueo de MS, usted podría traducir esto fácilmente a otro idioma (pero No voy a hacer eso por ti;). Por cierto cualquier versión de cualquier compilador .NET funcionará, adapté el código para el mínimo denominador común … *

Dejar de lado

2) Ejecutar el ejecutable durante el proceso de construcción: a) Ir a las propiedades del proyecto

Ir a las propiedades del proyecto

B) En las propiedades, vaya a "Constructores" -> "Nuevo …"

Pantalla de propiedades de Eclipse

C) Elija "Programa"

Elija el programa

D) En la pestaña "Principal" seleccione la ubicación del programa (también configuro el directorio de trabajo para que sea seguro) y dale un nombre si lo desea.

Editar configuración - principal

E) En la pestaña "Actualizar", seleccione la opción "Actualizar recursos al finalizar" y "El recurso seleccionado" – esto actualizará el manifiesto después de escribirlo.

Editar configuración - actualizar

F) En la pestaña "Opciones de compilación", puede desactivar "Asignar consola", ya que no tiene entrada y salida y luego seleccionar sólo "Durante las compilaciones manuales" y "Durante las compilaciones automáticas", desmarque "Después de una limpieza" si está marcada. A continuación, seleccione "Especificar un conjunto de recursos relevantes" y haga clic en el botón "Especificar recursos …". En el cuadro de diálogo "Editar conjunto de trabajo", busque el archivo "AndroidManifest.xml" en el diálogo y compruébelo, luego pulse "Finalizar"

Editar configuración - opciones de construcciónEditar conjunto de trabajo

F) Ahora haz clic en "Aceptar" en el cuadro de diálogo "Editar configuración" y en las propiedades de tu aplicación, selecciona el constructor recién creado y sigue haciendo clic en "Arriba" hasta que esté en la parte superior de la lista. Primero, y no desencadena estados fuera de sincronía o reconstrucciones accidentales. Una vez que el nuevo constructor que has hecho está en la parte superior de la lista, haz clic en "Aceptar" y terminaste.

Editar la configuración - pulse okIntroduzca aquí la descripción de la imagen

Este script de shell, adecuado para los sistemas * nix, establece el versionCode y el último componente de versionName en la revisión de subversión actual. Estoy usando Netbeans con NBAndroid y llamo a este script desde el destino -pre-compile en custom_rules.xml.

Guarde este script en un archivo llamado incVersion en el mismo directorio que AndroidManifest.xml, haga que sea ejecutable: chmod +x incVersion

 manf=AndroidManifest.xml newverfull=`svnversion` newvers=`echo $newverfull | sed 's/[^0-9].*$//'` vers=`sed -n '/versionCode=/s/.*"\([0-9][0-9]*\)".*/\1/p' $manf` vername=`sed -n '/versionName=/s/.*"\([^"]*\)".*/\1/p' $manf` verbase=`echo $vername | sed 's/\(.*\.\)\([0-9][0-9]*\).*$/\1/'` newvername=$verbase$newverfull sed /versionCode=/s/'"'$vers'"'/'"'$newvers'"'/ $manf | sed /versionName=/s/'"'$vername'"'/'"'$newvername'"'/ >new$manf && cp new$manf $manf && rm -f new$manf echo versionCode=$newvers versionName=$newvername 

Cree o edite custom_rules.xml y añada esto:

 <?xml version="1.0" encoding="UTF-8"?> <project name="custom_rules"> <xmlproperty file="AndroidManifest.xml" prefix="mymanifest" collapseAttributes="true"/> <target name="-pre-compile"> <exec executable="./incVersion" failonerror="true"/> </target> </project> 

Así que si mi revisión svn actual es de 82, termino con esto en AndroidManifest.xml:

 android:versionCode="82" android:versionName="2.1.82"> 

Cuando quiero publicar una nueva versión, normalmente actualizaré las primeras partes de versionName, pero incluso si me olvido, la última parte de versionName (que está expuesta en mi actividad About) siempre me dirá de qué revisión svn fue construida . Además, si no he registrado cambios, el número de revisión será 82M y versionName será algo así como 2.1.82M.

La ventaja de simplemente incrementar el número de versión cada vez que se realiza una compilación es que el número permanece bajo control y puede estar directamente relacionado con una revisión svn específica. Muy útil cuando se investigan errores en la última versión.

FWIW, pude actualizar el valor de versión de compilación en seis líneas de python:

 #!/bin/env python import os from xml.dom.minidom import parse dom1 = parse("AndroidManifest.xml") dom1.documentElement.setAttribute("android:versionName","%build.number%") f = os.open("AndroidManifest.xml", os.O_RDWR) os.write( f, dom1.toxml() ) 

Basándose en la respuesta de Charles , los siguientes incrementos de la versión de compilación existente:

 #!/usr/bin/python from xml.dom.minidom import parse dom1 = parse("AndroidManifest.xml") oldVersion = dom1.documentElement.getAttribute("android:versionName") versionNumbers = oldVersion.split('.') versionNumbers[-1] = unicode(int(versionNumbers[-1]) + 1) dom1.documentElement.setAttribute("android:versionName", u'.'.join(versionNumbers)) with open("AndroidManifest.xml", 'wb') as f: for line in dom1.toxml("utf-8"): f.write(line) 

Recibo:

Para que el atributo androide: versionCode del elemento manifiesto en AndroidManifest.xml se establezca automáticamente en la hora actual (de la época en segundos, obtenida de la shell unix) cada vez que se ejecute una compilación, agregue esto a su destino -pre-build en custom_rules.xml Archivo de Android.

 <target name="-pre-build"> <exec executable="date" outputproperty="CURRENT_TIMESTAMP"> <arg value="+%s"/> </exec> <replaceregex file="AndroidMainfest.xml" match="android:versionCode=.*" replace='android:versionCode="${CURRENT_TIMESTAMP}"' /> </target> 

Prueba de confirmación :

Obtenga el atributo versionCode del archivo apk generado, utilizando el siguiente comando shell del directorio de proyectos de Android:

 $ANDROID_SDK/build-tools/20.0.0/aapt dump badging bin/<YourProjectName>.apk | grep versionCode 

Y compárelo con la fecha actual devuelta por el comando shell: date +%s La diferencia debe ser igual al período de tiempo en segundos entre los dos pasos de confirmación anteriores.

Ventajas de este enfoque:

  1. Independientemente de si la compilación se inicia desde la línea de comandos o Eclipse, se actualizará el versionCode.
  2. El versionCode está garantizado para ser único y creciente para cada compilación
  3. El versionCode puede ser invertido en un tiempo de construcción aproximado si lo necesita
  4. El script anterior reemplaza cualquier valor actual de versionCode, incluso 0 y no requiere un titular de lugar macro (como -build_id-).
  5. Debido a que el valor se actualiza en el archivo AndroidManifest.xml, puede comprobarlo en el control de versiones y conservará el valor real, no alguna macro (como -build_id-).

Basándome en la respuesta de Rocky he mejorado ese script de python un poco para aumentar también versionCode, funciona para mí en Eclipse (integrado como por ckozl gran tutorial ) y Mac OSX

 #!/usr/bin/python from xml.dom.minidom import parse dom1 = parse("AndroidManifest.xml") oldVersion = dom1.documentElement.getAttribute("android:versionName") oldVersionCode = dom1.documentElement.getAttribute("android:versionCode") versionNumbers = oldVersion.split('.') versionNumbers[-1] = unicode(int(versionNumbers[-1]) + 1) dom1.documentElement.setAttribute("android:versionName", u'.'.join(versionNumbers)) dom1.documentElement.setAttribute("android:versionCode", str(int(oldVersionCode)+1)) with open("AndroidManifest.xml", 'wb') as f: for line in dom1.toxml("utf-8"): f.write(line) 

También no se olvide de chmod +x autoincrement.py y asegúrese de que tiene el camino correcto a python en la primera línea (dependiendo de su entorno) como sulai señaló

He hecho algo similar pero lo escribí como una aplicación de Desktop AIR en lugar de algún C # externo (no sentía instalar otro sistema de compilación). Construye esta aplicación de Flex / ActionScript y cambia la ruta a tu archivo, construidla como una aplicación de escritorio independiente. Reescribe la parte 1.2.3 de tu archivo.

  <?xml version="1.0" encoding="utf-8"?> <s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" width="371" height="255" applicationComplete="Init();"> <fx:Declarations> <!-- Place non-visual elements (eg, services, value objects) here --> </fx:Declarations> <fx:Script> <![CDATA[ public function Init():void { import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; var myFile:File = new File("D:\\Dropbox\\Projects\\My App\\src\\Main-app.xml"); var fileStream:FileStream = new FileStream(); fileStream.open(myFile, FileMode.READ); var fileContents:String = fileStream.readUTFBytes(fileStream.bytesAvailable); var startIndex:Number = fileContents.indexOf("<versionNumber>"); var numberIndex:Number = startIndex + 15; var endIndex:Number = fileContents.indexOf("</versionNumber>"); if (startIndex == -1 || endIndex == -1) return; var versionNumber:String = fileContents.substr(numberIndex, endIndex - numberIndex); var versionArr:Array = versionNumber.split("."); var newSub:Number = Number(versionArr[2]); newSub++; versionArr[2] = newSub.toString(); versionNumber = versionArr.join("."); var newContents:String = fileContents.substr(0, startIndex) + "<versionNumber>" + versionNumber + "</versionNumber>" + fileContents.substr(endIndex + 16); fileStream.close(); fileStream = new FileStream(); fileStream.open(myFile, FileMode.WRITE); fileStream.writeUTFBytes(newContents); fileStream.close(); close(); } ]]> </fx:Script> <s:Label x="10" y="116" width="351" height="20" fontSize="17" text="Updating My App Version Number" textAlign="center"/> </s:WindowedApplication> 

Pude elaborar mi propia solución a partir de la información proporcionada. En caso de que sea útil para alguien aquí es mi script bash para actualizar los atributos versionCode y versionName cuando se utiliza el GIT VCS en Linux.

Mi script para editar el archivo AndroidManifest.xml tiene este aspecto:

 #/bin/bash CODE=`git tag | grep -c ^v` NAME=`git describe --dirty` COMMITS=`echo ${NAME} | sed -e 's/v[0-9\.]*//'` if [ "x${COMMITS}x" = "xx" ] ; then VERSION="${NAME}" else BRANCH=" (`git branch | grep "^\*" | sed -e 's/^..//'`)" VERSION="${NAME}${BRANCH}" fi cat AndroidManifest.template.xml \\ | sed -e "s/__CODE__/${CODE}/" \\ -e "s/__VERSION__/${VERSION}/" > AndroidManifest.xml exit 0 

Analiza el archivo de plantilla (AndroidManifest.template.xml) y reemplaza las cadenas "__VERSION__" y "__CODE__" con valores más apropiados:

  • "__CODE__" se sustituye por un recuento del número de etiquetas en el repo de Git que comienza con una sola V en minúscula y es seguido por una secuencia de dígitos y puntos. Esto se parece a la mayoría de la cadena de versión como: "v0.5", "v1.1.4" y así sucesivamente.
  • "__VERSION__" se reemplaza con una combinación de la salida del comando "git describir" y, si no es una compilación "limpia", la rama en la que fue construida.

Por una construcción "limpia" me refiero a uno donde todos los componentes están bajo control de versión y su último compromiso está etiquetado. "Git describe –dirty" informará un número de versión basado en la última etiqueta anotada accesible en su último commit en la rama actual. Si hay confirmaciones desde esa etiqueta, se informa de un recuento de esos commit como es el nombre de objeto abreviado de su último commit. La opción "–dirty" añadirá "-dirty" a la información anterior si se han modificado los archivos que están bajo control de versiones.

Por lo tanto, AndroidManifest.xml ya no debería estar bajo control de versiones, y solo debería editar el archivo AndroidManifest.template.xml. El inicio de tu archivo AndroidManifest.template.xml se parece a esto:

 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.packagename" android:versionCode="__CODE__" android:versionName="__VERSION__" > 

Espero que esto sea útil para alguien

Todo el crédito va a ckoz, pero writed mi propia implementación en c #. Creo que es un poco más rápido y no come errores porque si algo sale mal probablemente algo está mal configurado y debo saber sobre ello.

 namespace AndroidVersionCodeAutoIncrement { using System.IO; using System.Text.RegularExpressions; public class Program { private static readonly Regex VersionCodeRegex = new Regex("android:versionCode=\"(?<version>.*)\"", RegexOptions.Compiled); public static void Main() { using (var manifestFileStream = File.Open("AndroidManifest.xml", FileMode.Open, FileAccess.ReadWrite)) using (var streamReader = new StreamReader(manifestFileStream)) { var manifestFileText = streamReader.ReadToEnd(); var firstMatch = VersionCodeRegex.Match(manifestFileText); if (firstMatch.Success) { int versionCode; var versionCodeValue = firstMatch.Groups["version"].Value; if (int.TryParse(versionCodeValue, out versionCode)) { manifestFileText = VersionCodeRegex.Replace(manifestFileText, "android:versionCode=\"" + (versionCode + 1) + "\"", 1); using (var streamWriter = new StreamWriter(manifestFileStream)) { manifestFileStream.Seek(0, SeekOrigin.Begin); streamWriter.Write(manifestFileText); manifestFileStream.SetLength(manifestFileText.Length); } } } } } } } 

Para aquellos que están en OSX y quieren usar Python, pero no perder el formato XML que cuando el análisis se realiza por el parser XML python sucede, aquí es un script python que hará el incremental basado en la expresión regular, que mantiene el formato:

 #!/usr/bin/python import re f = open('AndroidManifest.xml', 'r+') text = f.read() result = re.search(r'(?P<groupA>android:versionName=")(?P<version>.*)(?P<groupB>")',text) version = str(float(result.group("version")) + 0.01) newVersionString = result.group("groupA") + version + result.group("groupB") newText = re.sub(r'android:versionName=".*"', newVersionString, text); f.seek(0) f.write(newText) f.truncate() f.close() 

El código se basa en @ckozl respuesta, sólo se hizo en python por lo que no es necesario crear un ejecutable para esto. Simplemente nombre el script autoincrement.py, colócalo en la misma carpeta con el archivo manifest.xml y luego haz los pasos que ckozl describió arriba!

Si desea actualizar el archivo AndroidManifest.xml para usar un número de versión específico, tal vez desde un sistema de compilación, puede utilizar el proyecto que acabo de enviar a GitHub: https://github.com/bluebirdtech/AndroidManifestVersioner

Es una aplicación de línea de comandos .NET básica, uso:

 AndroidManifestVersioner <path> <versionCode> <versionName>. 

Gracias a otros carteles por su código.

Aquí está la versión de Java para lo que vale la pena. Manejo también de múltiples manifiestos.

 String directory = "d:\\Android\\workspace\\"; String[] manifests = new String[] { "app-free\\AndroidManifest.xml", "app-donate\\AndroidManifest.xml", }; public static void main(String[] args) { new version_code().run(); } public void run() { int I = manifests.length; for(int i = 0; i < I; i++) { String path = directory + manifests[i]; String content = readFile(path); Pattern versionPattern = Pattern.compile( "(.*android:versionCode=\")([0-9]+)(\".*)", Pattern.DOTALL ); Matcher m = versionPattern.matcher(content); if (m.matches()) { int code = Integer.parseInt( m.group(2) ) + 1; System.out.println("Updating manifest " + path + " with versionCode=" + code); String newContent = m.replaceFirst("$1" + code + "$3"); writeFile(path + ".original.txt", content); writeFile(path, newContent); } else { System.out.println("No match to update manifest " + path); } } } 

Si estás usando gradle entonces puedes versionName específico y versionCode muy fácil en build.gradle . Puede utilizar git commit count como un número creciente para identificar la generación.

También puede utilizar esta biblioteca: https://github.com/rockerhieu/Versionberg .

  • Desarrollando para Android en Eclipse: R.java no se está regenerando
  • Depurar una aplicación ya en ejecución sin reiniciarla
  • Extraño error en R.java, incluso después de limpiar el proyecto: "Los subrayados sólo se pueden usar con el nivel de fuente 1.7 o superior"
  • Trabajar con NDK en Eclipse
  • Incluyendo Google Play Downloader Library | Biblioteca de expansión de archivos APK
  • ¿No se pudo analizar la salida de 'versión de adb'?
  • Eclipse está diciendo "Actualizar Android Developer Toolkit"
  • Encontrar el número total de API que se utilizan en un código fuente de la aplicación de Android?
  • Eclipse: ¿Dónde poner NDK referencia? Falta el desarrollo nativo?
  • Java.lang.ClassCastException: android.widget.TextView no se puede emitir
  • Cómo crear líneas en xml
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.