【问题标题】:How can I conditionally include a file based on build configuration in Xcode?如何在 Xcode 中有条件地包含基于构建配置的文件?
【发布时间】:2026-01-19 10:25:01
【问题描述】:

我有一个包含大量目标的 Xcode 项目,我想在其中包含一个设置包,用于在 Ad-hoc 和 Debug 配置下构建的应用程序,但不在 Release 配置下。

构建阶段似乎不允许以配置为条件(它们显然可以以目标为条件,但将项目中的目标数量加倍将使其完全无法使用)。

剩下的就是编写自定义构建规则。我的计划是从所有目标中排除 Settings.bundle,并创建一个有条件地将其复制到产品包中的构建规则,但是很难找到适用的示例。

我开始的构建规则将 Process 设置设置为“名称匹配的源文件:”并将 Settings.bundle 作为名称。使用设置是“自定义脚本:”。

我的自定义脚本如下(需要注意的是我的 bash 脚本处于货物崇拜级别):

if [${CONFIGURATION} = 'Debug'] then
    cp -r ${INPUT_FILE_PATH} ${DERIVED_FILES_DIR}/.
fi

最后,我将${DERIVED_FILES_DIR}/Settings.bundle 列为输出文件。

既然我在这里,应该很明显它不起作用。我的第一个问题是我是否可以在某个地方查看构建规则的输出作为执行,以确保 1)它实际上正在执行,并且 2)我在某处没有愚蠢的语法错误。

另外,将输出复制到的正确位置(以环境变量的形式)是什么?

【问题讨论】:

    标签: xcode build-rules


    【解决方案1】:

    我终于明白了。

    对于您希望有条件地包含设置包的每个目标,从源列表中选择其项目,选择目标,然后切换到“构建阶段”选项卡。

    单击“添加构建阶段”按钮并选择“添加运行脚本”。

    然后为脚本输入以下内容:

    if [ "${CONFIGURATION}" == "Debug" ]; then
        cp -r "${PROJECT_DIR}/Settings.bundle" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app"
    fi
    

    【讨论】:

    • 谢谢,我已经习惯了为不同配置管理firebase项目plist文件的方法。
    【解决方案2】:

    我知道这个问题已经得到解答,而且答案对我很有帮助,但我也想把我自己修改后的解决方案扔出去。

    我的要求是为不同的构建配置提供不同的设置包,而不是在发布时不包括它。假设只有 DebugRelease 配置的简单方法,这里是如何做到的:

    首先将 2 个设置包添加到项目中,名为 Settings-debug.bundleSettings-release.bundle,然后从 复制包资源 构建阶段删除这些文件。接下来添加一个名为SETTINGS_BUNDLE 的用户定义构建设置,每个配置都有不同的值:

    Debug        ${PROJECT_DIR}/relative/path/to/Settings-debug.bundle
    Release      ${PROJECT_DIR}/relative/path/to/Settings-release.bundle
    

    接下来添加一个名为 Copy Settings Bundle 的运行脚本构建阶段(在 Copy Bundle Resources 之后),其中包含 Frank 解决方案中脚本的修改版本。

    cp -r "${SETTINGS_BUNDLE}/" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/Settings.bundle"
    

    这里的区别在于,无论源名称如何,复制的包始终命名为 Settings.bundle

    然后,您需要添加另一个构建阶段脚本,以防止在设置包中仅有更改时出现代码签名错误。它强制代码签名步骤发生在每个构建上。这应该在编译源文件构建阶段之前运行。我叫我的Force Codedesign

    touch "${PROJECT_DIR}/relative/path/to/main.m"
    

    【讨论】:

    • 内置设置应用程序中仅调试应用程序首选项窗格的绝佳解决方案,这就是我所追求的。非常感谢!
    • 你也可以这样写:cp -r "${PROJECT_DIR}/settings_bundle/Settings-${CONFIGURATION}.bundle/" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/Settings.bundle " 这将使您避免添加任何用户定义的构建条目,并将使用文件 'settings_bundle/Settings-Debug.bundle'、'settings_bundle/Settings-Release.bundle' 等
    • 作为 SETTINGS_BUNDLE 变量,我使用了 ${PROJECT_DIR}/${PROJECT_NAME}/Resources/Settings.bundle
    • 而不是在 Copy Bundle Resources 构建阶段查找文件以将其删除,只需在文件检查器中删除捆绑文件的任何目标成员身份。更快。
    【解决方案3】:

    对于已编译的源,可以添加记录不充分的用户定义构建设置。文件既可以从编译中排除也可以包含在编译中

    转到目标的构建设置 > 点击 + 按钮 > 添加用户定义的设置

    密钥是INCLUDED_SOURCE_FILE_NAMESEXCLUDED_SOURCE_FILE_NAMES

    该值为以空格分隔的文件路径列表

    见参考: http://lists.apple.com/archives/xcode-users/2009/Jun/msg00153.html

    【讨论】:

    • 我可以确认在 Xcode 8.2..x 中添加 EXCLUDED_SOURCE_FILE_NAMES 仍然有效(并且仍然未记录)
    【解决方案4】:

    (使用 Xcode 9.3 测试)

    我找不到 Xcode 何时包含此功能,但 EXCLUDED_SOURCE_FILE_NAMES 现在可以直接在 Build Settings > Build Options > Excluded Source File Names 中使用。

    因此您不再需要创建User-Defined Setting

    见下文:

    它会自动在您的.pbxproj 中添加这一行。

    【讨论】:

    • 是否有理由使用EXCLUDED_SOURCE_FILE_NAMES 的显式排除而不是INCLUDED_SOURCE_FILE_NAMES 的显式包含?当我使用包含时,它直接不起作用。尝试使用原始 json 文件和 xcassets 文件
    【解决方案5】:

    无论是发布还是调试配置,Settings.bundle 总是被复制到目标区域。所以,也许你需要以下代码:

    if [ ${CONFIGURATION} == "Release" ]; then
        rm -rf ${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/Settings.bundle
    fi
    

    【讨论】:

      【解决方案6】:

      我不是 shell 脚本专家,但我认为您需要在方括号和条件之间留出空格。此外,引用变量可能会有所帮助:

      if [ "${CONFIGURATION}" = "Debug" ] then
          cp -r "${INPUT_FILE_PATH}" "${DERIVED_FILES_DIR}"/.
      fi
      

      至于位置,我使用"$BUILT_PRODUCTS_DIR"/"$FULL_PRODUCT_NAME" 作为我的 OS X 应用程序包的根目录。

      【讨论】:

      • 这在我构建时给了我语法错误。弗兰克的解决方案,复制粘贴后效果很好。
      • 公平地说,这个人的答案是三个月前发布的。