Когда после подключения или обновления платежного плагина Flutter либо React Native проект перестает собираться, сообщение «dependency conflict» описывает только верхний слой проблемы. Конфликт может находиться в Dart- или JavaScript-пакетах, Android Gradle/Maven, iOS CocoaPods, минимальной версии платформы, Kotlin, Swift либо в двух нативных SDK, которые включают несовместимые варианты одной библиотеки. Поэтому случайное удаление lock-файлов и обновление всего проекта часто превращает одну понятную ошибку в несколько новых.

Безопасная задача — не заставить сборку пройти любой ценой, а получить воспроизводимый набор совместимых версий и затем проверить платежный сценарий. Платежный модуль затрагивает токены, 3-D Secure, возврат в приложение, callbacks и серверное подтверждение оплаты. Сборка, которая компилируется после принудительного понижения SDK, но неверно обрабатывает статус операции, не является исправленной.

Сначала сохраните рабочую точку и полный текст ошибки

До изменения зависимостей зафиксируйте текущий commit, lock-файлы, версии инструментов и последний успешно собранный релиз. Не начинайте с удаления pubspec.lock, package-lock.json, yarn.lock, Podfile.lock или Gradle caches. Эти файлы помогают сравнить рабочее и сломанное разрешение графа. Очистка кеша уместна только после доказанного повреждения артефакта, а не как универсальный первый шаг.

  • сохраните pubspec.yaml или package.json и соответствующий lock-файл;
  • запишите версию Flutter или React Native, Dart, Node.js и менеджера пакетов;
  • зафиксируйте Android Gradle Plugin, Gradle, Kotlin, compileSdk и minSdk;
  • запишите Xcode, CocoaPods и минимальную версию iOS;
  • сохраните точную версию платежного плагина и нативного SDK провайдера;
  • скопируйте первую содержательную ошибку, а не только последние строки stack trace;
  • отметьте команду и вариант сборки: debug, release, flavor, simulator или device;
  • не прикладывайте merchant secret, API key, keystore, provisioning profile и реальные платежные данные.

Если проблема появилась после обновления, составьте небольшой diff: какие файлы зависимостей и конфигурации изменились, какие версии были выбраны раньше и сейчас. Сравнение lock-файлов часто сразу показывает транзитивный пакет, который обновился вместе с платежным модулем.

Определите слой, на котором ломается проект

Одинаковая фраза «плагин оплаты конфликтует с другими зависимостями» может означать четыре разные ситуации. Исправление зависит от того, какой resolver сообщил ошибку. Не меняйте настройки iOS, если pub не может подобрать Dart-пакеты, и не добавляйте dependency_overrides, если Gradle спорит о нативной библиотеке Android.

  • Dart pub не может выбрать единую версию пакета из ограничений pubspec;
  • npm, Yarn или pnpm видит несовместимые peer dependencies в React Native;
  • Gradle выбирает конфликтующие версии Android SDK, Kotlin-модулей или AndroidX;
  • CocoaPods не может удовлетворить Podfile.lock, podspec либо deployment target;
  • линкер сообщает duplicate symbols после успешного разрешения пакетов;
  • компилятор находит одинаковые классы, ресурсы или несовместимый API;
  • сборка проходит, но приложение падает при инициализации нативного платежного SDK.

Первое сообщение resolver обычно полезнее сотни последующих ошибок. Например, «version solving failed» относится к pub, «Could not resolve all files for configuration» — к Gradle, «CocoaPods could not find compatible versions» — к pods, а duplicate class или duplicate symbols означает, что версии уже выбраны, но одинаковый код попал в итоговую сборку несколько раз.

Воспроизведите ошибку в чистой копии проекта

Проверьте сборку из свежего checkout на той же версии SDK, которая используется в CI или у коллеги. Локальная машина может скрывать проблему старыми pods, глобальным Node.js, локальным path-пакетом или измененным файлом, не попавшим в Git. В чистой копии сначала используйте сохраненные lock-файлы и обычную команду установки, не обновляющую весь граф.

# Flutter / Dart: диагностика без массового обновления flutter doctor -v dart pub deps dart pub outdated flutter pub get # React Native: выберите менеджер проекта npm ls # или: yarn why <package> # или: pnpm why <package>

Команда dart pub outdated показывает Current, Upgradable, Resolvable и Latest. Для исправления важнее Resolvable, а не максимальная Latest: последняя версия может быть несовместима с остальными ограничениями или текущим SDK. В приложении lock-файл следует хранить в системе контроля версий, чтобы разработчики и сборочная среда получали одинаковые версии.

