显然文件被缓存了,所以它只有在它被改变时才会被构建。我设置了环境变量来增加我的版本号,等等,并独立于 plist 更新它们(实际上是在项目构建设置中)。是否有一个脚本可以用作脚本构建阶段来强制 Info.plist 更新?还有什么方便的方法?
10 回答
选择“编辑方案”,然后从左侧的控件中选择“构建”。
然后,添加一个 Pre-actions 步骤,确保在“Provide build settings from”下拉菜单中选择了相关方案,然后将其添加到下面的编辑窗口中:
rm "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}"
这将删除 的缓存版本Info.plist
,导致 XCode 在您每次点击 build 时重新构建它。
或者,如果您让 Xcode 预处理模板 Info.plist 文件,只需使用
touch ${PROJECT_DIR}/${INFOPLIST_FILE}
也可以。
调试预操作脚本
当您犯错时,预操作步骤不会提供任何信息。您可以通过将此行添加到脚本来调试构建变量的使用
echo "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}" > ~/debug.txt
然后检查 的内容~/debug.txt
以验证预操作脚本是否已运行,并查看您是否使用了正确的路径。
我也自动设置了我的版本号。我创建了一个运行脚本构建阶段。关键是更新Info.plist的目标构建目录副本而不是构建目录之一。您还需要在复制捆绑阶段之后拥有运行脚本。可以直接编辑捆绑文件,因为在代码签名之前。您不想生成重新发明轮子的文件。
这是我的脚本:
# ---------------------------- IMPORTANT ----------------------------
# You must set GITHash to something like 'Set by build script' in the file
# file '<Project Name>-Info.plist' in the 'Supporting Files' group
# -------------------------------------------------------------------
#
# Get the version number from the tag in git and the number of commits as the build number
#
appVersion=$(git describe --long | cut -f 1 -d "-")
appBuild=$(git describe --long | cut -f 2 -d "-")
gitHash=$(git describe --long | cut -f 3 -d "-")
echo "From GIT Version = $appVersion Build = $appBuild"
#
# Set the version info in plist file
#
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $appVersion" "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $appBuild" "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
/usr/libexec/PlistBuddy -c "Set :GITHash $gitHash" "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
echo "Updated ${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
仅供参考,我还使用以下代码自动设置版本并在 About 选项卡上构建
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
NSString *appDisplayName = infoDictionary[@"CFBundleDisplayName"];
NSString *majorVersion = infoDictionary[@"CFBundleShortVersionString"];
NSString *minorVersion = infoDictionary[@"CFBundleVersion"];
self.appDescription.text = [NSString stringWithFormat:@"Dirty Dog Software\n%@\nVersion: %@(%@)",
appDisplayName, majorVersion, minorVersion];
您可以尝试使用touch
命令来更新时间戳,我认为这是 Xcode 用来确定是否应该重建它的,例如
$ touch Info.plist
一种方法是让运行脚本构建阶段Info.plist
从Info.plist.template
文件生成,然后rm Info.plist
在创建包之后。来自Dave DeLong在他的博客上发表的评论的想法。
如果缓存非常严重(即缓存,即使您没有在文件历史记录中打开 Info.plist),您可能也希望rm
在此脚本中缓存版本。
在 Xcode 4 中,您可以使用预构建操作来触摸 info plist。
注意:这与运行脚本构建阶段不同。预构建操作发生在 Xcode 检查信息 plist 之前,运行脚本构建阶段似乎发生在 Xcode 已经检查过信息 plist 之后(这就是为什么它只每隔一次工作一次)。
- 转到编辑方案 > 构建 > 预操作
- 单击“+”按钮并选择“新建运行脚本操作”
- 在“提供构建设置来自”下拉列表中选择您的目标
touch "${SRCROOT}/${INFOPLIST_FILE}"
在脚本框中添加
在目标的“获取信息”窗口的“构建”选项卡中有一个选项,在“打包”标记为“预处理 Info.plist 文件”的下方,您可以检查该选项。我相信每次构建都会更新文件。
使用 Xcode 8.3.2
受到@LeeH 2013 年回答的启发,我想出了两个解决方案来重建 Info.plist。
解决方案一:最简单优雅
最简单的解决方案是通过触摸您的目标来强制 Xcode 读取您的自定义变量Info.plist
。
添加构建阶段,请参见下面的屏幕截图(最初为解决方案 2截图),然后添加以下行:
touch $INFOPLIST_FILE
就这些!现在 Xcode 应该强制将您的自定义变量重新加载到Info.plist
文件中。
此解决方案与@lukelutman 建议的相同,但使用构建阶段。预操作脚本对我不起作用。
解决方案 2:更复杂和 hacky
另一种解决方案是删除构建目录中的缓存 。Info.plist
我写了这个超级简单的小 bash 脚本
#!/bin/bash
info_plist="$CONFIGURATION_BUILD_DIR/$PRODUCT_NAME.app/Info.plist"
echo "Removing Info.plist from build dir in order to force rebuild of it and reading of correct xcconfig variables, plist path $info_plist"
rm "$info_plist"
然后我保存它并从目标的构建阶段调用它。我把它作为第一个构建阶段。
背景:
我有三种不同的配置:Config
、Alpha
和AppStore
我正在使用通用链接、推送通知和其他需要使用权利文件的东西。但我不想拥有三个授权文件,每个配置一个。
我的项目已经严重依赖配置文件 ( .xcconfig
)。MyAppsProductName.entitlements
我实际上使用自定义配置变量设置了权利文件 ( )。
但是我想在运行时读取相同的配置变量,我想如果将它们添加到我的目标 Info.plist 中,我可以做到这一点。哪个有效!
但我注意到,当我更改.xcconfig
文件中的值时,Info.plist
文件并没有更改值。我注意到,如果我执行了一个干净的构建,那么Info.plist
得到的值会根据.xcconfig
文件中的值进行更新。Xcode 确实缓存了Info.plist
文件。
所以上面的这些解决方案解决了这个问题。希望能帮助到你!:)
讨论
我不知道解决方案 2是否比解决方案 1有任何优势……可能不是?任何输入任何人?
确保您还刷新了 plist 的视图。
在 Xcode 中查看 plist 时,只需单击 plist 中根元素旁边的显示三角形 ( Information Property List
)。然后再次单击它以展开它。
您会看到这些值已被刷新。我正在运行一个类似的脚本,并认为它只是间歇性地工作,直到我意识到 plist 视图根本没有刷新。
另一种方法是创建一个只有构建阶段的“聚合”目标。使用它来触摸 Info.plist 文件。使该目标成为构建您的应用程序的目标的依赖项。
因为它是一个单独的目标并且是您的应用目标的依赖项,所以它甚至会在您的应用目标的 Info.plist 文件被检查之前构建。(如其他地方所述,应用程序目标本身的构建阶段发生得太晚,在 Info.plist 文件的修改时间已经检查过之后。)
对于那些难以让项目进行自动版本控制的人,我创建了一个macOS GitHub 项目,该项目演示了如何以一种非常简单、直接的方式实现它,这要感谢 @GayleDDS 和 Daniel Farrelly 的想法以及他关于版本控制和我自己的一些实现。我认为您可以毫不费力地将其翻译到您在其他平台上的项目中。
这是一个关于如何在项目中复制它的小指南(Xcode 8)。
- 为减少您出错的机会,请确保您已事先将所有目标添加到您的项目中。
- 转到菜单File > New File...然后向下滚动并选择Configuration Settings File
- 命名它
BuildNumber
并且不要忘记将此配置文件添加到您想要保持同步的所有目标;通过在保存此文件之前单击相应的复选框来执行此操作 - 您应该会在项目中看到一个名为
BuildNumber.xcconfig
show up的文件 - 将以下文本添加到此文件:
CURRENT_PROJECT_VERSION = 1
. 如果你愿意,你可以从另一个号码开始。这将是您的内部版本号,每次构建时都会增加。但是,请不要更改变量的名称。 - 如果您有多个目标,请将以下脚本添加到通过导航到Project > Target > Build Phases 构建的第一个目标
- 导航到菜单编辑器 > 添加构建阶段 > 添加运行脚本阶段
- 一个运行脚本阶段应该已经添加到您的目标中;所以将它拖到目标依赖项下(这个细节很重要!)。
- 现在是有趣的部分,我将几乎逐行解释脚本:
首先在脚本的第一行创建 PlistBuddy 的路径:
plistbuddy="/usr/libexec/PlistBuddy"
添加第 2 行以读取配置文件,然后读取您在步骤 5 中设置的 CURRENT_PROJECT_VERSION 变量。
OLD_VERSION=`cat "$SRCROOT/BuildNumber.xcconfig" | awk '/CURRENT_PROJECT_VERSION/ { print $3 }'`
第 3-11 行使用增加的值设置 NEW_VERSION,然后使用新的内部版本号保存配置文件;剩下的几行是将营销版本和内部版本号保存到 plist 中:
NEW_VERSION=`cat "$SRCROOT/BuildNumber.xcconfig" | awk '/CURRENT_PROJECT_VERSION/ { print $3 + 1 }'`
sed -i '' "s/CURRENT_PROJECT_VERSION = .*/CURRENT_PROJECT_VERSION = $NEW_VERSION/" "$SRCROOT/BuildNumber.xcconfig"
CURRENT_PROJECT_VERSION=$NEW_VERSION
BUILD_STR="Build $NEW_VERSION"
COPYRIGHT_STR="© 2017 MyCompany.net"
APP_VERSION_STR="1.3.5"
$plistbuddy -c "Set :CFBundleShortVersionString $APP_VERSION_STR" "${SRCROOT}/$TARGETNAME/Info.plist"
$plistbuddy -c "Set :CFBundleVersion $BUILD_STR" "${SRCROOT}/$EXECUTABLE_NAME/Info.plist"
$plistbuddy -c "Set :NSHumanReadableCopyright $COPYRIGHT_STR" "$INFOPLIST_FILE"
我还在第 8-11 行展示了如何使用 Xcode 为其脚本设置的不同环境变量。您可以添加额外的行来编辑其他目标的 info.plist,然后保持主应用程序的版本及其助手同步。转到GitHub,下载项目并使用它,然后根据您的需要进行调整。使用 Xcode 进行愉快的自动版本控制。