我想project.pbxproj
使用命令行直接编辑(用于 CI 服务器脚本)
什么工具可以让我做到这一点?
我以前用来PlistBuddy
编辑输出Info.plist
;但是,我真正想要做的是编辑这个用户定义的字段,它在多个地方使用,我真的不想在每个 plist 位置寻找它
我想project.pbxproj
使用命令行直接编辑(用于 CI 服务器脚本)
什么工具可以让我做到这一点?
我以前用来PlistBuddy
编辑输出Info.plist
;但是,我真正想要做的是编辑这个用户定义的字段,它在多个地方使用,我真的不想在每个 plist 位置寻找它
project.pbxproj
也是一个老式的 ASCII 属性列表文件。所以你可以用/usr/libexec/PlistBuddy
它来编辑它。
像这样打印一些用户定义键的值,
# Get the key A83311AA20DA4A80004B8C0E in your project.pbxproj
# LZD_NOTIFICATION_SERVICE_BUNDLE_ID is defined by me,
# Replace key paths with your own.
/usr/libexec/PlistBuddy -c 'print :objects:A83311AA20DA4A80004B8C0E:buildSettings:LZD_NOTIFICATION_SERVICE_BUNDLE_ID' LAAppAdapter.xcodeproj/project.pbxproj
像这样设置它的值,
/usr/libexec/PlistBuddy -c 'set :objects:A83311AA20DA4A80004B8C0E:buildSettings:LZD_NOTIFICATION_SERVICE_BUNDLE_ID com.dawnsong.notification-service' LAAppAdapter.xcodeproj/project.pbxproj
更新:自 macOS Catalina 或更早版本以来,PlistBuddy
将自动转换project.pbxproj
为 xml 格式的 plist 文件。请考虑将设置项移到xcconfig
文件中,因为它比使用脚本xcconfig
编辑时更小更简单project.pbxproj
且不易出错。perl
我知道这已经回答了一段时间,但由于最初的问题是关于支持.pbxproj
文件操作的工具,而且许多其他人可能正在寻找相同的信息,这就是我的做法。我花了很长时间才弄清楚这一点,因为当我开始尝试这个时我对 Xcode 非常不熟悉,所以我希望这可以为其他人节省我不得不投入的悲伤时间。
您可以使用该plutil
命令将.pbxproj
文件从旧.plist
格式转换为 XML 或 JSON 格式,您将能够更轻松地进行操作。我正在使用 JSON。为此,只需运行:
plutil -convert json project.pbxproj
project.pbxproj
这将转换project.json
. 将会发生的情况是project.pbxproj
将其转换为 JSON 格式,但保留它的神秘.pbxproj
扩展名。因此,即使文件的格式已更改,Xcode 仍会选择它并以新的 JSON 格式使用它。
然后,您可以project.pbxproj
使用您选择的任何 JSON 操作工具轻松更改。我JsonSlurper
在 Groovy 脚本中使用 Groovy 的类。
注意我还探索了 XML 选项,但我发现project.pbxproj
XML 格式的文件解析起来很麻烦。元素未正确嵌套以允许轻松遍历树。它困扰着:
<key>someKey</key>
<dict>
<!--More elements which provide configuration for the key above-->
</dict>
所以它本质上是定位的。您必须查找key
与您要操作的设置相对应的元素,然后跳转到紧随其后的dict
元素。这意味着您必须将每个 XML 元素的子元素挂载到一个数组中,以便对它们进行索引。
以下是 3 个实现 .pbxproj 文件编辑的开源工具:
就个人而言,我使用基于 NodeJS 的工具获得了最好的体验。到目前为止,它已经可靠地满足了我们所有的需求。
下面列出了一个示例 javascript 文件update-project.js
,该文件设置开发人员团队 ID、应用程序权利、将GoogleService-Info.plist
文件添加到项目并将其作为构建目标的一部分进行检查。以此为灵感,根据您的需要调整脚本及其路径:
const fs = require('fs')
const xcode = require('xcode')
if (process.argv.length !== 3) {
console.error("Please pass the development team ID as the first argument")
process.exit(1)
}
const developmentTeamId = process.argv[2]
const path = 'ios/App/App.xcodeproj/project.pbxproj'
const project = xcode.project(path)
project.parse(error => {
const targetKey = project.findTargetKey('App')
const appGroupKey = project.findPBXGroupKey({path: 'App'})
project.addBuildProperty('CODE_SIGN_ENTITLEMENTS', 'App/App.entitlements')
project.addBuildProperty('DEVELOPMENT_TEAM', developmentTeamId)
project.addFile('App.entitlements', appGroupKey)
project.removeFile('GoogleService-Info.plist', appGroupKey)
const f = project.addFile('GoogleService-Info.plist', appGroupKey, {target: targetKey})
f.uuid = project.generateUuid()
project.addToPbxBuildFileSection(f)
project.addToPbxResourcesBuildPhase(f)
fs.writeFileSync(path, project.writeSync())
})
上面的脚本可以执行
yarn run update-project <arguments...>
鉴于update-project
注册于package.json
:
{
...,
"scripts": {
...
"update-project": "node update-project.js"
},
...
}