Разберите граф верхнего уровня

Найдите пакет, для которого два прямых или транзитивных потребителя требуют несовместимые диапазоны. Платежный плагин может зависеть от http, webview, protobuf, firebase_core, browser API, cryptography либо платформенного интерфейса. Второй плагин просит другую major-версию той же зависимости. Нужно определить обе цепочки, а не просто закрепить пакет на случайной версии.

Пример логики разбора: payment_plugin -> shared_package >=3.0.0 <4.0.0 analytics_plugin -> shared_package >=2.0.0 <3.0.0 Пересечения нет. Нужна совместимая версия одного из плагинов, его обновление/замена или проверенный патч, а не вечный override.
  1. Определите прямые зависимости, которые приводят к конфликтующему пакету.
  2. Откройте changelog и требования каждой доступной версии платежного плагина.
  3. Сверьте минимальную версию Flutter, Dart, React Native и платформы.
  4. Найдите последнюю комбинацию с пересекающимися диапазонами.
  5. Обновляйте один прямой пакет за раз и проверяйте diff lock-файла.
  6. После разрешения выполните статический анализ, тесты и платформенные сборки.

Не превращайте dependency_overrides в постоянное решение

Dart позволяет временно переопределить зависимость через dependency_overrides. Это полезно для локальной проверки исправленного fork или подтверждения гипотезы, но версия вне заявленного диапазона может нарушить API и поведение пакета. Официальная документация прямо предупреждает о таком риске. Если override доказал совместимость, нужен поддерживаемый релиз плагина, ограниченный fork с тестами либо согласованное изменение прямых зависимостей.

  • добавляйте override только с комментарием, причиной и сроком удаления;
  • не переопределяйте несколько пакетов одновременно;
  • проверяйте вызовы API, которые изменились между major-версиями;
  • не публикуйте библиотеку, полагаясь на override из ее собственного pubspec;
  • не понижайте библиотеку безопасности только ради успешной компиляции;
  • закрепляйте проверенный результат lock-файлом и тестами.

Проверьте Android-граф через Gradle

Даже если pub или npm успешно установил пакеты, каждый plugin может подключать нативные Maven-зависимости. Платежный SDK и, например, Firebase, WebView, Google Play services или библиотека шифрования могут потребовать разные версии AndroidX, Kotlin stdlib, coroutines или protobuf. Gradle обычно выбирает одну версию, но выбранная версия может отличаться от запрошенной и затем вызвать ошибку компиляции или падение.

# Из каталога android ./gradlew app:dependencies --configuration debugRuntimeClasspath ./gradlew app:dependencyInsight \ --dependency <group-or-module> \ --configuration debugRuntimeClasspath

Отчет dependencyInsight отвечает на два главных вопроса: кто подтянул модуль и почему выбрана именно эта версия. Проверяйте конфигурацию того варианта, который не собирается: debugRuntimeClasspath не всегда совпадает с releaseRuntimeClasspath или отдельным flavor. Слепое force для всей конфигурации может собрать APK, но подсунуть платежному SDK неподдерживаемый бинарный контракт.

Частые Android-причины

  • плагин требует более высокий compileSdk или minSdk;
  • Android Gradle Plugin не совместим с версией Gradle либо Java;
  • Kotlin plugin и транзитивная kotlin-stdlib расходятся по major-версии;
  • два SDK включают одинаковые классы в разных артефактах;
  • старый support library смешан с AndroidX;
  • в release включается minification и удаляет классы SDK;
  • flavor подключает дополнительный платежный модуль только в одной конфигурации;
  • репозиторий провайдера или артефакт недоступен для CI.

Если ошибка связана с duplicate class, найдите обе цепочки через dependencies и dependencyInsight. Исключение transitive-модуля допустимо только тогда, когда оставшаяся версия действительно совместима с обоими потребителями. После изменения обязательно соберите debug и release, потому что R8, manifest merge и signing проявляются на разных этапах.

Проверьте iOS-граф через CocoaPods

На iOS платежный plugin может зависеть от pod нативного SDK, а другой модуль — от общей библиотеки сети, аналитики или криптографии. Podfile.lock хранит точные версии. Команда pod install уважает уже закрепленные pods и разрешает новые, тогда как pod update предназначена для намеренного обновления указанного pod или всего набора. Поэтому массовый pod update без анализа способен добавить несовместимые изменения.

