Создать варианты номера версии для info.plist с помощью #define и clang?
Несколько лет назад при компиляции с GCC следующие определения в файле #include .h можно было предварительно обработать для использования в info.plist:
#define MAJORVERSION 2
#define MINORVERSION 6
#define MAINTVERSION 4
<key>CFBundleShortVersionString</key> <string>MAJORVERSION.MINORVERSION.MAINTVERSION</string>
... который превратился бы в "2.6.4". Это сработало, потому что GCC поддерживал флаг "-traditional". (см. Техническую ноту TN2175 файлы Info.plist в Xcode, используя препроцессор C, в разделе "Устранение пробелов между токенами в процессе расширения макроса")
Однако перемотка вперед до 2016 года и Clang 7.0.2 (Xcode 7.2.1), по-видимому, не поддерживают ни "-traditional", ни "-traditional-cpp" (или поддерживают его должным образом), что приводит к следующей строке:
"2 . 6 . 4"
(см. Ошибка 12035 - Препроцессор вставляет пробелы в расширениях макросов, комментарий 4)
Поскольку существует так много разных вариантов (CFBundleShortVersionString, CFBundleVersion, CFBundleGetInfoString), было бы неплохо обойти эту проблему лягушек, определить их один раз и объединить / связать части вместе. Какова общепринятая модель для этого сейчас? (В настоящее время я работаю на MacOS, но тот же шаблон будет работать для IOS)
2 ответа
Вот скрипт Python, который я использую для увеличения номера сборки при обнаружении изменения исходного кода и обновления одного или нескольких Info.plist
файлы в проекте.
Он был создан, чтобы решить проблему, поднятую в этом вопросе, который я задал некоторое время назад.
Вам нужно создать buildnum.ver
файл в дереве исходного кода, который выглядит следующим образом:
version 1.0
build 1
(вам нужно будет вручную увеличить version
когда достигнуты определенные вехи проекта, но buildnum
увеличивается автоматически).
ПРИМЕЧАНИЕ расположение .ver
файл должен находиться в корне дерева исходного кода (см. SourceDir
ниже), так как этот скрипт будет искать измененные файлы в этом каталоге. Если они найдены, номер сборки увеличивается. Изменено означает, что исходные файлы изменяются после .ver
Файл был последний раз обновлен.
Затем создайте новую цель XCode для запуска внешнего инструмента сборки и запустите что-то вроде:
tools/bump_buildnum.py SourceDir/buildnum.ver SourceDir/Info.plist
(заставить его работать в ${PROJECT_DIR}
)
и затем сделайте все фактические цели XCode зависимыми от этой цели, чтобы она выполнялась до того, как будет построена любая из них.
#!/usr/bin/env python
#
# Bump build number in Info.plist files if a source file have changed.
#
# usage: bump_buildnum.py buildnum.ver Info.plist [ ... Info.plist ]
#
# andy@trojanfoe.com, 2014.
#
import sys, os, subprocess, re
def read_verfile(name):
version = None
build = None
verfile = open(name, "r")
for line in verfile:
match = re.match(r"^version\s+(\S+)", line)
if match:
version = match.group(1).rstrip()
match = re.match(r"^build\s+(\S+)", line)
if match:
build = int(match.group(1).rstrip())
verfile.close()
return (version, build)
def write_verfile(name, version, build):
verfile = open(name, "w")
verfile.write("version {0}\n".format(version))
verfile.write("build {0}\n".format(build))
verfile.close()
return True
def set_plist_version(plistname, version, build):
if not os.path.exists(plistname):
print("{0} does not exist".format(plistname))
return False
plistbuddy = '/usr/libexec/Plistbuddy'
if not os.path.exists(plistbuddy):
print("{0} does not exist".format(plistbuddy))
return False
cmdline = [plistbuddy,
"-c", "Set CFBundleShortVersionString {0}".format(version),
"-c", "Set CFBundleVersion {0}".format(build),
plistname]
if subprocess.call(cmdline) != 0:
print("Failed to update {0}".format(plistname))
return False
print("Updated {0} with v{1} ({2})".format(plistname, version, build))
return True
def should_bump(vername, dirname):
verstat = os.stat(vername)
allnames = []
for dirname, dirnames, filenames in os.walk(dirname):
for filename in filenames:
allnames.append(os.path.join(dirname, filename))
for filename in allnames:
filestat = os.stat(filename)
if filestat.st_mtime > verstat.st_mtime:
print("{0} is newer than {1}".format(filename, vername))
return True
return False
def upver(vername):
(version, build) = read_verfile(vername)
if version == None or build == None:
print("Failed to read version/build from {0}".format(vername))
return False
# Bump the version number if any files in the same directory as the version file
# have changed, including sub-directories.
srcdir = os.path.dirname(vername)
bump = should_bump(vername, srcdir)
if bump:
build += 1
print("Incremented to build {0}".format(build))
write_verfile(vername, version, build)
print("Written {0}".format(vername))
else:
print("Staying at build {0}".format(build))
return (version, build)
if __name__ == "__main__":
if os.environ.has_key('ACTION') and os.environ['ACTION'] == 'clean':
print("{0}: Not running while cleaning".format(sys.argv[0]))
sys.exit(0)
if len(sys.argv) < 3:
print("Usage: {0} buildnum.ver Info.plist [... Info.plist]".format(sys.argv[0]))
sys.exit(1)
vername = sys.argv[1]
(version, build) = upver(vername)
if version == None or build == None:
sys.exit(2)
for i in range(2, len(sys.argv)):
plistname = sys.argv[i]
set_plist_version(plistname, version, build)
sys.exit(0)
Во-первых, я хотел бы уточнить, для чего предназначен каждый ключ:
CFBundleShortVersionString
Строка, описывающая выпущенную версию приложения с использованием семантического контроля версий. Эта строка будет отображаться в описании App Store.
CFBundleVersion
Строка, указывающая версию сборки (выпущена или не выпущена). Это строка, но Apple рекомендует использовать цифры.
CFBundleGetInfoString
Кажется устаревшим, так как он больше не указан в справочнике ключей списка свойств информации.
Во время разработки CFBundleShortVersionString
не так часто меняется, и я обычно устанавливаю CFBundleShortVersionString
вручную в Xcode. Единственная строка, которую я регулярно меняю, CFBundleVersion
потому что вы не можете отправить новую сборку в iTunes Connect/TestFlight, если CFBundleVersion
не изменился
Чтобы изменить значение, я использую задачу Rake с PlistBuddy
написать отметку времени (год, месяц, день, час и минута) для CFBundleVersion
:
desc "Bump bundle version"
task :bump_bundle_version do
bundle_version = Time.now.strftime "%Y%m%d%H%M"
sh %Q{/usr/libexec/PlistBuddy -c "Set CFBundleVersion #{bundle_version}" "DemoApp/DemoApp-Info.plist"}
end
Вы можете использовать PlistBuddy, если вам нужно автоматизировать CFBundleShortVersionString
также.