如何阻止Xcode 11将CFBundleVersion和CFBundleShortVersionString更改为$(CURRENT_PROJECT_VERSION)和$(MARKETING_VERSION)?

25
自从版本11开始,Xcode将CFBundleVersion的值设置为$(CURRENT_PROJECT_VERSION),并将CFBundleShortVersionString的值设置为$(MARKETING_VERSION),当我在目标设置(选项卡“常规”)中输入版本或构建值时。
我实际输入的版本和构建值现在存储在project.pbxproj文件中。我不希望也不喜欢这种行为,因为我使用Shell脚本在构建时修改值。
我可以手动在Info.plist文件中设置正确的值,但是一旦我在目标设置中更改版本或构建数字,Xcode会再次更改Info.plist文件。
如何停止Xcode 11这样做?
当我修改构建脚本以更改项目文件本身时,Xcode会在项目文件更改时立即取消构建。

为什么你想让Xcode 11停止这样做,而不是修改你的shell脚本来获取值? - Manuel
3
我认为使用 plistbuddy 修改属性列表是清晰简洁的,而修改项目文件则更加混乱、不可靠,并容易导致文件格式意外发生变化。 - hotdogsoup.nl
1
当你理解文件格式时,操作project.pbxproj文件并不杂乱无章。它只是一个Next样式的属性列表,有着良好的文档说明。你甚至可以使用plistbuddy修改文件,因为它兼容该格式。 - Manuel
我更新了我的答案,为您的用例提供了建议。 - Manuel
1个回答

7

迄今为止的路程

我的用例是:

  1. 我正在跨多个目标同步版本和构建号。
  2. 我正在将版本和构建号与目标的 Settings.bundle 同步。
  3. 我正在从 CI 服务器读取并修改构建号。

我以前会将第一点和第二点作为目标构建脚本执行,第三点作为 CI 上的自定义脚本执行。

Xcode 构建设置中存储版本和构建的新方式导致脚本存在问题,因为它们不能有效地修改这些值。至少读取是可能的。

不幸的是,我无法找到一个合法的方法来防止 Xcode 将版本和构建号存储到项目构建设置中,但是我设法创建了一个解决方法。

事实证明,当进行构建或打包时,Info.plist 中写入的值将被使用。这意味着该值在构建时进行替换,这样我们就无法在同一构建时间内修改它。

我还尝试使用 xcodeproj cli 修改项目,但对项目进行的任何更改都会导致任何构建停止,因此此解决方案无效。

最终,在我尝试的许多不同方法之后,我终于找到了一个妥协方案,它没有违反 Xcode 的新行为。

简短回答:

作为目标预操作,将在执行脚本时将相应的值写入目标的 Info.plist 中的 CFBundleShortVersionStringCFBundleVersion

作为真相来源,我使用 Xcode 构建设置来读取所需目标的 MARKETING_VERSIONCURRENT_PROJECT_VERSION 值。

这样,当您从项目设置中修改值时,下一次构建/打包时,它们将被写入 Info.plist,从而允许您的任何现有脚本逻辑继续工作。

详细回答

唯一可以在构建操作中修改资源的方法是使用 pre-action 脚本。如果您尝试从构建脚本进行修改,则更改不会立即生效,并且不会在构建/打包结束时存在。

要添加预构建操作,请转到“编辑方案”。

enter image description here

然后展开“构建”和“存档”部分。在 Pre-action 下,单击 Provide build and settings from 下拉菜单,并选择您希望读取值的真实来源目标。

请添加以下脚本:

输入图像描述

将以下脚本添加进去:

# 1) 
cd ${PROJECT_DIR}

# 2) 
exec > Pruvit-Int.prebuild.sync_project_version_and_build_with_info_plists.log 2>&1

# 3) 
./sync_project_version_and_build_with_info_plists.sh $MARKETING_VERSION $CURRENT_PROJECT_VERSION

这些脚本执行以下操作:
  1. 进入同步脚本所在目录以执行它。
  2. 允许在预处理操作期间编写日志,否则默认情况下将关闭任何输出。
  3. 通过提供 MARKETING_VERSIONCURRENT_PROJECT_VERSION 来执行同步脚本。
最后一步是编写自己的同步脚本,读取所提供的 MARKETING_VERSIONCURRENT_PROJECT_VERSION 的值到相应的目标,并在其他需要的时候进行同步。
在我的情况下,脚本如下:
#!/bin/bash

#IMPORTANT - this script must run as pre-action of each target's Build and Archive actions

version_number=$1
build_number=$2

echo "version_number is $version_number"
echo "build_number is $build_number"

#update Pruvit/Info.plist
pruvitInfoPlist="Pruvit/Info.plist"
/usr/libexec/PlistBuddy -c "Set CFBundleShortVersionString $version_number" $pruvitInfoPlist
/usr/libexec/PlistBuddy -c "Set CFBundleVersion $build_number" $pruvitInfoPlist

#update Pruvit/Settings.bundle
settingsPlist="Pruvit/Settings.bundle/Root.plist"
/usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:0:DefaultValue $version_number" $settingsPlist
/usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:1:DefaultValue $build_number" $settingsPlist

#update BadgeCounter/Info.plist
badgeCounterInfoPlist="BadgeCounter/Info.plist"
/usr/libexec/PlistBuddy -c "Set CFBundleShortVersionString $version_number" $badgeCounterInfoPlist
/usr/libexec/PlistBuddy -c "Set CFBundleVersion $build_number" $badgeCounterInfoPlist

我在我的两个应用目标之间使用共享的Info.plistSettings.bundle,因此我只需要更新一次。

此外,我还使用了一个通知服务扩展BadgeCounter,它必须与嵌入它的目标具有完全相同的版本和构建。所以我也要更新这个。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接