在所有目标中使用相同的 CFBundleVersion 和 CFBundleShortVersionString

Use same CFBundleVersion and CFBundleShortVersionString in all targets

我在提交应用程序更新时收到了来自 Apple 的以下电子邮件:

We have discovered one or more issues with your recent delivery for "Project". Your delivery was successful, but you may wish to correct the following issues in your next delivery:

CFBundleVersion Mismatch - The CFBundleVersion value '1' of extension 'Project.app/PlugIns/ProjectTodayExtension.appex' does not match the CFBundleVersion value '985' of its containing iOS application 'Project.app'.

CFBundleShortVersionString Mismatch - The CFBundleShortVersionString value '1.0' of extension 'Project.app/PlugIns/ProjectTodayExtension.appex' does not match the CFBundleShortVersionString value '2.1.6' of its containing iOS application 'Project.app'.

After you’ve corrected the issues, you can use Xcode or Application Loader to upload a new binary to iTunes Connect.

有没有办法在所有目标中使用相同的 CFBundleVersionCFBundleShortVersionString 来防止这种情况发生?

您的 ProjectTodayExtension.appex 版本必须与您的应用程序相同。示例:

目标>一般:

版本:1.0 <- 在此处更改 比尔德:1.0

如果您要在 iTunes Connect 上使用的应用程序版本是 2.3,那么您必须将 TodayExtension 的版本更改为相同的 2.3 版本。

我的解决方案是:

对于 CFBundleShortVersionString:

  • 在您的项目设置中添加一个user-defined常量

  • 将其命名为 $(CF_BUNDLE_SHORT_VERSION_STRING) 并将其设置为您想要的值

  • 将目标中的版本设置为 $(CF_BUNDLE_SHORT_VERSION_STRING)

  • 对所有目标重复。 完成

CFBundleVersion:你可以对 CFBundleVersion 做同样的事情,但不知何故我希望这个值是从我的 GIT 回购提交计数。我是这样做的:

  • 将 Pre-action 添加到您的 主要目标 。您可以通过 Product > Scheme > Edit Scheme
  • 访问显示的对话框

  • 将 Post-action 添加到您的 主要目标

  • 添加一个名为 BundleVersionUpdate 的新命令行工具目标和一个名为 BundleVersionRevert
  • 的目标

  • 导航到新的 BundleVersionUpdate 目标并添加新的 运行 脚本构建阶段

  • 粘贴以下内容
\#!/bin/sh

INFOPLIST="${SRCROOT}/MyApp/MyApp-Info.plist"
INFOPLIST_WKAPP="${SRCROOT}/MyApp-WKApp/Info.plist"
INFOPLIST_WKEXT="${SRCROOT}/MyApp-WKExt/Info.plist"

PLISTCMD="Set :CFBundleVersion $(git rev-list --all|wc -l)"

echo -n "$INFOPLIST" 
| xargs -0 /usr/libexec/PlistBuddy -c "$PLISTCMD"

echo -n "$INFOPLIST_WKAPP" 
| xargs -0 /usr/libexec/PlistBuddy -c "$PLISTCMD"

echo -n "$INFOPLIST_WKEXT" 
| xargs -0 /usr/libexec/PlistBuddy -c "$PLISTCMD"
  • 导航到新的 BundleVersionRevert 目标并添加新的 运行 脚本构建阶段并粘贴:
\#!/bin/sh

INFOPLIST="${SRCROOT}/MyApp/MyApp-Info.plist"
INFOPLIST_WKAPP="${SRCROOT}/MyApp-WKApp/Info.plist"
INFOPLIST_WKEXT="${SRCROOT}/MyApp-WKExt/Info.plist"

PLISTCMD="Set :CFBundleVersion SCRIPTED"

echo -n "$INFOPLIST" 
| xargs -0 /usr/libexec/PlistBuddy -c "$PLISTCMD"

echo -n "$INFOPLIST_WKAPP" 
| xargs -0 /usr/libexec/PlistBuddy -c "$PLISTCMD"

echo -n "$INFOPLIST_WKEXT" 
| xargs -0 /usr/libexec/PlistBuddy -c "$PLISTCMD"
  • 尽情享受吧!

