每次构建项目时,如何强制Xcode重建项目中的Info.plist文件?

时间:2010-09-16 19:45:16

标签: xcode xcodebuild

显然文件会被缓存,因此只有在文件被更改时才会生成。我将环境变量设置为增加我的版本号,等等,并且独立于plist更新它们(实际上在项目构建设置中)。是否有一个脚本可以用作脚本构建阶段来强制Info.plist更新?其他一些方便的方式?

10 个答案:

答案 0 :(得分:16)

选择“编辑方案”,然后从左侧的控件中选择“构建”。

然后,添加一个预操作步骤,确保在“提供构建设置来自”下拉菜单中选择了相关方案,然后将其添加到下面的编辑窗口中:

rm "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}"

这将删除Info.plist的缓存版本,导致XCode在每次点击构建时重建它。

或者,如果您让Xcode预处理模板Info.plist文件,只需使用

触摸模板即可
touch ${PROJECT_DIR}/${INFOPLIST_FILE}

也有效。

调试行动前脚本

如果您犯了错误,预执行步骤不会提供任何信息。您可以通过将此行添加到脚本

来调试构建变量的使用
echo "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}" > ~/debug.txt

然后检查~/debug.txt的内容以验证运行前脚本是否已运行并查看您是否使用了正确的路径。

答案 1 :(得分:15)

我也自动设置了我的版本号。我创建了一个运行脚本构建阶段。 关键是更新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}"

仅供参考我还自动设置版本并使用以下代码在“关于”标签上构建

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];                           

答案 2 :(得分:11)

您可以尝试使用touch命令更新时间戳,我假设Xcode用它来确定是否应该重建时间戳,例如。

$ touch Info.plist

答案 3 :(得分:9)

执行此操作的一种方法是使用“运行脚本”构建阶段从Info.plist文件生成Info.plist.template,然后在创建捆绑后生成rm Info.plist。来自评论Dave DeLong的想法发布在他的博客here上。

如果它的缓存非常严重(即即使您没有在文件历史记录中打开Info.plist,也可以缓存),您可能希望在此脚本中rm缓存版本。

答案 4 :(得分:5)

在Xcode 4中,您可以使用预构建操作来触摸信息plist。

注意:这与运行脚本构建阶段不同。在Xcode检查信息plist之前发生了预构建操作,在Xcode已经检查了信息plist之后,运行脚本构建阶段似乎发生了(这就是为什么它每隔一段时间才有效)。

  1. 转到编辑方案&gt;构建&gt;预动作
  2. 单击“+”按钮并选择“新建运行脚本操作”
  3. 在“提供构建设置”下拉列表中选择目标
  4. 在脚本框中添加touch "${SRCROOT}/${INFOPLIST_FILE}"

答案 5 :(得分:1)

目标的“获取信息”窗口的“构建”选项卡中有一个选项,位于标有“预处理信息.plist文件”的“打包”中,您可以查看该选项。我相信每次构建都会更新文件。

答案 6 :(得分:0)

确保您也刷新了对plist的看法 在Xcode中查看plist时,只需单击plist(Information Property List)中根元素旁边的显示三角形。然后再次单击它以展开它 您将看到值已刷新。我正在运行一个类似的脚本,并认为它只是间歇性地工作,直到我意识到plist视图根本不令人耳目一新。

答案 7 :(得分:0)

另一种方法是创建一个只有构建阶段的“聚合”目标。用它来触摸Info.plist文件。使该目标成为构建应用程序的目标的依赖项。

因为它是一个单独的目标和应用目标的依赖关系,所以它将在您的应用目标的Info.plist文件被检查之前构建。 (如其他地方所述,在已经检查Info.plist文件的修改时间之后,应用程序目标本身的构建阶段发生得太晚了。)

答案 8 :(得分:0)

对于那些努力让项目进行自动版本控制的人,我创建了一个macOS GitHub project,它演示了如何以一种非常简单,直接的方式实现它,这要归功于@GayleDDS和Daniel Farrelly的想法。他的博客关于版本控制和我自己的一些实现。我想你可以毫不费力地将它翻译成你在其他平台上的项目。

这里有一个关于如何在项目中复制它的指南(Xcode 8)。

  1. 为了减少出错的可能性,请确保您已事先将所有目标添加到项目中。
  2. 转到菜单文件&gt;新文件... ,然后向下滚动并选择配置设置文件
  3. 将其命名为BuildNumber并且不要忘记将此配置文件添加到要保持同步的所有目标;通过在保存此文件之前单击相应的复选框来执行此操作
  4. 您应该会在项目中看到名为BuildNumber.xcconfig的文件
  5. 将以下文字添加到此文件中:CURRENT_PROJECT_VERSION = 1。如果需要,您可以从另一个号码开始。这将是您每次构建时都会增加的内部版本号。 请不要更改变量的名称,但
  6. 如果您有多个目标,请将以下脚本添加到通过导航到项目&gt;构建的第一个目标。目标&gt;建立阶段
  7. 导航至菜单编辑器&gt;添加构建阶段&gt;添加运行脚本阶段
  8. 运行脚本阶段应该已添加到目标中;所以拖动它直到目标依赖性(这个细节很重要!)。
  9. 现在它是有趣的部分,我将逐行解释脚本:
  10. 首先在脚本的第一行创建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进行快速自动版本控制。

答案 9 :(得分:0)

使用Xcode 8.3.2

受到@LeeH 2013年答案的启发,我为我提供了两个重建Info.plist的解决方案。

解决方案1:最简单优雅

最简单的解决方案是通过触摸目标Info.plist来强制Xcode读取您的自定义变量。

添加构建阶段,请参阅下面的截图(最初为解决方案2 截屏),然后添加以下行:

touch $INFOPLIST_FILE

就是这样!现在Xcode应强制将自定义变量重新加载到Info.plist文件中。

此解决方案与@lukelutman建议的相同,但使用Build阶段。预行动脚本对我不起作用。

解决方案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"

然后我保存了它并从目标的构建阶段调用它。我把它作为第一个构建阶段。

enter image description here

背景

我有三种不同的配置:ConfigAlphaAppStore我正在使用通用链接,推送通知和其他需要使用权利文件的内容。但我不想拥有三个授权文件,每个配置一个。

我的项目已经在很大程度上依赖于配置文件(.xcconfig)。我实际上使用自定义配置变量设置了权利文件(MyAppsProductName.entitlements)。

但是我想读取相同的配置变量运行时,我想如果将它们添加到我的目标Info.plist中,我可以这样做。哪个有用!

但是我注意到当我更改.xcconfig文件中的值时,Info.plist文件没有更改值。我注意到如果我执行了干净的构建,那么Info.plist中的值会根据.xcconfig文件中的值进行更新。 Xcode确实缓存了Info.plist文件。

所以上面的这些解决方案解决了这个问题。希望能帮助到你! :)

讨论

我不知道 Solution 2 是否比 Solution 1 有任何优势......可能不是吗?有人输入吗?