我想在应用程序的设置包中包含应用程序版本和内部修订版,例如1.0.1(r1243)。
Root.plist文件包含这样的片段......
<dict>
<key>Type</key>
<string>PSTitleValueSpecifier</string>
<key>Title</key>
<string>Version</string>
<key>Key</key>
<string>version_preference</string>
<key>DefaultValue</key>
<string>VersionValue</string>
<key>Values</key>
<array>
<string>VersionValue</string>
</array>
<key>Titles</key>
<array>
<string>VersionValue</string>
</array>
</dict>
我想在构建时替换“VersionValue”字符串。
我有一个可以从我的存储库中提取版本号的脚本,我需要的是一种在构建时处理(预处理)Root.plist文件的方法,并替换版本号而不影响源文件
答案 0 :(得分:68)
还有另一种解决方案比以前的任何一种解决方案都简单得多。 Apple在其大多数安装程序中捆绑了一个名为 PlistBuddy 的命令行工具,并将其包含在/usr/libexec/PlistBuddy
的Leopard中。
由于您要替换VersionValue
,假设您将版本值提取到$newVersion
,您可以使用此命令:
/usr/libexec/PlistBuddy -c "Set :VersionValue $newVersion" /path/to/Root.plist
无需使用sed或正则表达式,这种方法非常简单。有关详细说明,请参阅man page。您可以使用PlistBuddy添加,删除或修改属性列表中的任何条目。例如,我的一位朋友使用PlistBuddy在博客上写了incrementing build numbers in Xcode。
注意:如果只提供plist的路径,PlistBuddy会进入交互模式,因此您可以在决定保存更改之前发出多个命令。我绝对建议在你的构建脚本中填充它之前这样做。
答案 1 :(得分:64)
我的懒人的解决方案是从我的应用程序代码更新版本号。你可以在Root.plist中有一个默认(或空白)值,然后在你的启动代码中的某个地方:
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
[[NSUserDefaults standardUserDefaults] setObject:version forKey:@"version_preference"];
唯一的问题是您的应用必须至少运行一次才能使更新版本显示在设置面板中。
你可以进一步理解这个想法,例如,更新你的应用程序启动次数或其他有趣信息的计数器。
答案 2 :(得分:59)
基于@Quinn的回答,这里是我用来完成此过程的完整流程和工作代码。
用以下内容替换内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>Title</key>
<string>About</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>DefaultValue</key>
<string>DummyVersion</string>
<key>Key</key>
<string>version_preference</string>
<key>Title</key>
<string>Version</string>
<key>Type</key>
<string>PSTitleValueSpecifier</string>
</dict>
</array>
<key>StringsTable</key>
<string>Root</string>
</dict>
</plist>
创建运行脚本构建阶段,移至复制捆绑资源阶段之后。添加以下代码:
cd "${BUILT_PRODUCTS_DIR}"
buildVersion=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${INFOPLIST_PATH}" )
/usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:1:DefaultValue $buildVersion" "${WRAPPER_NAME}/Settings.bundle/Root.plist"
将MyAppName替换为您的实际应用名称,并将PreferenceSpecifiers之后的1替换为“设置”中版本条目的索引。上面的Root.plist示例将它放在索引1处。
答案 3 :(得分:17)
使用Ben Clayton的plist https://stackoverflow.com/a/12842530/338986
在Run script
之后添加Copy Bundle Resources
以及以下代码段。
version=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "$PROJECT_DIR/$INFOPLIST_FILE")
build=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$PROJECT_DIR/$INFOPLIST_FILE")
/usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:1:DefaultValue $version ($build)" "$CODESIGNING_FOLDER_PATH/Settings.bundle/Root.plist"
在CFBundleVersion
之外添加CFBundleShortVersionString
。
它发出这样的版本:
写信给
$CODESIGNING_FOLDER_PATH/Settings.bundle/Root.plist
而不是$SRCROOT
中的那个有一些好处。
Settings.bundle
中$SRCROOT
的案例路径。路径可能会有所不同。 在Xcode 7.3.1上进行测试
答案 4 :(得分:12)
基于示例here,这是我用来自动更新设置包版本号的脚本:
#! /usr/bin/env python
import os
from AppKit import NSMutableDictionary
settings_file_path = 'Settings.bundle/Root.plist' # the relative path from the project folder to your settings bundle
settings_key = 'version_preference' # the key of your settings version
# these are used for testing only
info_path = '/Users/mrwalker/developer/My_App/Info.plist'
settings_path = '/Users/mrwalker/developer/My_App/Settings.bundle/Root.plist'
# these environment variables are set in the XCode build phase
if 'PRODUCT_SETTINGS_PATH' in os.environ.keys():
info_path = os.environ.get('PRODUCT_SETTINGS_PATH')
if 'PROJECT_DIR' in os.environ.keys():
settings_path = os.path.join(os.environ.get('PROJECT_DIR'), settings_file_path)
# reading info.plist file
project_plist = NSMutableDictionary.dictionaryWithContentsOfFile_(info_path)
project_bundle_version = project_plist['CFBundleVersion']
# print 'project_bundle_version: '+project_bundle_version
# reading settings plist
settings_plist = NSMutableDictionary.dictionaryWithContentsOfFile_(settings_path)
for dictionary in settings_plist['PreferenceSpecifiers']:
if 'Key' in dictionary and dictionary['Key'] == settings_key:
dictionary['DefaultValue'] = project_bundle_version
# print repr(settings_plist)
settings_plist.writeToFile_atomically_(settings_path, True)
这是我在Settings.bundle中获得的Root.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>Title</key>
<string>About</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>DefaultValue</key>
<string>1.0.0.0</string>
<key>Key</key>
<string>version_preference</string>
<key>Title</key>
<string>Version</string>
<key>Type</key>
<string>PSTitleValueSpecifier</string>
</dict>
</array>
<key>StringsTable</key>
<string>Root</string>
</dict>
</plist>
答案 5 :(得分:8)
其他答案因某种原因无效: 在打包设置包之后,运行脚本构建阶段才会执行。因此,如果您的Info.plist版本是2.0.11并且您将其更新为2.0.12,然后构建/存档您的项目,则设置包仍然会说2.0.11。如果打开“设置”包Root.plist,则可以看到版本号在构建过程结束之前不会更新。您可以构建项目AGAIN以正确更新Settings包,或者您可以将脚本添加到预构建阶段而不是......
将您的脚本添加到文本区域。以下脚本适合我。您可能需要修改路径以匹配项目设置:
versionString = $(/ usr / libexec / PlistBuddy -c&#34;打印CFBundleVersion&#34;&#34; $ {PROJECT_DIR} / $ {INFOPLIST_FILE}&#34;)
/ usr / libexec / PlistBuddy&#34; $ SRCROOT / Settings.bundle / Root.plist&#34; -c&#34;设置PreferenceSpecifiers:0:DefaultValue $ versionString&#34;
这将在构建/存档过程中打包设置包之前正确运行脚本。如果您打开设置包Root.plist并构建/存档项目,您现在将看到版本号在构建过程开始时更新,并且您的设置包将显示正确的版本。
答案 6 :(得分:8)
使用Xcode 11.4,您可以按照以下步骤在应用程序的设置捆绑包中显示应用程序版本。
$(MARKETING_VERSION)
和$(CURRENT_PROJECT_VERSION)
变量注意:如果在 Info.plist 中的$(MARKETING_VERSION)
和$(CURRENT_PROJECT_VERSION)
键上显示Bundle version string (short)
和Bundle version
变量,则可以跳过以下步骤并跳到下一部分。
0.1.0
),并更改 Build 字段内容更改为某个新值(例如12
)。这两项更改将在 Info.plist 文件中创建$(MARKETING_VERSION)
和$(CURRENT_PROJECT_VERSION)
变量。<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>DefaultValue</key>
<string></string>
<key>Key</key>
<string>version_preference</string>
<key>Title</key>
<string>Version</string>
<key>Type</key>
<string>PSTitleValueSpecifier</string>
</dict>
</array>
<key>StringsTable</key>
<string>Root</string>
</dict>
</plist>
version="$MARKETING_VERSION"
build="$CURRENT_PROJECT_VERSION"
/usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:0:DefaultValue $version ($build)" "${SRCROOT}/Settings.bundle/Root.plist"
答案 7 :(得分:3)
我设法通过使用pListcompiler(http://sourceforge.net/projects/plistcompiler)开源项目来做我想做的事。
使用此编译器,您可以使用以下格式在.plc文件中编写属性文件:
plist {
dictionary {
key "StringsTable" value string "Root"
key "PreferenceSpecifiers" value array [
dictionary {
key "Type" value string "PSGroupSpecifier"
key "Title" value string "AboutSection"
}
dictionary {
key "Type" value string "PSTitleValueSpecifier"
key "Title" value string "Version"
key "Key" value string "version"
key "DefaultValue" value string "VersionValue"
key "Values" value array [
string "VersionValue"
]
key "Titles" value array [
string "r" kRevisionNumber
]
}
]
}
}
我有一个自定义运行脚本构建阶段,正在将我的存储库修订版提取到.h文件,如brad-larson here所述。
plc文件可以包含预处理程序指令,如#define,#message,#if,#elif,#include,#warning,#ifdef,#else,#pragma,#error,#ifnf,#endif ,xcode环境变量。所以我能够通过添加以下指令
来引用变量kRevisionNumber#include "Revision.h"
我还为我的xcode目标添加了一个自定义脚本构建阶段,以便每次项目构建时都运行plcompiler
/usr/local/plistcompiler0.6/plcompile -dest Settings.bundle -o Root.plist Settings.plc
就是这样!
答案 8 :(得分:1)
我相信你可以使用类似于我在this answer中描述的方式(基于this post)来实现这一点。
首先,您可以通过将VersionValue重命名为$ {VERSIONVALUE}来使其成为Xcode中的变量。创建名为versionvalue.xcconfig的文件并将其添加到项目中。转到您的应用程序目标并转到该目标的Build设置。我相信您需要将VERSIONVALUE添加为用户定义的构建设置。在该窗口的右下角,将“基于”值更改为“versionvalue”。
最后,转到目标并创建运行脚本构建阶段。检查“运行脚本”阶段并在“脚本”文本字段中粘贴脚本。例如,我使用当前Subversion构建标记BUILD_NUMBER设置的脚本如下:
REV=`/usr/bin/svnversion -nc ${PROJECT_DIR} | /usr/bin/sed -e 's/^[^:]*://;s/[A-Za-z]//'`
echo "BUILD_NUMBER = $REV" > ${PROJECT_DIR}/buildnumber.xcconfig
当项目中的值发生变化时,这应该可以替换变量。
答案 9 :(得分:1)
我的工作示例基于@Ben Clayton答案以及@Luis Ascorbe和@Vahid Amiri的评论:
注意:此方法会修改存储库的工作副本
中的 Settings.bundle / Root.plist 文件。
打开Settings.bundle / Root.plist作为源代码
将内容替换为:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>DefaultValue</key>
<string></string>
<key>Key</key>
<string>version_preference</string>
<key>Title</key>
<string>Version</string>
<key>Type</key>
<string>PSTitleValueSpecifier</string>
</dict>
</array>
<key>StringsTable</key>
<string>Root</string>
</dict>
</plist>
将以下脚本添加到项目(目标)方案的“构建,实施前”部分
version=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "$PROJECT_DIR/$INFOPLIST_FILE")
build=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$PROJECT_DIR/$INFOPLIST_FILE")
/usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:0:DefaultValue $version ($build)" "${SRCROOT}/Settings.bundle/Root.plist"
构建并运行当前方案
答案 10 :(得分:0)
以上答案对我不起作用,因此我创建了自定义脚本。
这将动态更新Root.plist中的条目
使用下面的运行脚本。 w ^ 肯定能在xcode 10.3中得到验证。
“ var buildVersion”是要在标题中显示的版本。
在settings.bundle Root.plist中,标题的标识符名称是下面的“ var version”
cd "${BUILT_PRODUCTS_DIR}"
#set version name to your title identifier's string from settings.bundle
var version = "Version"
#this will be the text displayed in title
longVersion=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${INFOPLIST_PATH}")
shortVersion=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" ${TARGET_BUILD_DIR}/${INFOPLIST_PATH})
buildVersion="$shortVersion.$longVersion"
path="${WRAPPER_NAME}/Settings.bundle/Root.plist"
settingsCnt=`/usr/libexec/PlistBuddy -c "Print PreferenceSpecifiers:" ${path} | grep "Dict"|wc -l`
for (( idx=0; idx<$settingsCnt; idx++ ))
do
#echo "Welcome $idx times"
val=`/usr/libexec/PlistBuddy -c "Print PreferenceSpecifiers:${idx}:Key" ${path}`
#echo $val
#if ( "$val" == "Version" )
if [ $val == "Version" ]
then
#echo "the index of the entry whose 'Key' is 'version' is $idx."
# now set it
/usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:${idx}:DefaultValue $buildVersion" $path
# just to be sure that it worked
ver=`/usr/libexec/PlistBuddy -c "Print PreferenceSpecifiers:${idx}:DefaultValue" $path`
#echo 'PreferenceSpecifiers:$idx:DefaultValue set to: ' $ver
fi
done
Root.plist中的示例条目
<dict>
<key>Type</key>
<string>PSTitleValueSpecifier</string>
<key>Title</key>
<string>Version</string>
<key>DefaultValue</key>
<string>We Rock</string>
<key>Key</key>
<string>Version</string>
</dict>
答案 11 :(得分:0)
对我来说,这是最简单的解决方案:
在“复制捆绑包资源”步骤之前添加新的脚本构建阶段
Shell:/usr/bin/env python
内容:
#! /usr/bin/env python
import os
from AppKit import NSMutableDictionary
# Key to replace
settings_key = 'version_preference' # the key of your settings version
# File path
settings_path = os.environ.get('SRCROOT') + "/TheBeautifulNameOfYourOwnApp/Settings.bundle/Root.plist"
# Composing version string
version_string = os.environ.get('MARKETING_VERSION') + " (" + os.environ.get('CURRENT_PROJECT_VERSION') + ")"
# Reading settings plist
settings_plist = NSMutableDictionary.dictionaryWithContentsOfFile_(settings_path)
for dictionary in settings_plist['PreferenceSpecifiers']:
if 'Key' in dictionary and dictionary['Key'] == settings_key:
dictionary['DefaultValue'] = version_string
# Save new settings
settings_plist.writeToFile_atomically_(settings_path, True)
答案 12 :(得分:0)
这些是我在Xcode 12.2的快速项目中必须使用的变量
version=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "$PROJECT_DIR/$INFOPLIST_FILE")
build="$CURRENT_PROJECT_VERSION"
/usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:0:FooterText Version $version" "$CODESIGNING_FOLDER_PATH/Settings.bundle/ServerURLSettings.plist"
/usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:0:FooterText Version $version($build)" "$CODESIGNING_FOLDER_PATH/Settings.bundle/DeveloperSettings.plist"