移动/游戏
在无头/CI 环境中用 C# Client API 管理…
当需要在编辑器之外以无头或 CI 方式添加、移除、升级或查询 Unity UPM 包时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
在无头/CI 环境中用 C# Clien特定
解决思路
- 不要手动编辑 Packages/manifest.json,改用 UnityEditor.PackageManager.Client API,因为它能正确解析依赖和兼容版本。
- 先根据项目实际需要(模板已提供的包优先)确定去重后的包 id 列表,并在安装前向用户复述确认。
- 把安装脚本写到 Assets/Editor/ProjectBootstrap/PackageInstaller.cs(必须位于 Editor/ 文件夹或 Editor-only 程序集下,因为它使用 UnityEditor)。
- 在脚本中编辑 PackagesToAdd 数组列出要安装的包 id;要移除的包放入 PackagesToRemove 数组;用 @<version> 固定或升级版本(如 com.unity.cinemachine@2.9.7),不带版本则解析最新兼容版本。
- 用 Client.AddAndRemove(packagesToAdd, packagesToRemove) 在一次 UPM 解析中完成整组安装/移除,比逐个 Client.Add 更快更不易出错。
- 由于 Client.Add/AddAndRemove 是异步的(只在后续 EditorApplication.update tick 完成,阻塞式忙等会死锁),安装时不要用 unity run(它会注入 -quit 导致编辑器在 UPM 解析前退出),而要直接以 -batchmode 启动编辑器二进制且不传 -quit。
- 在脚本中订阅 EditorApplication.update 轮询请求:未完成时检查超时(如 600 秒),完成后根据 StatusCode 记录结果并调用 EditorApplication.Exit(0/1/2) 自行退出并设置退出码。
- 用 unity editors path "$VERSION" --format json 解析出编辑器安装目录,再按操作系统解析可执行文件路径(macOS 处理 Unity.app/Contents/MacOS/Unity,Linux 用 Editor/Unity,Windows 用 Editor/Unity.exe)。
- 以 "$UNITY_BIN" -batchmode -projectPath "$PROJECT" -executeMethod "$METHOD" -logFile - 运行,-logFile - 把编辑器日志(含 [PackageInstaller] 行)流式输出到 stdout 以便观察解析进度和 UPM 错误。
- 要确认包 id 是否存在或列出可用版本时,写 Assets/Editor/ProjectBootstrap/PackageSearch.cs,用 Client.SearchAll() 或 Client.Search("<id>"),采用与安装器相同的轮询加 Exit 模式和相同的无头运行方式。
- 在搜索脚本中遍历 _request.Result(PackageInfo[]),输出每个包的 name、displayName、versions.latestCompatible 等,并记录找到的包数量。
- 仅需终端校验已知包 id(非自由文本搜索)时,直接查询 Unity registry,参见 references/select-packages.md。
- 运行后检查退出码(0 成功、1 UPM 错误、2 超时),并用 cat "<project-path>/Packages/manifest.json" 确认每个请求的包都作为依赖出现;若解析失败,读取 _request.Error.message 并对照 registry 检查 id/版本。
- 当脚本或工具写入新的 .cs/asset 文件后,需要无头生成 .meta 文件时,写 Assets/Editor/ProjectBootstrap/ProjectSaver.cs,调用 AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate) 和 AssetDatabase.SaveAssets() 后 EditorApplication.Exit(0)。
- 该导入保存是同步的,可安全用 unity run "<project-path>" --editor-version <version> -- -executeMethod ProjectBootstrap.ProjectSaver.SaveAll 运行。
- 每个 .cs/asset 必须与其 .meta 文件一起提交;这些引导脚本可保留在 Assets/Editor/ProjectBootstrap/(不调用则无副作用)或安装后删除,并告知用户。
- 变现/后端包(com.unity.purchasing、com.unity.services.levelplay、UGS 包)用同一机制安装,但实际集成走专门技能:implement-in-app-purchases、levelplay-unity-integration、build-live-game。
适用边界 · 注意事项
- 不要用 unity run 执行包安装(其默认注入 -quit 会让编辑器在 UPM 解析完成前退出,导致包未安装、回调不执行)。
- 不要手动编辑 Packages/manifest.json 来增删包,会破坏依赖解析。
- 不要用阻塞式 while (!req.IsCompleted) 忙等异步请求,会死锁 UPM 子进程。
- 不要用 unity logs 查看编辑器日志(它显示的是 CLI 自身日志),应通过 -logFile - 流式读取。