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


14

从版本11开始,每当我在目标设置(选项卡“常规”)中输入“版本”或“构建”值时,Xcode便将my的CFBundleVersion值设置为,$(CURRENT_PROJECT_VERSION)并将my CFBundleShortVersionString的值$(MARKETING_VERSION)设置为。

我输入的实际版本和构建值现在存储在project.pbxproj文件中。我不希望或不喜欢这种行为,因为我在构建时使用shell脚本来修改值。

我可以在Info.plist文件中手动设置正确的值,但是一旦我在目标设置中更改了版本号或内部版本号,Info.plist文件就会被Xcode再次更改。

如何停止Xcode 11执行此操作?

当我修改构建脚本以更改项目文件本身时,Xcode将在项目文件更改后立即取消构建。


您为什么要Xcode 11停止这样做,而不是修改您的Shell脚本来检索值?
曼努埃尔

1
@Manuel我认为使用plist进行修改plistbuddy很干净,而修改项目文件则更加混乱,不可靠并且容易发生文件格式的意外更改。
Zystem先生19年

1
当您了解文件格式时,操作project.pbxproj文件不会很麻烦。这只是一个有据可查的Next样式plist。您甚至可以使用plistbuddy修改文件,该文件与此格式兼容。
曼努埃尔

我针对您的用例提出了建议,以更新我的答案。
曼努埃尔

Answers:


1

到目前为止的路

我的用例是:

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

我曾经在CI本身上将第1点和第2点作为目标构建脚本执行,而将第3点作为自定义脚本执行。

在Xcode构建设置中存储版本和构建的新方法导致脚本出现问题,因为它们不再能够有效地修改值。至少可以阅读。

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

事实证明,在构建或归档时,将Info.plist使用写入的值。这意味着在构建期间将替换该值,这不允许我们在相同的构建期间对其进行修改。

我也尝试过使用xcodeprojcli 修改项目,但是对项目的任何更改都会导致任何构建停止,因此该解决方案无法正常工作。

最终,在尝试了许多不同的方法之后,我终于设法找到了一个不违反Xcode新行为的折衷方案。

简短答案:

作为目标的预动作,脚本执行其各自的值写入到CFBundleShortVersionStringCFBundleVersion到目标的Info.plist

作为事实的来源,我使用Xcode构建设置读取所需目标的MARKETING_VERSION和的值CURRENT_PROJECT_VERSION

这样,当您从项目设置中修改值时-在下一次构建/归档时-它们将被写入Info.plist,从而允许您现有的脚本逻辑继续运行。

详细答案

在执行构建操作时修改资源的唯一方法是使用pre-action脚本。如果尝试从构建脚本执行此操作-更改将不会立即生效,并且不会在构建/归档结束时出现。

为了添加一个预构建动作-进入编辑方案。

在此处输入图片说明

然后展开“构建”和“存档”部分。在下方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_VERSION和执行同步脚本CURRENT_PROJECT_VERSION

最后一步是编写您自己的同步脚本,该脚本将读取所提供的值,MARKETING_VERSION并读取CURRENT_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.plist和共享Settings.bundle,因此我必须更新一次。

我还使用了通知服务扩展BadgeCounter,它必须具有完全相同的版本,并与嵌入它的目标相同。因此,我也对此进行了更新。


1

别。

大概是这种行为发生变化的原因。如果以后的Xcode功能基于此行为,那么事情将越来越“被构造”。

无需尝试弯曲Xcode,而是更改构建脚本检索这些值的方式:

如何使用脚本读取Xcode 11中的当前应用程序版本

如果您需要操作该project.pbxproj文件,则它是一个文档齐全的Next样式plist。您可以使用plistbuddy与此旧格式兼容的格式。awk如果您有更复杂的操作,也可以使用更多脚本。

如果我了解您的用例,您可以编写一个脚本,该脚本使用来获取最高版本号,awk然后使用来更新它在文件中可以找到的所有较低版本号sed


打印带有的值PlistBuddy 似乎可以正常工作,但是当我使用set命令时,整个project.pbxproj都将转换为XML .plist文件,并且Xcode无法再读取它。例如:PlistBuddy -c "Set :objects:$configurationId:buildSettings:CURRENT_PROJECT_VERSION $newProjectVersion" "$projectFile"
Zystem先生19年

根据您要实现的目标,您可能必须使用多种工具
Manuel

重新启动Xcode可以解决XML问题。Als发现,运行更改pbxproj文件的构建脚本时,将取消构建。因此,恐怕这真的行不通。
Zystem先生19年

我用以上信息更新了我的原始问题。
Zystem先生19年

1
例如-我的用例是同步版本并跨多个目标构建-我想设置版本并构建至第一个目标,该目标会自动更新为所有其他目标。之前它运行良好,因为您只是修改了资源。现在我无法在任何目标的构建阶段修改项目,因为构建被取消了。
KoCMoHaBTa
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.