Skip to content

Add template app distribution workflow#36571

Open
kubaflo wants to merge 2 commits into
dotnet:mainfrom
kubaflo:template-app-distribution
Open

Add template app distribution workflow#36571
kubaflo wants to merge 2 commits into
dotnet:mainfrom
kubaflo:template-app-distribution

Conversation

@kubaflo

@kubaflo kubaflo commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Summary

Supersedes #36136.

Adds a manually triggered Template App Distribution workflow that builds the MAUI templates into tester apps for Android, iOS, Mac Catalyst, and Windows, in both blank and sample-content variants. The dry-run path (publish=false) uploads directly-installable GitHub artifacts; publish=true optionally ships to Google Play test tracks and TestFlight via fastlane, gated on the protected template-app-distribution environment secrets.

Why this supersedes #36136

#36136 produced store-shaped artifacts that testers could not install or launch. Reported failures: Android had no APK, Windows showed a "install the .NET runtime" screen, iOS failed with 0xe800801f Attempted to install a Beta profile without the proper entitlement, and Mac Catalyst crashed on launch with EXC_CRASH (SIGKILL - Code Signature Invalid).

This version fixes each platform so the uploaded dry-run artifact runs on a tester device with no extra tooling:

Platform Problem in #36136 Fix
Android Only an .aab was produced (cannot be sideloaded) Build a signed, directly-installable APK (v2+v3)
Windows Framework-dependent (tester saw a runtime-missing screen) Publish self-contained (SelfContained=true + WindowsAppSDKSelfContained=true)
iOS Unsigned device .app / TestFlight-profile IPA installs nowhere Dry-run builds an arm64 iOS Simulator app that actually launches; the device path stays gated behind ad-hoc signing secrets
Mac Catalyst Store .pkg / Rosetta x64 build then SIGKILL Code Signature Invalid arm64-native .app, zipped with ditto, ad-hoc re-signed inside-out so it launches on macOS 15+ / 26

Validation

All four artifacts were validated end-to-end from CI output — installed and launched on a real target (arm64 macOS 26.5.2, an Android emulator, an iOS Simulator), not just built:

  • Android: APK signature verified, then adb install then am start; process stayed alive with no FATAL.
  • iOS: CI Simulator .app (arm64, ad-hoc), then simctl install / launch; UIKit app running, no crash.
  • macOS (Mac Catalyst): CI .app (arm64, ad-hoc) launches natively and the Hello-World window renders; tester quarantine then clear then launch also confirmed.
  • Windows: self-contained payload confirmed structurally (CoreCLR plus WindowsAppSDK natives bundled).

See .github/scripts/template-app-distribution/README.md for per-platform tester install steps.

Setup still needed before publish=true works

The template-app-distribution GitHub Environment and its signing / store secrets must be created in dotnet/maui. Dry-run artifact builds run without any secrets.

Note on scope

Unlike #36136 this PR does not touch src/Templates/src/templates/maui-mobile/MauiApp.1.csproj; that change was an incidental package-version edit from an older base and is now stale relative to main (which has since moved those versions forward via #36074 and #35608). The workflow does not require it.

/cc @PureWeen @jfversluis


🔍 This PR was prepared by GitHub Copilot CLI on behalf of @kubaflo, standing in for @jfversluis while he is away. All four platform artifacts were launched, not just built.

Supersedes dotnet#36136. Adds a manually triggered workflow that builds the MAUI
templates into tester apps for Android, iOS, Mac Catalyst, and Windows, in
both blank and sample-content variants. The dry-run path (publish=false)
uploads directly-installable GitHub artifacts; publish=true optionally ships
to Google Play test tracks and TestFlight via fastlane, gated on the
protected template-app-distribution environment secrets.

The original PR produced store-shaped artifacts that testers could not
install or launch. This version fixes each platform so the uploaded artifact
runs on a tester device with no extra tooling:

- Android: build a signed, directly-installable APK (v2+v3) for the dry-run
  path instead of an AAB, which cannot be sideloaded.
- Windows: publish self-contained (SelfContained=true plus
  WindowsAppSDKSelfContained=true) so testers do not need a matching .NET or
  WindowsAppSDK runtime installed.
- iOS: the dry-run now builds an arm64 iOS Simulator app
  (dotnet build -r iossimulator-arm64, with -p:UseMonoRuntime=false for the
  net11 CoreCLR build) that actually launches; the device path stays gated
  behind ad-hoc signing secrets.
