iOS 项目中获取 Git Commit Hash:写入 Info.plist 并在代码中读取

慢慢来
慢慢来
发布时间:2026-08-22 | 23人浏览过
原创

前言

在 iOS 项目里拿到当前构建对应的 Git 提交哈希和分支名,最常见的需求不是“能不能取到”,而是“怎样稳定写进包里并在代码中直接读取”。这篇文章把 Xcode 构建脚本、Info.plist 字段预留、PlistBuddy 写入方式以及 User Script Sandboxing 的权限影响放到一条链路里讲清楚,便于你快速判断该如何配置。

在 iOS 项目里记录构建时对应的 Git 提交信息,常见用途包括问题追踪、灰度排查和测试包比对。比较直接的做法,是在 Xcode 构建阶段把当前分支名和提交哈希写进 Info.plist,再由应用运行时读取;如果过程中遇到 Operation not permitted,通常还需要一并检查 User Script Sandboxing 的限制。

下面按“为什么会报权限错误、Info.plist 需要准备什么、脚本怎么写、代码如何读取”几个问题展开,方便你直接照着配置,也能判断这种方案在哪些场景下适合使用。

为什么脚本会遇到权限错误

User Script Sandboxing 用来控制 Xcode 构建脚本的沙盒限制。默认情况下,Xcode 会把脚本放进沙盒环境,对文件系统访问进行约束;当脚本需要读取或修改某些目录内容时,尤其是项目目录之外的文件,比较容易遇到权限问题。

说明 User Script Sandboxing 关闭前后对构建脚本文件访问范围和风险差异的对比信息图
User Script Sandboxing用对比结构梳理关闭 User Script Sandboxing 的作用、收益和边界。

如果构建脚本报出 Operation not permitted,可以先检查这一项设置。将 User Script Sandboxing 设置为 NO 后,脚本可以访问文件系统中的更多位置,从而避免这类错误。

如何关闭 User Script Sandboxing

  • 在项目的 TARGETS 中打开 Build Settings。
  • 搜索 User Script Sandboxing。
  • 将它设置为 NO。

完成后,构建脚本在执行期间会拥有更宽松的文件访问能力,更适合需要读写 Info.plist 或其他构建产物的场景。

关闭沙盒前要注意什么

  1. 安全性:禁用沙盒后,脚本拥有更高的文件系统访问权限。如果脚本里包含不受信任的操作,构建过程的风险也会随之增加。
  2. 系统权限:即便关闭了沙盒,系统级权限仍然可能影响文件读写。比如涉及 /etc/ 或 /System/ 这类目录时,依然可能需要管理员权限。

因此,这个设置适合用于你能够确认脚本来源、且确实需要额外访问权限的项目环境。

先在 Info.plist 里预留 Git 字段

要把 Git 信息带进应用,第一步是确保 Info.plist 里有对应字段。你可以手动先加好键值,也可以配合构建脚本动态更新。

文中的字段包括两个:

  • GitCommitHash
  • GitBranch

对应内容如下:

<key>GitCommitHash</key>
<string>your_git_commit_hash_here</string>
<key>GitBranch</key>
<string>your_git_branch_here</string>

其中,your_git_commit_hash_here 和 your_git_branch_here 只是占位内容,后续会在构建阶段被脚本替换成当前仓库的真实值。

在构建阶段把 Git 信息写入 Info.plist

准备好字段后,就可以在 Xcode 的构建流程中加入自定义脚本。这个脚本会读取当前 Git 仓库状态,拿到短提交哈希和当前分支名,再写回 Info.plist。

说明 Xcode 构建脚本如何获取 Git 提交哈希与分支名,并写入 Info.plist 后供应用读取的流程图
Git 信息写入与读取流程用流程图展示 Git 信息从仓库进入 Info.plist,再到运行时读取的路径。

在 Xcode 中添加 Run Script Phase

  1. 在 Xcode 中选择对应项目目标。
  2. 进入 Build Phases。
  3. 点击左上角 +,选择 New Run Script Phase。
  4. 把下面的脚本加入脚本输入框。
#!/bin/bash

# 获取当前 Git 提交的哈希值(短格式)
commit_hash=$(git rev-parse --short HEAD)

# 获取当前 Git 分支的名称
branch_name=$(git rev-parse --abbrev-ref HEAD)

# 获取 Info.plist 文件路径
plist_path="${PROJECT_DIR}/YourProject/Info.plist"  # 请替换为实际路径

# 修改 Info.plist 中的 Git 信息
/usr/libexec/PlistBuddy -c "Set :GitCommitHash $commit_hash" "$plist_path"
/usr/libexec/PlistBuddy -c "Set :GitBranch $branch_name" "$plist_path"

保存后重新构建,脚本会在每次构建时执行,并把当前的 Git 提交哈希和分支名称写入 GitCommitHash、GitBranch 这两个键。

这个脚本实际做了什么

  • 通过 git rev-parse --short HEAD 获取当前提交的短哈希。
  • 通过 git rev-parse --abbrev-ref HEAD 获取当前分支名称。
  • 通过 /usr/libexec/PlistBuddy 修改指定 Info.plist 中的键值。

要注意的是,脚本中的 ${PROJECT_DIR}/YourProject/Info.plist 只是示例路径,必须替换成项目里的实际文件位置,否则写入不会生效。

应用运行时如何读取 Git 信息

写入完成后,应用侧就可以直接从 Bundle.main.infoDictionary 读取这些值。原文给出的 Swift 示例如下:

// MARK: - Git 相关信息

/// 获取 Git 提交版本号
static var gitCommitHash: String {
    guard let commitHash = Bundle.main.infoDictionary?["GitCommitHash"] as? String else {
        return "未知提交"
    }
    return commitHash
}

/// 获取 Git 分支名称
static var gitBranch: String {
    guard let branch = Bundle.main.infoDictionary?["GitBranch"] as? String else {
        return "未知分支"
    }
    return branch
}

这种读取方式的好处是实现简单,不需要额外依赖;只要构建阶段已经把值写进包内配置,运行时就能直接取到。对于调试页、关于页面、崩溃日志附带版本信息等场景,这种做法都比较实用。

适用场景与配置要点

整套做法可以概括为三步:

  • 先在 Info.plist 中预留 GitCommitHash 和 GitBranch 键。
  • 在 Build Phases 中添加脚本,利用 Git 和 PlistBuddy 在构建时写入实际值。
  • 在代码里通过 Bundle.main.infoDictionary 读取并展示。

如果构建阶段报权限错误,再回头检查 User Script Sandboxing 是否需要设为 NO。这能解决不少脚本访问受限的问题,但同时也意味着你需要更谨慎地管理构建脚本的安全边界。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表