cd ios pod outdated pod install # Обновляйте только доказанно нужный pod pod update <PodName> # Сравните после этого git diff -- Podfile Podfile.lock

Сверьте deployment target приложения и podspec плагина. Новый платежный SDK может прекратить поддержку старой iOS. Простое повышение target влияет на аудиторию и должно быть отдельным продуктовым решением. Также проверьте статическую или динамическую линковку, use_frameworks, modular headers, Swift version и архитектуру симулятора. Не удаляйте Podfile.lock до того, как сохранена и понята рабочая комбинация.

Частые iOS-причины

  • podspec плагина требует более новую iOS или Swift;
  • Podfile.lock удерживает старый pod, несовместимый с новым plugin;
  • два pods требуют непересекающиеся версии одного SDK;
  • один и тот же framework включен вручную и через CocoaPods;
  • статическая и динамическая версии дают duplicate symbols;
  • сборка симулятора и физического устройства использует разные архитектуры;
  • проект открывается как xcodeproj вместо созданного xcworkspace;
  • CI использует другую версию CocoaPods или Xcode.

Сравните требования самого платежного провайдера

Версия обертки и версия нативного SDK — не одно и то же. Flutter- или React Native-плагин может объявлять собственную версию 4.2.0, но подключать Android SDK 7.x и iOS SDK 6.x. Сверяйте changelog обертки, podspec, Gradle build-файл и официальные требования провайдера. Особое внимание требуется к переходам между major-версиями, изменениям 3-D Secure, callback URL, обработке deep link и модели токенизации.

  • какие версии Android и iOS SDK включены в plugin;
  • какие минимальные версии ОС и инструментов требуются;
  • изменились ли методы инициализации или callback;
  • нужно ли добавить URL scheme, intent filter или associated domain;
  • изменились ли правила ProGuard/R8 и сохранения классов;
  • какие тестовые карты и сценарии рекомендует провайдер;
  • есть ли исправления безопасности в более новой версии;
  • поддерживается ли текущая версия plugin самим разработчиком.

Выберите минимальную совместимую стратегию

После построения графа обычно остается несколько вариантов. Предпочтителен официальный релиз платежного плагина, совместимый с текущим стеком. Если его нет, оцениваются обновление конфликтующего плагина, замена устаревшего модуля, ограниченный fork или обновление платформы. Решение должно иметь понятный срок поддержки и путь к следующему обновлению.

  1. Попробуйте совместимые patch/minor-версии в пределах заявленных ограничений.
  2. Обновите один прямой конфликтующий plugin и адаптируйте его API.
  3. Если пакет заброшен, замените его поддерживаемым аналогом.
  4. Используйте временный fork только с конкретным патчем и собственными тестами.
  5. Повышайте Flutter, React Native, Android или iOS target отдельным контролируемым изменением.
  6. Принудительное разрешение версии оставляйте последним вариантом и документируйте риск.

Не объединяйте миграцию фреймворка, смену платежного провайдера и обновление всех зависимостей в один commit. Маленький diff проще проверить и откатить. Если требуется крупная миграция, сначала восстановите воспроизводимую сборку на старом стеке, затем обновляйте слои поэтапно.

Проверьте не только компиляцию, но и оплату

После успешной сборки выполните тесты в sandbox платежного провайдера. Клиентское приложение не должно самостоятельно считать оплату окончательно успешной: итоговый статус подтверждается доверенным backend и webhook провайдера. Обновление plugin способно изменить форму результата, время callback или поведение при возврате из банковского приложения.

  • успешная оплата обычной тестовой картой;
  • 3-D Secure с успешным подтверждением;
  • отказ банка и понятное сообщение пользователю;
  • отмена на экране платежа и возврат в приложение;
  • тайм-аут или потеря сети после отправки запроса;
  • повторное открытие приложения во время незавершенной операции;
  • двойное нажатие кнопки без создания двух платежей;
  • deep link или universal link после внешней авторизации;
  • подтверждение статуса backend через API или webhook;
  • повторная доставка webhook без двойного изменения заказа.

Логи должны содержать технический идентификатор операции и этап, но не полный номер карты, CVV, секретный ключ или платежный токен. Проверяйте, что отладочное логирование выключено в release и что тестовые credentials не попали в production-конфигурацию.

Соберите матрицу платформ и вариантов

