Настройка dSYM загрузки для деобфускации крашей iOS
Firebase Crashlytics показывает 0x000000010034a5c8 вместо PaymentViewController.swift:142 — и разработчик тратит час на то, чтобы понять, что вообще упало. dSYM-файлы (debug symbol maps) решают эту проблему, но их загрузка в крэш-репортинг регулярно ломается по нескольким неочевидным причинам.
Почему dSYM не попадают в Crashlytics
Самая частая ситуация: Bitcode был включён, Apple перекомпилировала бинарник на своих серверах — и dSYM для этой конкретной сборки живёт уже не в Xcode Organizer, а в App Store Connect. Crashlytics получает устаревшие символы от локальной сборки и не может сопоставить адреса. Результат — все крэши в продакшене приходят обфусцированными.
Вторая проблема — автоматическая загрузка через Run Script не срабатывает при сборке на CI. Скрипт ${PODS_ROOT}/FirebaseCrashlytics/run выполняется в Build Phase, но на агенте без keychain Firebase CLI не может аутентифицироваться. Крэши начинают накапливаться деобфусцированными с первого же релиза.
Как мы настраиваем загрузку dSYM
Базовая настройка через Run Script
Для проектов без Bitcode и с ручным CI достаточно корректно настроенного Build Phase:
# Build Phase: Run Script
"${PODS_ROOT}/FirebaseCrashlytics/run"
В поле Input Files обязательно указать:
${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}
$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)
Без Input Files Xcode пропускает скрипт при инкрементальных сборках — Crashlytics не получает новые символы.
Загрузка dSYM из App Store Connect
Когда Bitcode включён (или для App Clips), dSYM нужно скачивать отдельно:
# Fastlane: download_dsyms + upload_symbols_to_crashlytics
lane :refresh_dsyms do
download_dsyms(
app_identifier: "com.example.app",
version: "2.1.0",
build_number: "210"
)
upload_symbols_to_crashlytics(
dsym_paths: Actions.lane_context[SharedValues::DSYM_PATHS]
)
clean_build_artifacts
end
Эту lane можно запускать по расписанию через CI (например, раз в день после выхода новой сборки в App Store) или как post-deploy шаг.
Ручная загрузка через Firebase CLI
Если Fastlane не используется:
firebase crashlytics:symbols:upload \
--app=1:123456789:ios:abcdef \
MyApp.app.dSYM.zip
Файл dSYM находится в ~/Library/Developer/Xcode/Archives/ после архивирования, либо скачивается из Xcode Organizer → Archives → Download Debug Symbols.
Проверка корректности символов
После загрузки проверяем через Firebase Console: Crashlytics → выбрать крэш → убедиться, что стектрейс показывает имена методов и строки кода. Если по-прежнему адреса — UUID dSYM не совпадает с UUID бинарника.
Проверить UUID:
# UUID бинарника
dwarfdump --uuid MyApp.app/MyApp
# UUID dSYM
dwarfdump --uuid MyApp.app.dSYM
Оба должны совпадать. Расхождение означает, что загружен dSYM от другой сборки.
Интеграция со Sentry
Для проектов на Sentry вместо Firebase процесс аналогичен, но через sentry-cli:
sentry-cli upload-dif \
--org my-org \
--project ios-app \
--include-sources \
MyApp.app.dSYM
Флаг --include-sources позволяет показывать исходный код прямо в Sentry — удобно для команд без доступа к локальному репозиторию во время дежурства.
Настройка на CI/CD
На Bitrise, GitHub Actions или GitLab CI загрузка dSYM встраивается в pipeline после шага архивирования:
# GitHub Actions пример
- name: Upload dSYM to Crashlytics
env:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
run: |
fastlane run upload_symbols_to_crashlytics \
dsym_path:"./MyApp.app.dSYM.zip" \
gsp_path:"./GoogleService-Info.plist"
FIREBASE_TOKEN получается через firebase login:ci — токен не истекает и безопасен для хранения в секретах CI.
Процесс работы
Аудит текущей настройки: проверяем Build Phase, наличие Input Files, историю загрузок в Firebase Console.
Определяем источник dSYM: локальная сборка или App Store Connect (зависит от наличия Bitcode/App Clip).
Настраиваем автоматическую загрузку: Fastlane lane или CI шаг после каждого релизного билда.
Верифицируем: создаём тестовый крэш через fatalError() в Debug-сборке, проверяем символизацию в Console.
Ориентиры по срокам
Настройка для проекта без Bitcode с уже работающим CI — 2–4 часа. Если нужно настроить регулярное скачивание из App Store Connect и интеграцию с несколькими крэш-репортинг сервисами — 1 рабочий день.







