Обновлено: 8 сентября 2026
Замена App Center для .NET MAUI в 2026 году: связка из трёх сервисов. Firebase App Distribution для кросс-платформенной раздачи бета-сборок, TestFlight для официального бета-тестирования iOS и Google Play Internal Testing для Android. Microsoft окончательно закрыл App Center 31 марта 2025 года, и большинство команд, которые я вижу в консалтинге, до сих пор либо тянут артефакты в общий Slack-канал, либо пытаются собрать «монстра Франкенштейна» из старых CLI-скриптов. Ниже я разберу рабочую связку на 2026 год с полными пайплайнами и подписью.
Что случилось с App Center и почему нужна замена
Microsoft объявил о закрытии Visual Studio App Center ещё в апреле 2024 года, а 31 марта 2025 года окончательно выключил все сервисы: Build, Distribute, Test, Crashes, Analytics и Push Notifications. Официальное объявление можно прочитать в Microsoft Learn: App Center retirement notice. С этого момента любые CLI-команды appcenter distribute release возвращают 404, ключи API отозваны, а публичные ссылки на дистрибутивы больше не работают.
Большинство команд эту миграцию тянут до последнего, и вот почему это плохо. Без работающего канала раздачи бета-сборок QA получают билды через AirDrop или Telegram, что убивает воспроизводимость и историю версий. Я в трёх проектах разгребал последствия, и в двух случаях команда потеряла двухнедельный трек регрессий, потому что не могла сопоставить, кто какую сборку тестировал. Держите открытыми в фоне официальный гайд Firebase App Distribution и документацию TestFlight: это базовые ссылки, пока настраиваешь замену.
Отдельно про push-уведомления и Notification Hub. App Center Push был отключён ещё в 2020 году, поэтому если ваш MAUI-проект до сих пор его дёргает, это уже мёртвый код, удаляйте. Актуальная замена сейчас: Firebase Cloud Messaging напрямую или Azure Notification Hubs с прямыми регистрациями.
Сравнение альтернатив App Center для .NET MAUI
Прежде чем ставить конкретный сервис, полезно увидеть картину целиком. Ни одна платформа не покрывает всё, что делал App Center, поэтому в 2026 году правильная стратегия такая: комбинировать сервисы, а не искать «серебряную пулю». Ниже сравнение, которое я использую при первом разговоре с командой, оценивающей миграцию.
| Возможность | Firebase App Distribution | TestFlight | Google Play Internal Testing | Codemagic Distribute |
|---|---|---|---|---|
| Платформы | iOS + Android | iOS только | Android только | iOS + Android |
| Формат артефакта | APK, AAB, IPA | IPA (подписан App Store) | APK, AAB | APK, AAB, IPA |
| Макс. тестеров | Без лимита | 10 000 внешних | 100 на трек | По плану |
| Обзор Apple/Google | Не требуется | Требуется для внешних | Не требуется | Не требуется |
| Стоимость | Бесплатно | Бесплатно (в рамках Apple Developer $99/год) | Бесплатно (в рамках Google Play $25 разово) | От $28/мес |
| CLI / автоматизация | firebase CLI, fastlane pilot альтернатива | fastlane pilot, notarytool | fastlane supply, Google Play API | Codemagic YAML |
| Скорость публикации | Секунды | 10–40 минут processing | Минуты | Секунды |
| Обратная связь тестеров | Через email/ссылку | Встроенный feedback + скриншоты | Через Play Store | Через email |
Практический вывод такой. Firebase App Distribution — рабочая лошадка для внутренней раздачи (быстро, бесплатно, кросс-платформенно), TestFlight обязателен для сколько-нибудь серьёзного iOS-бета-цикла (там реальные пользователи со скриншот-фидбеком), а Google Play Internal Testing удобен как «предпродакшн» для Android, потому что там уже подписанные Play Store артефакты, идентичные тому, что уйдёт в релиз.
Firebase App Distribution для .NET MAUI: пошаговая настройка
Начну с Firebase App Distribution, потому что это самый прямой путь от App Center. У него похожие концепции (группы тестеров, релизы, notes), и мигрируется он за один день. Большинство команд пропускают шаг с сервисным аккаунтом, а потом две недели дебажат, почему в CI при загрузке падает 401. Проверьте по чеклисту ниже.
Шаг 1. Создание Firebase проекта и приложений
- Заведите проект на
console.firebase.google.com(либо используйте существующий, если Analytics или FCM уже там). - Добавьте два приложения: iOS (Bundle ID вашего
Info.plist) и Android (Package name изAndroidManifest.xml). - Скачайте
google-services.jsonиGoogleService-Info.plist. Они нужны только для Firebase SDK (Analytics/Crashlytics). Для App Distribution как такового они не требуются, но пусть лежат в проекте. - В разделе App Distribution включите сервис и создайте группы тестеров, например
qa-internalиstakeholders.
Шаг 2. Сервисный аккаунт для CI
Это тот самый шаг, который большинство команд пропускают, и потом у них падает загрузка из GitHub Actions. Нужен именно service account, а не персональный токен:
# В Google Cloud Console → IAM → Service Accounts
# 1. Создайте service account: firebase-app-distribution-ci
# 2. Назначьте роль: Firebase App Distribution Admin
# 3. Скачайте JSON-ключ, сохраните как GOOGLE_APPLICATION_CREDENTIALS.json
# 4. В GitHub Actions добавьте секрет FIREBASE_SERVICE_ACCOUNT со всем содержимым JSON
Шаг 3. Загрузка Android AAB из .NET MAUI
Собираем подписанный AAB и заливаем через Firebase CLI:
# Publish подписанного AAB для Android
dotnet publish -f net9.0-android -c Release \
-p:AndroidPackageFormat=aab \
-p:AndroidKeyStore=true \
-p:AndroidSigningKeyStore=$KEYSTORE_PATH \
-p:AndroidSigningStorePass=$KEYSTORE_PASS \
-p:AndroidSigningKeyAlias=$KEY_ALIAS \
-p:AndroidSigningKeyPass=$KEY_PASS \
-o ./artifacts/android
# Загрузка через firebase CLI (v13.20+)
firebase appdistribution:distribute \
./artifacts/android/*-Signed.aab \
--app "1:123456789:android:abcdef" \
--groups "qa-internal,stakeholders" \
--release-notes-file ./release-notes.md
Шаг 4. Загрузка iOS IPA
Для iOS процесс похож, но требует Ad Hoc или Development provisioning profile. Firebase App Distribution не примет App Store подпись (это ограничение самой Apple), ищите profile с типом PROFILE_TYPE_IOS_APP_ADHOC:
dotnet publish -f net9.0-ios -c Release \
-p:ArchiveOnBuild=true \
-p:CodesignKey="Apple Distribution: MyCompany LLC" \
-p:CodesignProvision="MyApp AdHoc" \
-p:RuntimeIdentifier=ios-arm64 \
-o ./artifacts/ios
firebase appdistribution:distribute \
./artifacts/ios/*.ipa \
--app "1:123456789:ios:abcdef" \
--groups "qa-internal" \
--release-notes "Sprint 47 build, see JIRA MAUI-1234"
TestFlight для .NET MAUI iOS бета-тестирования
TestFlight в 2026 году это единственный способ дать реальным пользователям (не разработчикам, у которых UDID зарегистрирован) потестировать iOS-приложение до релиза. Это официальный канал Apple, поэтому он поддерживает внешних тестеров (до 10 000 человек), обязательный App Review для внешних групп и встроенный сбор скриншот-фидбека. Если раньше вы полностью полагались на Ad Hoc через App Center, время перестраиваться, потому что TestFlight требует App Store подпись и загрузку через Apple, а не через сторонние сервисы.
Настройка App Store Connect и API ключа
Первое, что стоит сделать даже до начала любой автоматизации, это создать API-ключ в App Store Connect. С 2023 года altool отключён, для загрузки используется xcrun notarytool и fastlane pilot. Полезно свериться с официальной документацией App Store Connect API, чтобы понимать, какие роли и scope доступны:
# App Store Connect → Users and Access → Keys
# Создайте ключ с ролью App Manager, скачайте .p8 файл (только один раз!)
# Запомните Key ID и Issuer ID
# Fastlane setup для CI
bundle init
echo 'gem "fastlane"' >> Gemfile
bundle install
# Fastfile для загрузки в TestFlight
lane :beta do
api_key = app_store_connect_api_key(
key_id: ENV["APP_STORE_KEY_ID"],
issuer_id: ENV["APP_STORE_ISSUER_ID"],
key_filepath: ENV["APP_STORE_KEY_PATH"],
duration: 1200
)
pilot(
api_key: api_key,
ipa: "./artifacts/ios/MyApp.ipa",
skip_waiting_for_build_processing: true,
changelog: File.read("./release-notes.md"),
distribute_external: false,
groups: ["internal-qa"]
)
end
Гочи, которые убьют вам полдня
- Processing зависает на 40+ минут: обычно причина в отсутствии всех required device family icons или в невалидном
ITSAppUsesNonExemptEncryptionвInfo.plist. Добавьте<key>ITSAppUsesNonExemptEncryption</key><false/>, и экспортный compliance закрывается автоматически. - Билд не появляется у внешних тестеров: проверьте, что группа помечена как External и прошла Beta App Review (первая версия занимает 24–48 часов, минорные обновления часто идут автоматом).
- Bundle version conflict: App Store Connect отвергнет билд с уже загруженной комбинацией версии и bundle-версии. Инкрементируйте
CFBundleVersionна каждый CI-запуск:-p:ApplicationVersion=$GITHUB_RUN_NUMBER.
Google Play Internal Testing для Android
Внутреннее тестирование в Google Play Console это не то же самое, что «internal app sharing» (последний нужен для быстрого шаринга одного APK на девайс). Internal Testing это полноценный трек внутри Play Console, до 100 email-адресов, публикация за минуты, автоматические обновления через Play Store на устройствах тестеров. Именно этот канал я использую как замену App Center для Android, он проверяет, что подпись, targetSdk и Play Console-политики отработают именно так, как в проде. Спецификации трека расписаны в официальном хелпе Google Play Console по testing tracks.
Первичная настройка Play Console
- Создайте приложение в Play Console (если ещё нет). Заполните обязательные секции: контент-рейтинг, целевую аудиторию, политику приватности.
- Перейдите в Testing → Internal testing → Create new release.
- Загрузите первую сборку вручную, чтобы Play Console принял upload key. Дальше можно автоматизировать через API.
- В Setup → API access создайте service account и назначьте роль Release Manager.
Автоматизация через fastlane supply
lane :internal_android do
upload_to_play_store(
package_name: "com.mycompany.myapp",
aab: "./artifacts/android/com.mycompany.myapp-Signed.aab",
track: "internal",
release_status: "draft",
json_key: ENV["GOOGLE_PLAY_JSON_KEY_PATH"],
skip_upload_metadata: true,
skip_upload_images: true,
skip_upload_screenshots: true
)
end
Автоматизация раздачи через GitHub Actions
Так, теперь к пайплайну. Ниже рабочий GitHub Actions воркфлоу, который собирает MAUI iOS + Android, заливает Android в Firebase App Distribution и в Google Play internal, а iOS уходит в Firebase (для Ad Hoc QA) и в TestFlight. Пайплайн top-down, как я всегда пишу: сначала контекст (триггеры, env), потом job'ы, потом стадии. Если у вас ещё нет базовой сборки, посмотрите отдельный разбор CI/CD для .NET MAUI на GitHub Actions, где расписаны шаги с подписью и провижн-профилями; здесь я не буду повторяться.
name: MAUI Beta Distribution
on:
push:
branches: [main, "release/*"]
workflow_dispatch:
env:
DOTNET_VERSION: 9.0.x
BUILD_CONFIGURATION: Release
ARTIFACTS_PATH: ./artifacts
jobs:
android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Install MAUI workloads
run: dotnet workload install maui-android
- name: Decode keystore
run: echo "${{ secrets.ANDROID_KEYSTORE_B64 }}" | base64 -d > keystore.jks
- name: Publish signed AAB
run: |
dotnet publish -f net9.0-android -c $BUILD_CONFIGURATION \
-p:AndroidPackageFormat=aab \
-p:AndroidKeyStore=true \
-p:AndroidSigningKeyStore=./keystore.jks \
-p:AndroidSigningStorePass="${{ secrets.KEYSTORE_PASS }}" \
-p:AndroidSigningKeyAlias="${{ secrets.KEY_ALIAS }}" \
-p:AndroidSigningKeyPass="${{ secrets.KEY_PASS }}" \
-p:ApplicationVersion=${{ github.run_number }} \
-o $ARTIFACTS_PATH/android
- name: Firebase App Distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{ secrets.FIREBASE_ANDROID_APP_ID }}
serviceCredentialsFileContent: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
groups: qa-internal
file: ${{ env.ARTIFACTS_PATH }}/android/com.mycompany.myapp-Signed.aab
- name: Google Play Internal
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_JSON_KEY }}
packageName: com.mycompany.myapp
releaseFiles: ${{ env.ARTIFACTS_PATH }}/android/com.mycompany.myapp-Signed.aab
track: internal
status: draft
ios:
runs-on: macos-14
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- run: dotnet workload install maui-ios
- name: Import signing certificate
uses: apple-actions/import-codesign-certs@v3
with:
p12-file-base64: ${{ secrets.IOS_DISTRIBUTION_P12 }}
p12-password: ${{ secrets.IOS_DISTRIBUTION_P12_PASS }}
- name: Download provisioning profile
uses: apple-actions/download-provisioning-profiles@v3
with:
bundle-id: com.mycompany.myapp
profile-type: IOS_APP_STORE
issuer-id: ${{ secrets.APP_STORE_ISSUER_ID }}
api-key-id: ${{ secrets.APP_STORE_KEY_ID }}
api-private-key: ${{ secrets.APP_STORE_PRIVATE_KEY }}
- name: Publish IPA
run: |
dotnet publish -f net9.0-ios -c $BUILD_CONFIGURATION \
-p:ArchiveOnBuild=true \
-p:CodesignKey="Apple Distribution: MyCompany LLC" \
-p:CodesignProvision="MyApp AppStore" \
-p:RuntimeIdentifier=ios-arm64 \
-p:ApplicationVersion=${{ github.run_number }} \
-o $ARTIFACTS_PATH/ios
- name: TestFlight upload
uses: apple-actions/upload-testflight-build@v3
with:
app-path: ${{ env.ARTIFACTS_PATH }}/ios/MyApp.ipa
issuer-id: ${{ secrets.APP_STORE_ISSUER_ID }}
api-key-id: ${{ secrets.APP_STORE_KEY_ID }}
api-private-key: ${{ secrets.APP_STORE_PRIVATE_KEY }}
Такой пайплайн я обычно ставлю на release/*-ветки и workflow_dispatch, чтобы не заваливать TestFlight на каждый push в main. TestFlight processing на второй сборке в час стабильно замедляется, не гоняйте туда каждый коммит.
Что заменит crash reporting и аналитику
App Center Crashes и Analytics были важной частью пакета, и именно эта часть чаще всего забывается при миграции. К моменту, когда вам понадобится расследовать первый крэш в проде на TestFlight, поздно поднимать SDK. Ставьте сразу.
Sentry для .NET MAUI
Sentry — мой первый выбор для крэш-репортинга. SDK нативно поддерживает MAUI начиная с версии 4.0, есть автоматический symbolication для iOS/Android, и работает даже с NativeAOT-сборками (это важно, если вы читали разбор NativeAOT в .NET MAUI и уже включили публикацию). Настройка занимает минут пять:
// В MauiProgram.cs
builder.UseSentry(options =>
{
options.Dsn = "https://xxxx@o0.ingest.sentry.io/000";
options.TracesSampleRate = 0.2;
options.AttachScreenshot = true;
options.CacheDirectoryPath = FileSystem.CacheDirectory;
});
Firebase Crashlytics
Если вы уже поставили Firebase ради App Distribution, Crashlytics логично включить туда же. Для .NET MAUI используйте Plugin.Firebase.Crashlytics. SDK нужен в оба проекта (iOS + Android), symbol upload идёт через upload-symbols для iOS и firebase-crashlytics-buildtools для Android.
Аналитика
Firebase Analytics это самый безболезненный upgrade path с App Center Analytics: события и user properties мигрируют почти один в один. Альтернатива это Azure Application Insights (если у вас уже есть Azure-инфра), но SDK для MAUI придётся тянуть через community-обёртку, официального нет.
Миграция существующего пайплайна с App Center
Собственно чеклист, который я использую с командами. Идите строго сверху вниз, пункты нельзя переставлять местами, иначе получите период, когда старая раздача уже не работает, а новая ещё не настроена.
- Аудит App Center-упоминаний в кодовой базе. Ищите
Microsoft.AppCenter,appcenter-cli, вебхуки Slack/Teams с URLappcenter.ms. Всё, что нашли, помечайте на удаление. - Замените SDK пакеты. Удалите
Microsoft.AppCenter.CrashesиMicrosoft.AppCenter.Analyticsиз.csproj. ДобавьтеSentry.Maui(4.10+) или Firebase-пакеты. - Перенесите тестерские группы. Экспортируйте список email'ов из App Center (если у вас есть бэкап), заведите тех же людей в Firebase App Distribution как группу и в App Store Connect / Play Console как тестеров.
- Настройте service accounts. Firebase App Distribution Admin, Google Play Release Manager, App Store Connect API key. Секреты храните в GitHub Actions / Azure Pipelines.
- Соберите тестовый билд. Прогоните полный пайплайн на одном пре-релизе, убедитесь, что тестеры получили и iOS, и Android. Только после этого убирайте старый пайплайн.
- Обновите документацию для QA. Инструкции «как установить бета-сборку» изменились. Для Firebase App Distribution нужно принять приглашение по email и установить Firebase App Tester (iOS/Android). Для TestFlight ставим приложение TestFlight. Не оставляйте это без объяснения, иначе потеряете два дня на «у меня не приходит ссылка».
- Настройте мониторинг: Sentry alerts, Firebase Crashlytics velocity alerts. Первый крэш в TestFlight-беты вы должны увидеть до того, как тестер напишет.
Часто задаваемые вопросы
Что случилось с App Center?
Microsoft закрыл Visual Studio App Center 31 марта 2025 года. Все сервисы (Build, Distribute, Crashes, Analytics, Test) выключены, CLI возвращает 404, API-ключи отозваны. Официальное объявление опубликовано в апреле 2024 года на Microsoft Learn, ретирейтмент дал командам 12 месяцев на миграцию.
Есть ли бесплатная альтернатива App Center для .NET MAUI?
Да. Firebase App Distribution полностью бесплатен для внутренней раздачи, TestFlight входит в подписку Apple Developer ($99/год), Google Play Internal Testing бесплатен после разового платежа $25 за аккаунт Play Console. Sentry имеет бесплатный tier до 5000 крэшей в месяц.
Можно ли автоматизировать загрузку в TestFlight из GitHub Actions?
Да, используя App Store Connect API key и action apple-actions/upload-testflight-build@v3 либо fastlane pilot. Ключ создаётся в App Store Connect → Users and Access → Keys с ролью App Manager. Требуется macOS runner (macos-14) для сборки iOS.
Что использовать вместо App Center Push?
App Center Push был отключён ещё в 2020 году. Актуальные замены на 2026 год: Firebase Cloud Messaging напрямую (кросс-платформенно, бесплатно), Azure Notification Hubs (если у вас Azure-инфра), OneSignal (если нужны сегментация и analytics без бэкенда).
Работает ли Firebase App Distribution с .NET MAUI Blazor Hybrid?
Да. Blazor Hybrid это обычный MAUI-проект с BlazorWebView внутри, артефакт сборки такой же (AAB для Android, IPA для iOS), поэтому Firebase App Distribution принимает его без изменений. Особая настройка не требуется.