Конфликт может проявляться только на одной платформе или конфигурации. Минимальная матрица включает Android debug и release, iOS simulator и physical device, а при наличии flavors — каждый платежный flavor. Если приложение поддерживает несколько архитектур или старую ОС, проверяется минимальная заявленная версия.

Проверка сборки: - Android debug APK / app bundle - Android release с R8 и signing - iOS simulator - iOS archive для устройства - CI на закрепленных версиях инструментов Проверка поведения: - запуск SDK - создание платежа - возврат из 3-D Secure - серверное подтверждение - повтор и отмена

Как безопасно применить исправление

  1. Создайте отдельную ветку от последней воспроизводимой версии.
  2. Измените только одну прямую зависимость или одно платформенное ограничение.
  3. Запустите resolver и внимательно проверьте diff lock-файлов.
  4. Сохраните отчеты pub, npm/Yarn, Gradle или CocoaPods, подтверждающие выбор версии.
  5. Соберите все нужные платформы и release-варианты.
  6. Пройдите sandbox-сценарии оплаты и отрицательные проверки.
  7. Проверьте backend, webhooks, идемпотентность и статусы заказов.
  8. Зафиксируйте причину, выбранную комбинацию и план следующего обновления.
  9. Развертывайте постепенно с возможностью быстро вернуть предыдущий релиз.

Типичные ошибки

  • удалить все lock-файлы и принять случайно выбранные свежие версии;
  • запустить pod update без имени и обновить весь iOS-граф;
  • оставить dependency_overrides без срока удаления;
  • использовать Gradle force, не выяснив двух потребителей зависимости;
  • понизить платежный SDK до версии с известными уязвимостями;
  • исправить debug и не собрать release с minification;
  • тестировать только Android, хотя plugin меняет также iOS pod;
  • не закрепить версии Node.js, Flutter, Xcode, Java и CocoaPods в CI;
  • считать успешную компиляцию доказательством правильной оплаты;
  • подтверждать платеж только по callback мобильного клиента;
  • записывать секреты и платежные токены в диагностический лог;
  • смешивать обновление фреймворка и исправление одного plugin в одном большом diff.

Как проверить результат

Исправление завершено, если чистая копия проекта с сохраненными lock-файлами воспроизводимо собирается локально и в CI, а sandbox-платеж проходит полный жизненный цикл. В отчете resolver не должно оставаться скрытого принудительного выбора, который команда не понимает. Повторная установка зависимостей не должна менять lock-файл без намеренного обновления.

  • граф зависимостей разрешается без временных неописанных override;
  • lock-файлы добавлены в commit и совпадают с CI;
  • Android dependencyInsight показывает ожидаемую нативную версию;
  • Podfile.lock содержит проверенную версию платежного SDK;
  • debug и release собираются для всех поддерживаемых платформ;
  • успех, отказ, отмена, тайм-аут и 3-D Secure обработаны корректно;
  • backend подтверждает итог операции и не создает дублей;
  • в release-логах нет credentials и платежных данных;
  • предыдущий релиз можно вернуть без несовместимой серверной миграции.

Как предотвратить повторение конфликта

Обновляйте зависимости регулярно небольшими партиями и отдельно проверяйте платежный контур. Храните lock-файлы приложений, закрепляйте версии инструментов в CI и не допускайте, чтобы production-сборка самостоятельно получала новые транзитивные версии. Для Dart полезно регулярно запускать pub outdated, а для Gradle и CocoaPods сохранять понятный способ получить дерево зависимостей.

  • назначьте владельца платежной интеграции и список поддерживаемых версий;
  • следите за changelog плагина и нативных SDK провайдера;
  • обновляйте один важный plugin за pull request;
  • автоматически собирайте Android и iOS после изменения lock-файлов;
  • держите sandbox smoke-тесты для основных платежных сценариев;
  • проверяйте минимальные версии ОС до обновления SDK;
  • удаляйте временные forks и overrides по зарегистрированной задаче;
  • сохраняйте инструкции отката и совместимость backend API.

Когда нужна помощь с конфликтом платежного плагина

Если платежный плагин конфликтует с другими зависимостями, я могу разобрать полный граф Flutter или React Native, отдельно проверить Gradle и CocoaPods, подобрать поддерживаемую комбинацию версий и восстановить воспроизводимую сборку. После исправления проверяю release-варианты, sandbox-оплату, 3-D Secure, возврат в приложение и серверное подтверждение статуса. Для первичной оценки достаточно прислать обезличенный текст ошибки, файлы зависимостей и версии инструментов без секретных ключей и реальных платежных данных.