如何在应用程序的设置包中显示应用程序版本修订?
-
22-08-2019 - |
题
我想在我的应用程序的设置包中包含应用程序版本和内部修订版,例如 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 文件并替换修订号而不影响源文件的方法。
解决方案 7
我设法通过使用 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 所描述的那样 这里.
plc 文件可以包含预处理器指令,例如#define、#message、#if、#elif、#include、#warning、#ifdef、#else、#pragma、#error、#ifndef、#endif、xcode 环境变量。所以我可以通过添加以下指令来引用变量 kRevisionNumber
#include "Revision.h"
我还在我的 xcode 目标中添加了一个自定义脚本构建阶段,以便在每次项目构建时运行 plcompiler
/usr/local/plistcompiler0.6/plcompile -dest Settings.bundle -o Root.plist Settings.plc
就是这样!
其他提示
有另一种解决方案,可以比任一以前的答案要简单得多。苹果束称为命令行工具的 PlistBuddy 强>内大部分安装的,并已包括它在/usr/libexec/PlistBuddy
豹。
由于要替换VersionValue
,假设你有提取到$newVersion
版本值,可以使用下面的命令:
/usr/libexec/PlistBuddy -c "Set :VersionValue $newVersion" /path/to/Root.plist
无需使用sed或正则表达式来摆弄,这种做法是非常简单的。请参阅详细说明,手册页。您可以使用PlistBuddy添加,删除或修改在属性列表中的任何条目。例如,我的朋友在博客递增在Xcode建立数字使用PlistBuddy。
注意:如果您只是提供了路径的plist,PlistBuddy进入交互模式,这样你就可以决定保存更改之前发出多个命令。我绝对推荐你构建脚本plopping之前这样做。
我懒惰的人的解决方案是更新从我的应用程序代码的版本号。你可以有在Root.plist默认(或空)值,然后,在某处你的启动代码:
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
[[NSUserDefaults standardUserDefaults] setObject:version forKey:@"version_preference"];
,唯一的缺点是,你的应用程序都必须至少运行一次的更新版本出现在设置面板。
您可以采取进一步的想法和更新,例如,多少次的计数器您的应用程序已经启动,或其他信息感兴趣位。
根据@Quinn 的回答,这里是我用来执行此操作的完整过程和工作代码。
- 将设置包添加到您的应用程序中。不要重命名它。
- 在文本编辑器中打开 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>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。
使用 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 上测试
,这里的脚本I”使用自动更新设置束版本数m:
#! /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)
这里的Root.plist我在Settings.bundle了:
<?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>
由于一个原因,其他答案无法正常工作:在打包设置包之后,才会执行运行脚本构建阶段。因此,如果您的 Info.plist 版本是 2.0.11 并且您将其更新到 2.0.12,然后构建/存档您的项目,Settings 包仍会显示 2.0.11。如果打开 Settings 包 Root.plist,您可以看到版本号直到构建过程结束才更新。您可以再次构建项目以正确更新设置包,或者您可以将脚本添加到预构建阶段...
- 在 XCode 中,编辑项目目标的方案
- 单击 BUILD 方案上的显示箭头
- 然后,单击“预操作”项
- 单击加号并选择“新建运行脚本操作”
- 将 shell 值设置为 /bin/sh
- 将“提供构建设置自”设置为您的项目目标
将脚本添加到文本区域。以下脚本对我有用。您可能需要修改路径以匹配您的项目设置:
versionString=$(/usr/libexec/PlistBuddy -c "打印 CFBundleVersion" "${PROJECT_DIR}/${INFOPLIST_FILE}")
/usr/libexec/PlistBuddy“$SRCROOT/Settings.bundle/Root.plist”-c“设置 PreferenceSpecifiers:0:DefaultValue $versionString”
这将在构建/存档过程中打包设置捆绑包之前正确运行脚本。如果您打开设置包 Root.plist 并构建/归档您的项目,您现在将看到版本号在构建过程开始时更新,并且您的设置包将显示正确的版本。
首先,你可以通过它重命名为$ {} VERSIONVALUE使VersionValue在Xcode中的变量。创建一个名为versionvalue.xcconfig文件,并将它添加到您的项目。转到您的应用程序的目标,并去为目标构建设置。我认为,你需要VERSIONVALUE添加为用户定义的构建设置。在该窗口的右下拐角,所述基于值更改为“versionvalue”。
最后,进入到你的目标,并创建一个运行脚本生成阶段。检查运行脚本阶段和脚本文本字段中的脚本粘贴。例如,我的脚本标记我BUILD_NUMBER与当前的Subversion构建设置如下:
REV=`/usr/bin/svnversion -nc ${PROJECT_DIR} | /usr/bin/sed -e 's/^[^:]*://;s/[A-Za-z]//'`
echo "BUILD_NUMBER = $REV" > ${PROJECT_DIR}/buildnumber.xcconfig
这应该做更换可变的把戏时,这些价值在项目中改变。
我的工作示例基于@Ben Clayton 的回答以及@Luis Ascorbe 和@Vahid Amiri 的评论:
笔记:该方法修改了 设置.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"
构建并运行当前方案