- Mac Catalyst: pin the arm64-native RID, zip the .app with ditto instead of
  Compress-Archive (which strips the exec bit and framework symlinks), and
  re-sign the bundle ad-hoc inside-out so it launches on macOS 15+ and
  macOS 26 without a Code Signature Invalid SIGKILL.

All four artifacts were validated end-to-end from CI output (installed and
launched, not just built). See
.github/scripts/template-app-distribution/README.md for per-platform tester
install steps.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 92e506ca-933d-4c5b-ab06-62cf471e259c
Copilot AI review requested due to automatic review settings July 14, 2026 20:25
@kubaflo kubaflo had a problem deploying to copilot-pat-pool July 14, 2026 20:25 — with GitHub Actions Failure
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 36571

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 36571"

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
1 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new manually-triggered “Template App Distribution” GitHub Actions workflow plus supporting scripts to (1) pack the MAUI templates, (2) generate per-platform apps (blank + sample), (3) produce sideloadable artifacts for dry-runs, and (4) optionally publish to Google Play / TestFlight using fastlane behind a protected environment.

Changes:

  • Adds .github/workflows/template-app-distribution.yml with a prepare → dry-run-build / publish job split and a platform/variant matrix.
  • Adds PowerShell scripts under .github/scripts/template-app-distribution/ to resolve the source ref + SDK, pack templates, generate apps, and build platform-appropriate distributables.
  • Adds a dedicated fastlane bundle (Gemfile/Gemfile.lock + Fastfile) and a README documenting artifact types and tester install steps.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
.github/workflows/template-app-distribution.yml New workflow_dispatch pipeline to build and (optionally) publish template-based tester apps across platforms/variants.
.github/scripts/template-app-distribution/Resolve-SourceRef.ps1 Resolves/validates source_ref and enforces trust rules for publish=true.
.github/scripts/template-app-distribution/Resolve-DotNetSdk.ps1 Resolves SDK version (global.json) and derives the netX.Y TFM used by matrix generation.
.github/scripts/template-app-distribution/Prepare-Matrix.ps1 Builds the variant/platform matrix and default app identifiers/bundle IDs.
.github/scripts/template-app-distribution/Pack-Templates.ps1 Builds/packs Microsoft.Maui.Templates into a local nupkg for dotnet new install.
.github/scripts/template-app-distribution/New-TemplateApp.ps1 Generates an app from the packed templates and normalizes app identity/version settings.
.github/scripts/template-app-distribution/Install-AppleSigningAssets.ps1 Installs Apple certs/profiles into a temporary keychain and exports signing env vars.
.github/scripts/template-app-distribution/Build-TemplateApp.ps1 Builds platform-specific outputs (APK/AAB, iOS IPA + simulator .app zip, Mac Catalyst .pkg + .app zip, Windows self-contained zip).
.github/scripts/template-app-distribution/README.md Tester-facing documentation for what artifacts are produced and how to install/run them.
.github/scripts/template-app-distribution/fastlane/Gemfile Pins fastlane dependency for publish lanes.
.github/scripts/template-app-distribution/fastlane/Gemfile.lock Bundler lockfile for deterministic fastlane installs in CI.
.github/scripts/template-app-distribution/fastlane/Fastfile Implements the fastlane lanes used to upload to Google Play / TestFlight.

