Автоинкрементный код версии в приложении Android - PullRequest
62 голосов
/ 20 июля 2011

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

Согласно http://developer.android.com/guide/publishing/versioning.html, вам придется вручную увеличивать код версии в AndroidManifest.xml.

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

Я нашел эту статью о настройке Ant Builder, но это не совсем об Android иБоюсь, это слишком сильно испортит предопределенные этапы сборки для Android?

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

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

Ответы [ 14 ]

112 голосов
/ 16 ноября 2011

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

1) Создайте исполняемый файл внешней консоли, который собирается записать код новой версии в AndroidManifest.xml: (мой находится в 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 { }
        }
    }
}

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

  1. если у вас его еще нет, установите .NET runtime ( Mono будет работать, ссылка ) ( ссылка на MS .NET Framework 2.0, 2.0 - это самая маленькая загрузка, любая версия> = 2.0все в порядке )
  2. скопируйте этот код в файл *.cs (я назвал мой: AndroidAutoIncrementVersionCode.cs)
  3. откройте командную строку и перейдите туда, где вы сделали *.cs file
  4. создайте файл с помощью этой команды (в Windows аналогично Mono, но измените путь к компилятору): c:\Windows\Microsoft.NET\Framework\v2.0.50727\csc AndroidAutoIncrementVersionCode.cs (см .: .NET или Mono для получения дополнительной информации)
  5. поздравляю, вы только что создали приложение C # без каких-либо инструментов, оно должно было сгенерировать AndroidAutoIncrementVersionCode.exe в том же прямомory автоматически

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

end aside

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

go to project properties

b) В свойствах перейдите к «Строителям» -> «Новый ...»

Eclipse properties screen

в) Выберите «Программа»

choose program

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

edit configuration - main

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

edit configuration - refresh

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

edit configuration - build options edit working set

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

edit configuration - hit ok enter image description here

9 голосов
/ 18 октября 2012

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

Сохраните этот скрипт в файле с именем 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.Очень полезно при поиске ошибок в других версиях.

7 голосов
/ 01 августа 2012

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() )
6 голосов
/ 12 сентября 2012

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

#!/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)
4 голосов
/ 20 июля 2011

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

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

  1. Манифест разбора (разбора XML)
  2. получить манифест старой версии и увеличить его / получить версию из репозитория
  3. сохранить новую версию в манифесте
  4. сборка приложения для Android.

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

3 голосов
/ 16 сентября 2014

Receipe:

Чтобы автоматически устанавливать для атрибута android: versionCode элемента manifest в 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 Разница должна равняться периоду времени в секундахмежду двумя шагами подтверждения выше.

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

  1. Независимо от того, запущена ли сборка из командной строки или Eclipse, она обновитversionCode.
  2. VersionCode гарантированно является уникальным и увеличивается для каждой сборки
  3. VersionCode может быть обратным-инжиниринг в приблизительное время сборки, если вам это нужно
  4. Приведенный выше скрипт заменяет любое текущее значение versionCode, даже 0 и не требует заполнителя макроса (например, -build_id-).
  5. Поскольку значение обновляется в файле AndroidManifest.xml, вы можете включить его в систему контроля версий, и оно сохранит фактическое значение, а не какой-либо макрос (например, -build_id -).
2 голосов
/ 09 октября 2013

Опираясь на Ответ Рокки Я немного улучшил этот скрипт на Python, чтобы увеличить также 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

1 голос
/ 08 января 2014

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

#!/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, поэтому вам не нужно создавать исполняемый файл для этого. Просто назовите скрипт autoincrement.py, поместите его в ту же папку, где находится файл manifest.xml, а затем выполните действия, которые ckozl описал выше!

1 голос
/ 27 декабря 2012

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

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);
                        }
                    }
                }
            }
        }
    }
}
1 голос
/ 13 ноября 2012

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

Мой скрипт для редактирования файла 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 description» и, еслине "чистая" сборка, а ветвь, на которой она была построена.

Под "чистой" сборкой я подразумеваю тот, где все компоненты находятся под контролем версий, а их последняя фиксация помечена.«git description --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__" >

Надеюсь, это кому-нибудь пригодится

...