.NET MAUI GitHub Actions CI/CD 완벽 가이드 2026: 자동 빌드, 코드 서명, App Store와 Play Store 배포까지
App Center 종료 이후, .NET MAUI 10 앱을 GitHub Actions로 자동 빌드하고 iOS·Android 코드 서명, TestFlight, Google Play 내부 트랙까지 배포하는 실전 파이프라인. 러너 이미지, 시크릿 관리, OIDC까지 2026년 기준으로 정리했습니다.
.NET MAUI 앱의 CI/CD를 GitHub Actions로 구축하려면, macOS 러너에서 dotnet workload install maui로 워크로드를 설치하고, base64로 인코딩된 .p12와 .jks 시크릿으로 iOS와 Android를 각각 서명한 뒤, xcrun altool의 후속 도구인 Transporter(또는 fastlane pilot)와 r0adkll/upload-google-play 액션으로 스토어에 업로드하는 파이프라인이 필요합니다. 솔직히 말하면, App Center가 종료된 2026년 현재 대부분의 팀이 놓치는 서명·시크릿·러너 이미지 이슈까지 이 글에서 모두 다룰 겁니다.
Visual Studio App Center는 2025년 3월 31일에 완전히 종료되었으며, Microsoft 공식 마이그레이션 경로는 GitHub Actions + Firebase App Distribution 또는 Azure Pipelines 조합입니다.
.NET MAUI 10은 2025년 11월 GA된 .NET 10 위에서 동작하며, LTS로 3년간 지원됩니다. iOS 빌드에는 반드시 macos-15 또는 macos-26 러너가 필요합니다.
iOS 코드 서명은 apple-actions/import-codesign-certs@v3와 App Store Connect API 키(.p8)를 조합해 처리하고, Android는 base64 인코딩된 keystore를 GitHub Secrets에 저장해 -p:AndroidSigningKeyStore MSBuild 프로퍼티로 전달합니다.
AAB 배포에는 -p:AndroidSigningKeyStore에 env: 대신 file: 접두사를 써야 하며, 이를 놓치면 빌드는 통과하지만 서명되지 않은 AAB가 만들어집니다.
버전 자동 증가는 -p:ApplicationVersion=${{ github.run_number }} 하나로 충분합니다. 리포지토리에 커밋을 되돌려 넣을 필요가 없습니다.
2026년 기준 xcrun altool은 노터라이제이션(notarization) 경로에서 완전히 거부되므로, iOS 업로드는 Transporter나 fastlane upload_to_testflight로 대체해야 합니다.
.NET MAUI에서 CI/CD가 왜 중요한가요?
모바일 팀에서 로컬 머신으로 iOS와 Android를 각각 빌드해 스토어에 올리는 방식은 5년 전에나 통했습니다. 2026년의 현실은 이렇습니다. 개발자 한 명의 맥에서만 빌드가 성공하고, Xcode가 업데이트되면 갑자기 서명이 깨지고, 프로비저닝 프로필은 언제 만료됐는지 아무도 모릅니다. 대부분의 팀은 이 과정을 자동화하지 않고 넘어가는데, 그러다 릴리스 전날 밤에 "왜 이 맥에서만 되지?"라는 슬랙 메시지가 올라옵니다.
CI/CD가 해결하는 문제는 세 가지입니다. 첫째, 재현 가능성 (러너 이미지는 매일 초기화되므로 "환경이 오염됐다"는 변명이 사라집니다). 둘째, 서명 자산의 중앙화. .p12, keystore, 프로비저닝 프로필이 GitHub Secrets에 있으면 개인 맥북이 분실돼도 릴리스가 가능합니다. 셋째, 스토어 업로드의 자동화인데, TestFlight와 Play 내부 트랙 배포가 한 커밋으로 끝납니다.
제 경험상 .NET MAUI 테스트 자동화가 어느 정도 자리 잡은 팀이라도 CI/CD가 없으면 릴리스 리듬이 2주에 한 번을 넘지 못합니다. 반대로 파이프라인이 안정적이면 하루에 3~5개의 TestFlight 빌드를 QA에 넘기는 것이 정상이 됩니다.
App Center 종료 이후, 어떤 대안을 선택해야 하나요?
Visual Studio App Center는 2025년 3월 31일에 공식 종료되었고, 분석과 진단(Analytics & Diagnostics)만 Azure Monitor 파트너십을 통해 2026년 6월 30일까지 연장되었습니다. 현재 시점에서는 완전히 새 파이프라인으로 옮겨야 합니다.
이 가이드에서는 소스가 GitHub에 있고, iOS/Android 모두 스토어 배포까지 자동화한다는 전제로 GitHub Actions를 선택합니다. Azure DevOps 사용자라면 YAML 문법이 다르지만 파이프라인의 논리적 단계는 동일하게 적용됩니다.
GitHub Actions 러너 준비: .NET 10과 MAUI 워크로드
먼저 러너 이미지 상황부터 정리합니다. 2026년 8월 기준 GitHub-hosted 러너 라인업은 다음과 같습니다.
macos-latest: 2025년 8월부터 macOS 15로 마이그레이션됨. 2026년 6월에 macos-26(Tahoe, M4)로 이동 예정.
macos-14(Sonoma): 2026년 7월 6일 deprecated, 11월 2일 완전 지원 종료.
macos-15(Sequoia, M2): Xcode 16.4 CLT, iOS 빌드의 현재 안정 조합.
macos-26(Tahoe, M4): 기본 Xcode 26.4.1, Xcode 26.0.1부터 26.5까지 다중 설치.
windows-latest: Windows Server 2022, Android 빌드용으로 macOS보다 빠르고 저렴합니다.
ubuntu-latest: 24.04, Android 빌드 가능 (iOS는 불가).
여기서 반드시 고정해야 할 세 가지가 있습니다. global.json으로 .NET SDK 버전을 못 박고, maxim-lobanov/setup-xcode@v1로 Xcode 버전을 고정하며, MAUI 워크로드 버전을 --version으로 명시하는 것입니다. 이걸 안 하면 러너 이미지가 갱신되는 날 갑자기 파이프라인이 깨집니다. 제가 지난 프로젝트에서 이 실수로 금요일 저녁을 통째로 태운 적이 있습니다.
iOS 빌드는 macOS 러너가 필수입니다. 2026년 현재 안정적인 조합은 macos-15 + Xcode 16.4입니다. macos-26과 Xcode 26.x 조합은 사용 가능하지만, MAUI 워크로드가 요구하는 Xcode 버전과 어긋나는 케이스가 아직 남아 있어 릴리스 파이프라인에서는 신중해야 합니다.
서명 자산은 다음 세 개를 시크릿으로 준비합니다.
IOS_DIST_CERT_P12_BASE64: Apple Distribution 인증서와 개인키를 담은 .p12의 base64 인코딩.
iOS 워크로드와 Xcode 버전이 어긋나면 This version of .NET for iOS requires Xcode ... 에러가 발생합니다. dotnet/macios 이슈 #24314와 dotnet/maui 디스커션 #34312에서 다뤄지는 가장 흔한 실패 케이스입니다. 두 버전을 모두 global.json과 setup-xcode에서 명시적으로 고정하는 것이 유일한 예방책입니다.
TestFlight에 IPA 업로드하기
Apple의 TN3147 기술 노트에서 확인할 수 있듯이, xcrun altool은 2023년 11월 1일 이후 노터라이제이션 경로에서 완전히 거부됩니다. 2026년에는 세 가지 실용적 옵션이 남습니다.
Transporter (iTMSTransporter): Apple 공식 CLI, 러너 이미지에 기본 포함됩니다.
ASC_KEY_P8는 .p8 파일의 내용을 그대로 시크릿에 넣어두면 됩니다. 여러 줄 문자열이 그대로 인식됩니다. fastlane을 도입하지 않는다면 xcrun iTMSTransporter를 직접 호출할 수 있지만, 로깅 품질이 떨어져 디버깅이 어렵습니다.
Google Play 내부 트랙에 AAB 배포하기
Play 배포는 GitHub Actions 생태계에서 r0adkll/upload-google-play 액션이 사실상 표준입니다. GCP 콘솔에서 서비스 계정 JSON을 발급하고, Play Console에서 "Release manager" 역할을 부여한 뒤, JSON 전체를 PLAY_SERVICE_ACCOUNT_JSON 시크릿에 저장합니다.
whatsNewDirectory는 whatsnew-en-US, whatsnew-ko-KR 같은 파일들이 담긴 디렉터리를 가리켜야 합니다. 파일 하나가 릴리스 노트 한 언어에 대응됩니다.
시크릿 관리와 OIDC 인증 베스트 프랙티스
모바일 CI/CD의 실질적 보안 리스크는 대부분 시크릿 관리에서 발생합니다. 아래 체크리스트를 릴리스 파이프라인 코드리뷰의 표준으로 삼는 걸 권장합니다.
.p12, .jks, .p8, .mobileprovision, google-service-account.json은 절대 리포지토리에 커밋하지 않는다.
바이너리 시크릿은 base64로 인코딩해 GitHub Secrets에 저장한다.
production 배포 잡은 Environment에 묶고 required reviewers를 지정한다.
permissions:는 잡 레벨에서 최소 권한으로 설정한다. OIDC가 필요한 잡에만 id-token: write를 부여한다.
GCP 인증은 가능하면 google-github-actions/auth의 workload identity federation으로 대체해 장기 JSON 키를 없앤다.
Apple/Play 시크릿의 회전 주기를 캘린더에 등록한다. iOS 배포 인증서는 매년 만료됩니다.
GitHub OIDC 공식 문서는 2026년 7월 15일부터 기본 subject 포맷이 owner+repo ID를 포함하도록 변경되었습니다. 이전에 Azure Key Vault나 GCP와 OIDC를 이미 연결한 팀이라면, trust condition의 subject 필드가 새 포맷과 일치하는지 확인해야 합니다. 안 그러면 어느 아침 갑자기 AADSTS700213 같은 에러를 만납니다.
자주 발생하는 5가지 문제와 해결법
1. "This version of .NET for iOS requires Xcode X" 에러
MAUI 워크로드 버전과 러너의 Xcode 버전이 어긋난 겁니다. global.json에 SDK를 못 박고, maxim-lobanov/setup-xcode로 Xcode 버전을 고정하세요. 그리고 dotnet workload install maui --version 10.0.100처럼 워크로드 버전도 명시합니다.
2. AAB는 만들어지지만 서명이 비어 있음
env: 접두사를 file:로 바꿔야 합니다. 이건 APK/AAB의 MSBuild 파이프라인 차이에서 오는 함정입니다. bin/Release/net10.0-android/publish/에서 파일명이 -Signed.aab로 끝나는 것만 스토어에 올려야 합니다.
Google 정책상 첫 릴리스는 반드시 Play Console에서 수동 업로드해야 합니다. 앱이 등록된 뒤부터 API 업로드가 활성화됩니다.
5. macOS 러너에서 디스크 공간 부족
Xcode 하나가 15GB 이상을 차지하므로 다른 Xcode 버전을 설치할 때 실패합니다. sudo rm -rf /Applications/Xcode_<old>.app로 미사용 Xcode를 먼저 정리하면 대부분 해결됩니다.
Fastlane과 GitHub Actions, 무엇을 선택해야 하나요?
2026년 기준으로 이 질문의 답은 플랫폼별로 갈립니다. Android는 r0adkll/upload-google-play가 90% 케이스를 커버하므로 Ruby 스택인 fastlane을 굳이 도입할 이유가 없습니다. 반면 iOS는 여전히 fastlane의 강점이 큽니다. 특히 match는 팀원이 여러 명일 때 인증서와 프로비저닝 프로필을 암호화된 Git 저장소에 동기화하는, 사실상 유일하게 성숙한 도구입니다.
제 팀의 일반적 규칙은 이렇습니다.
솔로 개발자 또는 iOS 앱 하나만 관리: 순수 GitHub Actions + 수동 .mobileprovision.
단, 2025년 5월 이후 fastlane의 "managed capabilities"가 deprecated 되면서 Apple 승인이 필요한 entitlement의 자동 갱신은 불가능해졌습니다. 이 부분은 어차피 사람이 App Store Connect에서 확인해야 하므로, 완전 무인 파이프라인은 현실적으로 존재하지 않는다고 보는 편이 안전합니다.
MAUI의 프로젝트 구조와 서명 프로퍼티는 fastlane gym을 우회하고 dotnet publish가 직접 IPA를 생성하므로, fastlane은 인증서 관리와 업로드 단계에만 관여하는 게 자연스럽습니다. .NET MAUI 10 성능 최적화나 푸시 알림 구현 파이프라인과 마찬가지로, CI/CD도 "필요한 도구만 각자의 자리에" 두는 접근이 결국 유지보수가 쉽습니다.
자주 묻는 질문
.NET MAUI 앱을 Ubuntu 러너에서 빌드할 수 있나요?
Android 타깃(net10.0-android)은 Ubuntu와 Windows 러너 모두에서 빌드 가능합니다. iOS/Mac Catalyst 타깃은 반드시 macOS 러너가 필요합니다. Ubuntu는 비용과 속도 면에서 유리하므로 Android 잡에는 ubuntu-latest를 권장합니다.
GitHub Actions에서 앱 버전을 자동으로 증가시키는 방법은 무엇인가요?
-p:ApplicationVersion=${{ github.run_number }}와 -p:ApplicationDisplayVersion=1.0.${{ github.run_number }}를 dotnet publish 명령에 넘기면 됩니다. 리포지토리에 커밋을 되돌려 넣을 필요가 없고, 워크플로우 실행 번호가 자연스럽게 빌드 번호가 됩니다.
fastlane match 없이 iOS 인증서를 팀원과 공유해도 되나요?
솔로 또는 두 명 이하 팀이라면 .p12와 .mobileprovision을 각자 로컬에 두고 CI에는 GitHub Secrets를 통해서만 전달하는 방식으로 충분합니다. 3명 이상, 여러 앱을 관리한다면 match가 확실히 노력을 줄여줍니다.
xcrun altool은 왜 더 이상 쓰면 안 되나요?
Apple은 2023년 11월 1일부로 altool의 노터라이제이션 경로를 완전히 차단했습니다. TestFlight 업로드 자체는 아직 동작하지만 공식 지원이 종료된 도구입니다. 2026년의 안전한 선택은 Transporter(xcrun iTMSTransporter) 또는 fastlane upload_to_testflight입니다.
App Center를 대체할 크래시 리포팅 도구로는 무엇을 추천하나요?
MAUI 통합 난이도와 무료 티어를 고려하면 Sentry가 가장 실용적입니다. Firebase Crashlytics는 Android/iOS 네이티브 SDK 래핑이 필요하고, Azure Monitor는 엔터프라이즈 환경에서 강점이 있지만 초기 설정 비용이 큽니다. 소규모 팀이라면 Sentry, 대규모/규제 환경이라면 Azure Monitor를 권장합니다.
.NET MAUI Android APK를 R8 축소기, IL Trimmer full 모드, App Bundle ABI 분할, WebP·폰트 서브셋으로 60~70% 다이어트하는 실전 가이드. .NET 10 기준 csproj 설정, proguard-rules.pro, CI 크기 회귀 방지 스크립트까지 프로덕션에서 검증한 예제로 정리했습니다.