Comment on lines +45 to +48
function Write-Base64File([string]$Base64Value, [string]$Path) {
$bytes = [Convert]::FromBase64String($Base64Value)
[System.IO.File]::WriteAllBytes($Path, $bytes)
}
The iOS dry-run only produced a Simulator .app.zip, so testers reported
there was no .ipa to install on a real iPhone/iPad. Add a best-effort
unsigned ios-arm64 device build wrapped as a Payload/*.app .ipa, which
testers can install via AltStore/Sideloadly (re-signed with their own
Apple ID). The Simulator app is still uploaded as an additional artifact
for Mac-only smoke testing, and the device IPA build is wrapped in
try/catch so a failure never regresses the existing Simulator artifact.

A directly-installable device build still requires the secret-gated
ad-hoc IPA or TestFlight publish path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 92e506ca-933d-4c5b-ab06-62cf471e259c
Copilot AI review requested due to automatic review settings July 15, 2026 12:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 4 comments.

git config --global advice.defaultBranchName false

- name: Checkout workflow scripts
uses: actions/checkout@v7
Comment on lines +315 to +333
- name: Create generated app
id: app
shell: pwsh
run: |
& "${{ github.workspace }}/trusted/.github/scripts/template-app-distribution/New-TemplateApp.ps1" `
-TemplatePackagePath "${{ steps.pack.outputs.template_package_path }}" `
-BuildRoot "${{ runner.temp }}/template-app-build" `
-Variant "${{ matrix.variant }}-${{ matrix.platform }}" `
-ProjectName "${{ matrix.projectName }}" `
-Template "${{ matrix.template }}" `
-TemplateArgsJson '${{ matrix.templateArgsJson }}' `
-DotNetTfm "${{ needs.prepare.outputs.dotnet_tfm }}" `
-TargetFramework "${{ matrix.targetFramework }}" `
-ApplicationId "${{ matrix.applicationId }}" `
-DisplayName "${{ matrix.displayName }}" `
-DotNetSdk "${{ needs.prepare.outputs.dotnet_sdk }}" `
-AppDisplayVersion "$env:APP_DISPLAY_VERSION" `
-AppBuildNumber "$env:APP_BUILD_NUMBER" `
-NuGetConfigPath "${{ github.workspace }}/source/NuGet.config"
Comment on lines +596 to +614
- name: Create generated app
id: app
shell: pwsh
run: |
& "${{ github.workspace }}/trusted/.github/scripts/template-app-distribution/New-TemplateApp.ps1" `
-TemplatePackagePath "${{ steps.pack.outputs.template_package_path }}" `
-BuildRoot "${{ runner.temp }}/template-app-build" `
-Variant "${{ matrix.variant }}-${{ matrix.platform }}" `
-ProjectName "${{ matrix.projectName }}" `
-Template "${{ matrix.template }}" `
-TemplateArgsJson '${{ matrix.templateArgsJson }}' `
-DotNetTfm "${{ needs.prepare.outputs.dotnet_tfm }}" `
-TargetFramework "${{ matrix.targetFramework }}" `
-ApplicationId "${{ matrix.applicationId }}" `
-DisplayName "${{ matrix.displayName }}" `
-DotNetSdk "${{ needs.prepare.outputs.dotnet_sdk }}" `
-AppDisplayVersion "$env:APP_DISPLAY_VERSION" `
-AppBuildNumber "$env:APP_BUILD_NUMBER" `
-NuGetConfigPath "${{ github.workspace }}/source/NuGet.config"
Comment on lines +45 to +48
function Write-Base64File([string]$Base64Value, [string]$Path) {
$bytes = [Convert]::FromBase64String($Base64Value)
[System.IO.File]::WriteAllBytes($Path, $bytes)
}
@kubaflo

kubaflo commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

🔍 AI-generated update (GitHub Copilot CLI, on behalf of @kubaflo).

iOS dry-run now emits an installable .ipa

A tester reported "I don't see an IPA file to install the app on iOS." The iOS dry-run only built a Simulator .app.zip, so there was no .ipa in the artifact at all. The latest commit adds a best-effort unsigned ios-arm64 device build wrapped as a Payload/*.app .ipa, alongside the existing Simulator app.

Why unsigned: a dry-run has no Apple signing secrets, and iOS refuses to run unsigned/ad-hoc code on a device. The unsigned IPA is meant to be installed with AltStore/Sideloadly, which re-sign it with the tester's own Apple ID. A directly installable device build still needs the secret-gated ad-hoc IPA or TestFlight (publish=true). The device-IPA build is wrapped in try/catch, so a failure can never regress the Simulator artifact.

Validated on CI — dry-run run 29414424580 (source_ref=net11.0, publish=false): all 8 jobs green. Downloaded the blank-ios artifact and confirmed the IPA:

Check Result
Archive layout Payload/MauiTemplateBlank.app/… at root ✓
Binary Mach-O 64-bit executable arm64
Platform LC_BUILD_VERSION platform 2 (iOS device, not simulator) ✓
DTPlatformName iphoneos
Embedded profile none — so no app-store/Beta profile to reject (the original 0xe800801f error) ✓
Signature not signed at all → AltStore/Sideloadly re-signs ✓

Both blank and sample iOS jobs now produce MauiTemplate*.app.ipa (device) + MauiTemplate*.app.zip (Simulator).

@kubaflo kubaflo added the area-infrastructure CI, Maestro / Coherency, upstream dependencies/versions label Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-infrastructure CI, Maestro / Coherency, upstream dependencies/versions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants