Автоматическое увеличение кода версии в приложении для Android

Есть ли способ автоматически увеличивать код версии каждый раз, когда вы создаете приложение Android в Eclipse?

В соответствии с http://developer.android.com/guide/publishing/versioning.html вам нужно вручную увеличить код своей версии в AndroidManifest.xml.

Я понимаю, вам нужно запустить script перед каждой сборкой, которая будет, например. проанализируйте файл AndroidManifest.xml, найдите номер версии, увеличьте его и сохраните файл до начала сборки. Однако я не мог узнать, как и если Eclipse поддерживает сценарии запуска до/после сборки.

Я нашел эту статью о настройке ant builder, но это не совсем о Android, и я боюсь, что это слишком сильно испортит предопределенные шаги здания для Android?

Должна быть общей проблемой, как вы ее решили?

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

Ответ 1

Итак, я вижу это так:

В зависимости от статьи, которую вы представляете, используйте ant для этих задач (целей?).

  • проанализировать манифест (проанализировать XML)
  • получить декларацию формы старой версии и увеличить ее/получить версию из репо
  • сохранить новую версию в манифесте
  • создать приложение для Android.

Но в моем случае я обычно заполняю это поле по значению на основе изменения тега при развертывании или распространении приложения.

Ответ 2

Я сделал это. И вот как я сделал это для следующего парня (используя Eclipse):

1) Создайте исполняемый файл внешней консоли, который собирается записать код новой версии в AndroidManifest.xml: (мой находится на С#)

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

в стороне: любой c-sharp компилятор может создать это приложение, вам не нужна Visual Studio или даже Windows

  • Если у вас его еще нет, установите .NET runtime (Mono будет работать, ссылка) (ссылка на MS.NET framework 2.0, 2.0 - самая маленькая загрузка, любая версия >= 2.0 в порядке)
  • скопируйте этот код в файл *.cs (я назвал mine: AndroidAutoIncrementVersionCode.cs)
  • откройте командную строку и перейдите туда, где вы создали файл *.cs
  • создайте файл с помощью этой команды (в Windows, аналогичной для Mono, но измените путь к компилятору): c:\Windows\Microsoft.NET\Framework\v2.0.50727\csc AndroidAutoIncrementVersionCode.cs (см.: . NET или Mono для подробнее)
  • congrats, вы просто создали приложение С# без каких-либо инструментов, оно должно было сгенерировать AndroidAutoIncrementVersionCode.exe в том же каталоге автоматически

    ** пробег может различаться, пути могут быть разными, не требуется покупка, void, где запрещено, я добавил это, потому что С# является удивительным, и люди ошибочно полагают, что он имеет блокировку MS, вы могли бы просто перевести это на другой язык (но я не собираюсь делать это для вас;). кстати, любая версия любого компилятора .NET будет работать, я адаптировал код для наименьшего общего знаменателя... *

конец >

2) Запустите исполняемый файл во время процесса сборки: a) Перейдите к свойствам проекта

go to project properties

b) В свойствах перейдите к "Строителям" → "Создать..."

Eclipse properties screen

c) Выберите "Программа"

choose program

d) На вкладке "Главная" выберите расположение программы (я также установил рабочий каталог в безопасное состояние) и дайте ему имя, если хотите.

edit configuration - main

e) На вкладке "Обновить" выберите параметр "Обновить ресурсы после завершения" и "Выбранный ресурс" - это обновит манифест после его записи.

edit configuration - refresh

f) На вкладке "Параметры сборки" вы можете отключить "Allocate Console", так как у вас нет ввода и вывода, а затем выберите только "Во время ручных сборок" и "Во время автоматической сборки" снимите флажок "После очистки", если это проверено. Затем выберите "Укажите рабочий набор релевантных ресурсов" и нажмите кнопку "Укажите ресурсы...". В диалоговом окне "Изменить рабочий набор" найдите файл "AndroidManifest.xml" в диалоговом окне и проверьте его, затем нажмите "Готово"

edit configuration - build optionsedit working set

f) Теперь нажмите "ОК" внутри "Редактировать диалог конфигурации" и в свойствах вашего приложения, выберите вновь созданный строитель и нажмите "Вверх", пока он не окажется в верхней части списка, таким образом, auto increment запускается первым и не запускает случайные состояния синхронизации или перестройки. После того, как новый создатель, который вы создали, находится в верхней части списка, нажмите "ОК", и вы закончите.

edit configuration - hit okenter image description here

Ответ 3

Эта оболочка script, подходящая для систем * nix, устанавливает код версии и последний компонент versionName в текущую ревизию subversion. Я использую Netbeans с NBAndroid, и я называю это script из target -pre-compile в custom_rules.xml.

Сохраните этот script в файле incVersion в том же каталоге, что и AndroidManifest.xml, сделайте его выполнимым: 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

Создайте или отредактируйте custom_rules.xml и добавьте следующее:

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

Итак, если моя текущая версия svn - 82, я получаю это в AndroidManifest.xml:

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

Когда я хочу выпустить новую версию, я обычно обновляю первые части versionName, но даже если я забуду, последняя часть versionName (которая отображается в моей активной активности) всегда скажет мне, что svn ее переделает был построен из. Кроме того, если я не проверял изменения, номер версии будет 82M, а versionName будет примерно как 2.1.82M.

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

Ответ 4

FWIW, я смог обновить значение версии сборки в шести строках 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() )

Ответ 5

Основываясь на ответе Чарльза, следующий шаг увеличивает существующую версию сборки:

#!/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)

Ответ 6

Receipe:

Чтобы автоматически использовать атрибут android: versionCode элемента манифеста в AndroidManifest.xml, установленном на текущее время (из эпохи в секундах, полученное из оболочки unix) каждый раз, когда вы запускаете сборку, добавьте ее в свою цель -pre-build Файл custom_rules.xml для 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>

Тест подтверждения:

Получить атрибут versionCode сгенерированного файла apk, используя следующую команду оболочки из каталога проектов Android:

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

и сравните его с текущей датой, возвращаемой командой оболочки: date +%s Разница должна равняться периоду времени в секундах между двумя вышеуказанными шагами подтверждения.

Преимущества такого подхода:

  • Независимо от того, запущена ли сборка из командной строки или Eclipse, она обновит версию.
  • Код версии гарантированно будет уникальным и увеличится для каждой сборки
  • Код версии может быть преобразован в обратном порядке в приблизительное время сборки, если вам это нужно
  • Вышеупомянутый script заменяет любое текущее значение versionCode, даже 0, и не требует наличия держателя макроса (например, -build_id-).
  • Поскольку значение обновляется в файле AndroidManifest.xml, вы можете проверить его на управление версиями и сохранить фактическое значение, а не некоторый макрос (например, -build_id -).

Ответ 7

Основываясь на Rocky answer Я увеличил этот python script немного, чтобы увеличить также versionCode, работает для меня на Eclipse (интегрирован как ckozl great tutorial) и 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)

также не забудьте chmod +x autoincrement.py и убедитесь, что у вас есть правильный путь к python в первой строке (в зависимости от вашей среды), поскольку sulai указал из

Ответ 8

Я сделал что-то подобное, но написал его как приложение Desktop AIR вместо некоторого внешнего С# (не чувствовал себя установкой другой системы сборки). Создайте это приложение Flex/ActionScript и измените путь к вашему файлу, создайте его как автономное настольное приложение. Он перезаписывает часть 1.2.3 вашего файла.

    <?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 (e.g., 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>

Ответ 9

Я смог выработать свое собственное решение из приведенной информации. В случае, если это полезно для кого-то, это мой bash script для обновления атрибутов versionCode и versionName при использовании GIT VCS в Linux.

My script для редактирования файла AndroidManifest.xml выглядит следующим образом:

#/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

Он анализирует файл шаблона (AndroidManifest.template.xml) и заменяет строки "__VERSION__" и "__CODE__" более подходящими значениями:

  • "__ CODE__" заменяется счетчиком количества тегов в репозитории GIT, который начинается с одного строчного V и сопровождается последовательностью цифр и точек. Это похоже на большинство строк версии: "v0.5", "v1.1.4" и т.д.
  • "__ VERSION__" заменяется комбинацией вывода команды "git описать" и, если не "чистой" сборки, веткой, на которой она была построена.

Под "чистой" сборкой я подразумеваю, что все компоненты находятся под контролем версий, а их последняя фиксация отмечена. "git описать --dirty" сообщит номер версии на основе последнего доступного аннотированного тега в вашей последней фиксации в текущей ветке. Если с этого тега есть коммиты, сообщается количество этих коммитов, как сокращенное имя объекта вашего последнего коммита. Параметр "--dirty" добавит "-dirty" к вышеуказанной информации, если какие-либо файлы изменены, которые находятся под управлением версиями, были изменены.

Итак, AndroidManifest.xml больше не должен находиться под управлением версиями, и вы должны только отредактировать файл AndroidManifest.template.xml. Начало вашего файла AndroidManifest.template.xml выглядит примерно так:

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

Надеюсь, что это кому-то полезно

Ответ 10

Все кредиты идут на ckoz, но я отладил свою собственную реализацию в С#. Я думаю, что это немного быстрее и не есть ошибки, потому что, если что-то пойдет не так, возможно, что-то неправильно настроено, и я должен знать об этом.

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

Ответ 11

Для тех, кто находится на OSX и хочет использовать Python, но не потеряет форматирование XML, которое происходит при синтаксическом анализе с помощью парсера python XML, здесь находится python script, который будет делать инкрементное на основе регулярного выражения, который сохраняет форматирование:

#!/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()

Этот код был основан на ответе @ckozl, как раз в python, поэтому для этого вам не нужно создавать исполняемый файл. Просто назовите script autoincrement.py, поместите его в ту же папку с файлом manifest.xml, а затем выполните шаги, описанные выше ckozl!

Ответ 12

Если вы хотите обновить AndroidManifest.xml, чтобы использовать определенный номер версии, возможно, из системы сборки, то вы можете использовать проект, который я просто нажал на GitHub: https://github.com/bluebirdtech/AndroidManifestVersioner

Это базовое приложение командной строки .NET, использование:

AndroidManifestVersioner <path> <versionCode> <versionName>.

Спасибо другим плакатам за их код.

Ответ 13

Вот версия Java для того, что стоит. Также обрабатывает несколько манифестаций.

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

Ответ 14

Если вы используете gradle, то в build.gradle вы можете использовать специальные versionName и versionCode. Вы можете использовать git commit count как увеличивающееся число для идентификации сборки.

Вы также можете использовать эту библиотеку: https://github.com/rockerhieu/Versionberg.