Интегрированные среды разработки
Прощай, project.pbxproj, здравствуй, JSON: крупнейшее изменение Xcode за 30 лет
Apple наконец заменила самый пугающий файл в каждом iOS-репозитории. Вот что изменилось, как перейти на новый формат и стоит ли это делать — с объяснениями для джунов, сеньоров и тимлидов.
Apple наконец заменила самый пугающий файл в каждом iOS-репозитории. Вот что изменилось, как перейти на новый формат и стоит ли это делать — с объяснениями для джунов, сеньоров и тимлидов.
Проблема, которую знает каждый iOS-разработчик
Если вы когда-нибудь открывали pull request, добавляющий всего два Swift-файла, и видели, как project.pbxproj внезапно разрастается на 30+ строк изменений с такими строками:
7B2A1F4E2C8D9A3B00F1E2D3 /* PaymentView.swift in Sources */ = {
isa = PBXBuildFile;
fileRef = 7B2A1F4D2C8D9A3B00F1E2D3 /* PaymentView.swift */;
};
…то вы уже понимаете, почему это изменение важно. Десятилетиями стандартная командная политика при проверке diff-файлов pbxproj выглядела примерно так: «одобрить с закрытыми глазами и надеяться, что сегодня больше никто его не трогал».
С Xcode 27.2 эта эпоха заканчивается. Файл конфигурации проекта теперь использует JSON.
Предыстория: что такое project.pbxproj и почему он причинял столько боли
Внутри каждого пакета .xcodeproj находится один конфигурационный файл, описывающий весь проект: какие файлы существуют, к каким target они относятся, настройки сборки и фазы сборки.
До сих пор этим файлом был project.pbxproj — ASCII-формат property list, доставшийся Apple ещё от NeXTSTEP, то есть ему уже больше 30 лет. У него было три фундаментальные проблемы:
1. Плоский граф объектов, склеенный 24-символьными шестнадцатеричными ID. Каждый файл, группа, target и build phase представляли собой объект с идентификатором вроде 7B2A1F4E2C8D9A3B00F1E2D3, а сами объекты ссылались друг на друга по этим ID из совершенно разных частей файла. Человек это нормально читать не мог, а инструментам приходилось заниматься реверс-инжинирингом формата.
2. Одно действие означало изменения в 3–4 местах. Добавление одного файла заставляло Xcode записывать PBXFileReference, PBXBuildFile, запись в PBXGroup и запись в build phase Sources нужного таргета — четыре разрозненных изменения ради одного клика.
3. Это была фабрика merge-конфликтов. Когда два разработчика добавляли файлы в разных ветках, git видел два набора неупорядоченных изменений, изобилующих ID и попадающих в пересекающиеся области одного огромного файла. В результате появлялся страшный <<<<<<< HEAD внутри файла, который человек не мог безопасно править вручную. Во многих командах неофициально существовал отдельный «специалист по исправлению конфликтов pbxproj».
Что нового в Xcode 27.2
В Xcode 27.2 и новее конфигурацией проекта по умолчанию становится project.xcproj — более компактный, иерархический и самоописываемый файл в формате JSON. Из официальной документации Apple:
«В Xcode 27.2 и новее файлом конфигурации проекта по умолчанию является более компактный, иерархический и самоописываемый JSON-файл с расширением .xcproj. Xcode 27 и новее поддерживает оба формата файлов, поэтому вы можете выбрать тот, который предпочитаете».
Вот как выглядит минимальный проект в новом формате:
{
"default-configuration": "Debug",
"configurations": ["Debug", "Release"],
"files": [
{
"kind": "group",
"path": "Sources",
"children": [
{ "path": "PaymentView.swift", "target-membership": ["MyApp/compile-sources"] }
]
}
],
"targets": [
{
"name": "MyApp",
"build-settings": {
"IPHONEOS_DEPLOYMENT_TARGET": "27.0",
"SWIFT_OPTIMIZATION_LEVEL[config=Debug]": "-Onone"
}
}
]
}
Его сможет прочитать даже джун. Ревьюер сможет нормально проверить изменения. Git сможет их нормально слить.
Что решает новый формат
Обратные связи. Вместо того чтобы target перечисляли файлы через цепочки ID-ссылок, теперь каждый файл сам объявляет своё членство в target через target-membership. Добавление файла теперь означает одну строку в одном месте, а не четыре изменения в четырёх секциях. Уже одно это устраняет большую часть исторических merge-конфликтов.
ID почти исчезают. Идентификаторы остаются только там, где они действительно нужны, например у target и продуктов. Diff больше не выглядит как утечка ключей шифрования.
Настройки сборки схлопываются. Вместо дублирования целых блоков XCBuildConfiguration для каждой конфигурации условие можно указать прямо в одной строке настройки: "SETTING[config=Debug]": "value". В одном из примеров сообщества примерно 300 строк property list превратились примерно в 123 строки JSON.
Diff теперь соответствует вашим действиям. В документации Apple говорится, что изменения в режиме сравнения теперь соответствуют тому, что вы реально сделали в Xcode. Переименовали файл? Diff покажет переименование файла, а не пятнадцать изменившихся шестнадцатеричных ссылок.
Меньше merge-конфликтов. Поскольку структура JSON иерархическая и изолирует изменения конфигурации, два разработчика, добавляющие файлы в разные группы, просто не сталкиваются друг с другом.
Coding agents могут безопасно редактировать проекты. Apple явно проектировала формат с расчётом на эпоху ИИ — в документации он называется «более удобным для редактирования агентами coding intelligence». Агент, добавляющий файл, теперь вставляет один JSON-узел вместо синхронизации четырёх перекрёстно связанных таблиц. Apple также выпустила open-source Swift-библиотеку xcode-project-format, которая даёт инструментам типизированный доступ к структуре проекта, поэтому экосистеме больше не нужно заниматься реверсом формата.
Как перейти
Новые проекты — ничего делать не нужно
Любой проект, созданный в Xcode 27.2 или новее, использует формат JSON по умолчанию. Вы получаете project.xcproj с самого начала, без каких-либо флагов или дополнительных настроек.
Существующие проекты — один выпадающий список
Существующие проекты не конвертируются автоматически; Apple оставляет решение за вами. Переход занимает считаные секунды:
- В Project navigator выберите проект.
- Откройте File inspector (⌥⌘1).
- В разделе Project Document откройте выпадающее меню Project Format и выберите JSON.
- Если появится диалог, нажмите Continue.
Внутри вашего .xcodeproj файл project.pbxproj будет удалён, а project.xcproj — добавлен. Закоммитьте оба изменения вместе отдельным коммитом с понятным сообщением.
Для автоматизации во множестве репозиториев xcodebuild предлагает вызов -convert-project, а Apple также поставляет инструмент xcprojformatter для проверки и форматирования .xcproj-файлов.
Откат
Если вы используете систему контроля версий, отменить переход очень просто, и это официально задокументировано: отмените два изменения файлов — удаление .pbxproj и добавление .xcproj — и проект вернётся к старому формату.
Чек-лист перед миграцией
- Все уже на Xcode 27+? Формат JSON совместим только с Xcode 27 и новее. Коллега на Xcode 26 не сможет открыть конвертированный проект — это жёсткое ограничение.
- Проверьте CI и инструменты. Всё, что парсит или изменяет файл проекта, должно понимать JSON: CocoaPods, XcodeGen, Tuist/XcodeProj, Capacitor, плагины fastlane, собственные скрипты. Поддержка быстро появляется по всей экосистеме, но перед конвертацией проверьте каждый инструмент отдельно.
- Конвертируйте в спокойный момент. Делайте это отдельным PR без других изменений, желательно сразу после релиза, чтобы долгоживущим веткам не пришлось ребейзиться через границу смены формата.
- Понимайте масштаб. Меняется только файл конфигурации проекта. Schemes,
Package.resolved, данные workspace и пользовательские данные не затрагиваются. Сама сборка не меняется — меняется только её описание.
Плюсы и минусы
Плюсы
- Радикально меньше merge-конфликтов в самом конфликтном файле большинства iOS-репозиториев — это реально возвращает команде часы времени в каждом спринте.
- Diff можно нормально ревьюить. Изменения файла проекта снова становятся полноценной частью code review, а не местом, где все просто нажимают Approve.
- Меньший и читаемый человеком файл, чья иерархия отражает то, что вы видите в Project navigator.
- Полноценная поддержка ИИ-инструментов. Coding agents, включая собственные интеллектуальные функции Xcode, могут надёжно редактировать проект, а open-source библиотека
xcode-project-formatдаёт сторонним инструментам официальную основу. - Низкорисковая и обратимая миграция с официально задокументированным Apple путём отката и поддержкой обоих форматов бок о бок в Xcode 27.
Минусы
- Жёсткое требование Xcode 27+. Один человек в команде или один CI-образ на старой версии Xcode блокирует переход для всех.
- Экосистема пока отстаёт. Инструменты, которые читают или записывают
pbxproj, ещё догоняют новый формат; некоторые, например Capacitor, сообщали о поломках уже в первую неделю после выхода 27.2. Если ваш pipeline сильно зависит от инструментов, изменяющих проект, лучше дождаться их обновлений. - Эволюция, а не революция. Это не вручную написанный manifest вроде
Package.swiftили DSL от Tuist. Xcode остаётся основным редактором; по-прежнему не стоит вручную писать этот файл как часть обычного рабочего процесса. - Документация пока скудная. Apple описывает миграцию, но не публикует полную спецификацию формата — Swift-библиотека сейчас ближе всего к роли справочника.
Кому и когда стоит переходить
Переходите сейчас, если вся команда уже на Xcode 27+, проект управляется напрямую в Xcode, а конфликты pbxproj регулярно отнимали время. Улучшенные diff и снижение числа конфликтов окупают десятисекундную конвертацию практически сразу.
Переходите позже, если вы сильно зависите от CocoaPods или других инструментов, изменяющих проект, либо если кто-то из команды или какая-то CI-машина всё ещё работает на старом Xcode. Для новых проектов уже используйте JSON, а существующие переводите после того, как ваши инструменты добавят поддержку.
Ничего срочного не меняется, если источником истины у вас является XcodeGen или Tuist — сгенерированный проект у вас всё равно одноразовый. Переходите на новый формат, когда ваш генератор начнёт создавать .xcproj.
Итог
Apple заменила 30-летний, забитый ID и постоянно конфликтующий plist на чистый иерархический JSON-формат, который могут читать люди, нормально сливать git и редактировать ИИ-агенты. Миграция выполняется одним выбором в меню, полностью обратима и ограничивается только версией Xcode в вашей команде и совместимостью инструментов. Для большинства команд это редкий пример платформенного изменения, которое почти ничего не стоит, но окупается в каждом спринте.
-
Разработка3 недели назадДаем ИИ видеть SwiftUI: Xcode Preview MCP на практике — проблемы и надежды
-
Новости4 недели назадВидео и подкасты о мобильной разработке 2026.39
-
Новости3 недели назадВидео и подкасты о мобильной разработке 2026.40
-
Новости2 недели назадВидео и подкасты о мобильной разработке 2026.41