方案操作不在源代码管理中,因此最好将构建阶段添加到应用的目标中。跨所有目标同步版本可以通过一个简单的脚本来解决,该脚本可以针对您要同步的每个目标进行修改:

  1. 在“构建阶段”中为您的应用目标添加“新运行脚本阶段

  1. 将脚本重命名为 "Sync Versions" 并将其拖到“Compile Sources”上方(注意:Xcode 有一个错误这可能会阻止拖放工作。如果是这样,您需要手动编辑 .pbxproj 文件,以便构建阶段进入正确的位置

  2. 将以下脚本粘贴到 shell:

    INFOPLIST_MYAPP="${SRCROOT}/MyApp/MyApp-Info.plist"
    myAppVersion=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "$INFOPLIST_MYAPP")
    myAppBuild=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_MYAPP")
    
    INFOPLIST_SHAREEXT="${SRCROOT}/ShareExtension/Info.plist"
    /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $myAppVersion" "$INFOPLIST_SHAREEXT"
    /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $myAppBuild" "$INFOPLIST_SHAREEXT"
    

  1. 像往常一样构建您的项目,您的共享扩展的版本和构建将与您的主要目标保持同步。

在尝试验证我的存档时,我收到错误消息 CFBundleShortVersionString 丢失。 为了解决这个问题,我在 xml 代码中进入 Info.plist 并添加了 CFBundleShortVersionString 新版本号 这以 plist 格式生成 Bundle versions string, short 这解决了我的问题

Twitch 分享了一个非常棒的版本管理系统。

在此 blog post, it is somewhat similar to stk's accepted 中进行了描述,但更清晰并且还支持以下内容:

  • 将内部版本号直接(并且可逆地)绑定到构建之前的 git 提交。轻松返回到为使用崩溃报告而构建的确切版本。

  • 通过目标依赖处理版本生成,更容易在多个目标之间共享。

  • 在 Info.plist 内置于 Xcode 构建设置中的功能上使用 C 预处理器,以允许即时替换版本号,无需修改 Info.plist 文件。

实现起来有点复杂,但它是我找到的最佳解决方案,尤其是当您有扩展或其他版本必须保持同步的目标时。

安装说明: 注意博客很好地描述了四个 shell 文件,但没有真正给出安装或定制说明。这是我所做的:

  1. 在项目的顶层创建一个 Versions 子目录(.xcodeproj 所在的位置)。

  2. 下载代码示例左下方的要点 link 指示的四个文件。将这四个文件移动到您的 Versions 目录中。

  3. 使用终端,cd 到您的 Versions 目录,然后执行命令:chmod +x * 使 shell 文件可执行

  4. 现在按照博客中的说明从头开始创建依赖目标。

  5. 您可能应该对脚本进行一些自定义。我更改了命名并重构以将 4 个工具移动到我跨项目共享的单独工具目录。 YMMV.

Xcode11+

1) 转到项目设置,选择 PROJECT(目标上方),转到 Build Settings
2) 按 Add User-Defined Setting 并添加 APP_BUILDAPP_VERSION
3) 在您的目标中转到 Info 并将 Bundle version 替换为 $(APP_BUILD) 并将 Bundle version string 替换为 $(APP_VERSION) 在您需要同步的所有目标和扩展中。
4)哇啦!您应该只在一个地方更改包版本 - 在您的项目的 Build Settings 中。

Xcode 12

我能够通过以下方式保持目标扩展版本和构建字符串与主应用程序同步:

  1. Compile Sources
  2. 上面加一个Run Script Phase
  3. 将以下内容添加到新创建的运行脚本的内容中:
WIDGET_EXTENSION="${SRCROOT}/MyWidget/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString ${MARKETING_VERSION}" "$WIDGET_EXTENSION"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion ${CURRENT_PROJECT_VERSION}" "$WIDGET_EXTENSION"

我利用了 stk 的出色答案,但我想提及一个问题,以便其他人知道:

为主要目标(主应用程序可执行文件)设置用户定义的常量导致将应用程序上传到商店时出错。至少在 Xcode 13.0 中,Xcode 在尝试创建 URL 参数以验证服务器版本号时崩溃了。直接设置主要目标的版本号解决了这个问题。所有其他“子目标”使用定义的常量都可以正常工作。