哪些工具支持编辑 project.pbxproj 文件?

Posted

技术标签:

【中文标题】哪些工具支持编辑 project.pbxproj 文件?【英文标题】:What tools support editing project.pbxproj files? 【发布时间】:2015-08-21 06:16:53 【问题描述】:

我想使用命令行直接编辑project.pbxproj(用于 CI 服务器脚本)

什么工具可以让我做到这一点?

我以前用PlistBuddy编辑输出Info.plist;但是,我真正想做的是编辑这个用户定义的字段,它在多个地方使用,我真的不想在每个 plist 位置寻找它

【问题讨论】:

嗨。你能解释一下你想编辑 .pbxproj 文件的内容吗? 用户定义字段 您可以尝试使用*.xcconfig 文件,加上user defined fields 可以从cmd 行重新定义。这是来自teamcity CI 的构建步骤:xcodebuild -project 'MyApp.xcodeproj' -scheme 'MyAppStaticTeamcity' -configuration 'Debug' -sdk 'iphoneos' GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS NS_BLOCK_ASSERTIONS=1 MY_LOG_LEVEL=2' clean build @Mozilla 实际上,我没有意识到您可以传入预处理器标志。如果我只想传入一个随机字段,这会直接起作用吗,比如"USER_DEFINED_VARIABLE=$hi" ?? 也许你走错路了。如果您有一个经常更改的参数,在* .plist 中作为设置执行它会更容易。替换* .plist 中的值比编辑项目文件或传递用户定义字段容易得多(请参阅plistbuddy)。在我的项目中,我将设置 server_address 放在 *.plist 中。 【参考方案1】:

project.pbxproj 也是一个old-style ASCII property list 文件。所以你可以使用/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

更新PlistBuddy 将自动将project.pbxproj 转换为 xml 格式的 plist 文件,因为 macOS Catalina 或更早版本。请考虑将设置项移到xcconfig文件中,因为xcconfigproject.pbxproj更小更简单,使用perl脚本编辑时不易出错。

【讨论】:

谢谢。很有帮助。这是 IMO 的正确答案。 project.pbxproj 打印值似乎工作正常,但是当我使用set 命令时,整个project.pbxproj 被转换为XML .plist 文件,Xcode 无法再读取。 @sachadso 我认为PlistBuddy-x 选项成为默认选项。这是strange。 Apple Doc 说,“因为您不能以旧式 (OpenStep) 格式保存属性列表,所以此方法唯一有效的格式参数是 NSPropertyListXMLFormat_v1_0 和 NSPropertyListBinaryFormat_v1_0”。我认为它解释了为什么以及会发生什么 @sachadso 没有找到解决方案,所以我停止尝试弄乱 .pbxproj 文件。【参考方案2】:

我知道这个问题已经回答了一段时间,但由于最初的问题是关于支持操作 .pbxproj 文件的工具,而且许多其他人可能正在寻找相同的信息,所以我就是这样做的。我花了很长时间才弄清楚这一点,因为当我开始尝试这个时,我对 Xcode 非常不熟悉,所以我希望这可以为其他人节省我不得不投入的悲伤时间。

您可以使用plutil 命令将.pbxproj 文件从旧的.plist 格式转换为您可以更轻松地操作的XML 或JSON 格式。我正在使用 JSON。为此,只需运行:

plutil -convert json project.pbxproj

这将转换project.pbxproj 的格式,但请注意 - 与常识相反 - 输出不会是另一个具有 JSON 扩展名的文件,例如 project.json。将会发生的事情是 project.pbxproj 将被转换为 JSON 格式,但保留它的神秘 .pbxproj 扩展名。因此,即使文件的格式已更改,Xcode 仍会拾取它并以新的 JSON 格式使用它。

然后,您可以使用您选择的任何 JSON 操作工具轻松更改 project.pbxproj。我在 Groovy 脚本中使用了 Groovy 的 JsonSlurper 类。

注意 我也探索了 XML 选项,但我发现 XML 格式的 project.pbxproj 文件解析起来很麻烦。元素未正确嵌套以允许轻松遍历树。它的困扰:

<key>someKey</key>
<dict>
    <!--More elements which provide configuration for the key above-->
</dict>

所以它本质上是位置性的。您必须查找与您要操作的设置相对应的key 元素,然后跳转到紧随其后的dict 元素。这意味着您必须将每个 XML 元素的子元素挂载到一个数组中,以便对它们进行索引。

【讨论】:

很好的解释。谢谢你分享这个。它为我节省了大量时间,也可能为其他许多人节省时间。 没问题@TheiosDev,你介意投票给我的答案吗?提前致谢。 将 pbxproj 文件转换为 JSON 对我不起作用。 Xcode 10 说文件已损坏,转换后无法打开。 @PaulSlocum 你试过升级plutil 命令吗?您可能正在使用旧的 plutil 版本,它无法处理由 Xcode 10+ 生成的 .pbxproj 格式,我使用的是 Brew。我刚试过brew outdated,得到了这个libplist (1.12) &lt; 2.0.0_1。我查了一下,找到了here。遗憾的是,plutil 中没有-v--version 选项,但brew upgrade libplist 会为您提供最新版本或说Error: libplist 2.0.0_1 already installed 哇,我不知道 Xcode 可以支持这个。谢谢!【参考方案3】:

这里有 3 个实现 .pbxproj 文件编辑的开源工具:

https://github.com/CocoaPods/Xcodeproj(基于 Ruby) https://github.com/apache/cordova-node-xcode(基于 NodeJS) https://github.com/kronenthaler/mod-pbxproj(基于 Python)

就个人而言,我使用基于 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 &lt;arguments...&gt;

假设update-project 注册在package.json


  ...,
  "scripts": 
    ...
    "update-project": "node update-project.js"
  ,
  ...

【讨论】:

以上是关于哪些工具支持编辑 project.pbxproj 文件?的主要内容,如果未能解决你的问题,请参考以下文章

我应该忽略 xcodeproject/project.pbxproj 文件吗?

project.pbxproj 始终在 git 中标记为已修改

文件的 project.pbxproj 散列 - 使用啥散列以及如何使用?

升级本机反应时如何解决“project.pbxproj”文件中的冲突?

聊聊 Xcode 项目文件中的 project.pbxproj

Runner.xcodeproj/project.pbxproj 中硬编码的 FLUTTER_ROOT