Xcode 10 构建阶段 Shell 脚本

Posted

技术标签:

【中文标题】Xcode 10 构建阶段 Shell 脚本【英文标题】:Xcode 10 Build Phase Shell Script 【发布时间】:2018-09-26 18:46:53 【问题描述】:

在我们的项目中,我们从 git tag 等中派生发布版本,然后使用 shell 脚本将其写入构建文件夹的 Info.plist:

GIT_RELEASE_VERSION=$(some git command) defaults write "$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH%.*" "CFBundleShortVersionString" "$GIT_RELEASE_VERSION#*v"

这对所有过去的 Xcode 版本都运行良好,但在 Xcode 10 的新构建系统中,这实际上无法更新 info.list 文件中的 CFBundleShortVersionString。不过,该值已使用 Xcode 10 的 Legacy Build System 正确更新。

我在脚本中添加了一些回声,并比较了新系统和旧系统上的构建日志,看不出有任何区别:

echo "git release version:" $GIT_RELEASE_VERSION echo "info path:" $BUILT_PRODUCTS_DIR/$INFOPLIST_PATH%.* echo "grv:" "$GIT_RELEASE_VERSION#*v"

不确定是否有人在新构建系统中遇到过类似问题?

【问题讨论】:

我使用来自gist.github.com/airdrummingfool/ecfa9827f47c5d02af53 的代码,它可以工作:/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $version" "$TARGET_BUILD_DIR/$INFOPLIST_PATH"。不同之处在于将BUILT_PRODUCTS_DIR 替换为TARGET_BUILD_DIR。并确保此脚本是运行的最后一步。 感谢@Cœur,但更改为TARGET_BUILD_DIR 似乎对我的情况没有帮助 谁能发布完整的运行脚本来创建通用目标? @SatishMavani 您的问题与此处的原始问题并不真正相关。你能把它作为一个新线程发布吗? 【参考方案1】:

问题似乎是有时您的Run Script Phase 会在Xcode 创建Info.plist 之前执行。如果您想确保您的脚本阶段在特定步骤之后运行,您需要使用输入来标记您的依赖项。

例如,添加:

$(TARGET_BUILD_DIR)/$(INFOPLIST_PATH)

作为脚本阶段的输入,应强制执行您正在寻找的顺序:Xcode 将创建 Info.plist,之后的某个时间,您的脚本将执行并修改 Info.plist

【讨论】:

这对我有用:我有一个预编译脚本,它根据自上次标记以来的 git 提交计数更新内部版本号。为了避免影响存储库,我必须在处理完 info.plist 后重置内部版本号。将此添加到重置中即可实现。 完美 ? 我正在使用它来动态设置应用程序传输安全性 - 根据链接到我的方案的配置允许任意加载。 Xcode 在生成我试图修改的 plist 之前正在运行我的脚本。这修正了订单! 这成功了!我最初将括号打错为大括号,更正后,它可以工作。【参考方案2】:

(Xcode 11.2)

在新构建系统中,任何自定义构建步骤都将在新构建系统的Process .../Info.plist 步骤之前运行

要在 Xcode 完成构建后运行 shell 脚本,您可以将其作为构建后操作添加到您的方案中:

Product > Scheme > Edit Scheme... > Build > Post-actions

如果您要引用任何构建系统环境变量(例如 BUILT_PRODUCTS_DIRINFOPLIST_PATH),请务必更改 Provide build settings from 选择。

添加您的 shell 脚本,但请记住,如果您编辑应用程序包中的任何文件(即 Info.plist),则需要重新签署应用程序。将此添加到您的后期构建步骤中:

export CODESIGN_ALLOCATE=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate
/usr/bin/codesign --force --sign - --entitlements "$TARGET_TEMP_DIR/$FULL_PRODUCT_NAME.xcent" --timestamp=none "$CODESIGNING_FOLDER_PATH"

【讨论】:

【参考方案3】:

同样的问题...一种解决方法是清理然后执行完整构建。

Xcode 10 中的新构建系统在完整构建和增量构建中以不同方式运行 Process Info.plist 步骤:

完整构建:在处理资产之后,在链接故事板之前(链接 步骤) 增量:嵌入框架后,签名前。

实际的问题是作为构建步骤运行并更新已处理的 Info.plist 文件的脚本需要始终在文件处理之后但在签名之前运行。

【讨论】:

【参考方案4】:

与上面的答案类似(尚无法评论),但略有变化。

脚本输入文件:

$(PROJECT_DIR)/$(INFOPLIST_FILE)      
$(TARGET_BUILD_DIR)/$(INFOPLIST_PATH)

输出文件:

$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)

我用一个脚本创建了一个要点,用于设置捆绑版本和一些额外的信息,如标签、日期、分支。

https://gist.github.com/JoeMatt/aedd459c54a383373231719e508a2a36

【讨论】:

这对我不起作用。 @david G 的回答有效。添加此处建议的其他两个条目会导致错误:“invalid task blahblahblah with mutable output but no other virtual output node”

以上是关于Xcode 10 构建阶段 Shell 脚本的主要内容,如果未能解决你的问题,请参考以下文章

Xcode 9.2 Shell 脚本调用错误

Xcode 运行脚本构建阶段“仅在安装时运行脚本”选项

仅为 Xcode 4 中的“存档”构建运行脚本

在Xcode中切换运行脚本构建阶段

在 Xcode 构建阶段运行脚本中设置全局环境变量

单元测试目标中的 xcode RunUnitTests 脚本?