Skip to content

MAUI (Distribution) #17

MAUI (Distribution)

MAUI (Distribution) #17

name: MAUI (Distribution)
on:
workflow_dispatch:
permissions:
id-token: write # needed for OIDC token use
contents: write # needed for publishing a release
discussions: write
defaults:
run:
shell: pwsh
env:
CSPROJ_PATH: "src/MAUI/MauiDemo.csproj"
NUGETCONFIG_PATH: "src/NuGet.Config"
TELERIK_USERNAME: ${{secrets.MyTelerikAccountUsername}}
TELERIK_PASSWORD: ${{secrets.MyTelerikAccountPassword}}
BUILD_CONFIG: Release
DOTNET_VERSION: "9.0.x"
WINUI_TFM: "net9.0-windows10.0.22621.0"
ANDROID_TFM: "net9.0-android"
IOS_TFM: "net9.0-ios"
MACCATALYST_TFM: "net9.0-maccatalyst"
MACOS_ARTIFACTS_PATH: "artifacts_macos"
IOS_ARTIFACTS_PATH: "artifacts_ios"
ANDROID_ARTIFACTS_PATH: "artifacts_android"
WINDOWS_ARTIFACTS_PATH: "artifacts_windows"
jobs:
# ***************************************** #
# >>>>>>> Generate Common Resources <<<<<<< #
# ***************************************** #
shared-resources:
name: Create Shared Resources
runs-on: windows-2022
outputs:
app_version: ${{steps.version-creator.outputs.app_version}}
steps:
# Generates a version number using year.monthday.run_number.0 (e.g., 2024.824.1.0)
- name: Generate version number using date and run number
id: version-creator
run: |
$buildDay = Get-Date -Format "yyyy.Mdd"
$runNumber = "$env:GITHUB_RUN_NUMBER"
$ver = $buildDay + "." + $runNumber + ".0"
echo "app_version=$ver" >> $env:GITHUB_OUTPUT
# ********************************************* #
# >>>>>>> Windows Microsoft Store build <<<<<<< #
# ********************************************* #
maui-windows-msstore:
name: Build Windows MS Store
needs: shared-resources
runs-on: windows-2022
if: ${{ needs.shared-resources.outputs.app_version != ''}}
env:
RID: win10-x64
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{env.DOTNET_VERSION}}
# Needed only for WinUI builds
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v2
- name: Install MAUI workloads
run: dotnet workload install maui --source https://api.nuget.org/v3/index.json
- name: Restore NuGet packages
run: dotnet restore ${{env.CSPROJ_PATH}} --configfile ${{env.NUGETCONFIG_PATH}}
# Update the manifest for Microsoft Store using the store's app and publisher identity
- name: Update manifest for Microsoft Store build
run: |
[xml]$manifest = get-content 'src\MAUI\Platforms\Windows\Package.appxmanifest'
$manifest.Package.Identity.Version = "${{needs.shared-resources.outputs.app_version}}"
$manifest.Package.Identity.Name = "61469LanceLotSoftware.MauiDemo"
$manifest.Package.Identity.Publisher = "CN=51B5A8B2-5D86-4826-BBE2-C92E963A4C02"
$manifest.Package.Properties.DisplayName = "MauiDemo"
$manifest.Package.Properties.PublisherDisplayName = "Lancelot Software"
$manifest.Package.Applications.Application.VisualElements.DisplayName = "Maui Demo"
$manifest.save("src\MAUI\Platforms\Windows\Package.appxmanifest")
# Compile and publish the WinUI x64 project for the Microsoft Store (no code signing for store builds, Microsoft signs it)
- name: Build WinUI win10-x64
run: dotnet publish ${{env.CSPROJ_PATH}} -f "${{env.WINUI_TFM}}" -p:RuntimeIdentifierOverride="win10-x64" -p:PublishTrimmed=False -p:GenerateAppxPackageOnBuild=true -p:AppxPackageSigningEnabled=false -p:EnableMsixTooling=true --self-contained=true
# Find the msix file
- name: Locate msix
id: find-msix-file
run: |
$msixPath = Get-ChildItem -Filter MauiDemo*.msix -Recurse | %{$_.FullName}
echo "PACKAGE_PATH=$msixPath" >> $env:GITHUB_OUTPUT
# Attaching the asset to workflow run
- name: Attach artifacts
uses: actions/upload-artifact@v4
with:
name: "MauiDemo_v${{needs.shared-resources.outputs.app_version}}_MsftStoreOnly.msix"
path: ${{steps.find-msix-file.outputs.PACKAGE_PATH}}
if-no-files-found: error
retention-days: 30
# ************************************** #
# >>>>>>> Windows Sideload build <<<<<<< #
# ************************************** #
maui-windows-sideload:
name: Build Windows Sideload
needs: shared-resources
runs-on: windows-2022
if: ${{ needs.shared-resources.outputs.app_version != ''}}
strategy:
matrix:
RID: [win10-x64]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{env.DOTNET_VERSION}}
# Needed only for WinUI builds
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v2
- name: Install MAUI workloads
run: dotnet workload install maui --source https://api.nuget.org/v3/index.json
- name: Restore NuGet packages
run: dotnet restore ${{env.CSPROJ_PATH}} --configfile ${{env.NUGETCONFIG_PATH}}
# Update the app manifest using the sideload publisher identity (this MUST match the certificate's details)
- name: Update manifest for side load build
run: |
[xml]$manifest = get-content 'src\MAUI\Platforms\Windows\Package.appxmanifest'
$manifest.Package.Identity.Version = "${{needs.shared-resources.outputs.app_version}}"
$manifest.Package.Identity.Name = "LanceMcCarthy.MauiDemo"
$manifest.Package.Identity.Publisher = 'CN=" Lance McCarthy", O=" Lance McCarthy", L=Revere, S=Massachusetts, C=US'
$manifest.Package.Properties.DisplayName = "MauiDemo"
$manifest.Package.Properties.PublisherDisplayName = "Lance McCarthy"
$manifest.Package.Applications.Application.VisualElements.DisplayName = "Maui Demo"
$manifest.save("src\MAUI\Platforms\Windows\Package.appxmanifest")
- name: Build WinUI ${{matrix.RID}}
run: dotnet publish ${{env.CSPROJ_PATH}} -f ${{env.WINUI_TFM}} -p:RuntimeIdentifierOverride=${{matrix.RID}} -p:PublishTrimmed=False -p:GenerateAppxPackageOnBuild=true -p:AppxPackageSigningEnabled=false -p:EnableMsixTooling=true --self-contained=true
- name: Locate msix
id: find-msix-file
run: |
$msixPath = Get-ChildItem -Filter MauiDemo*.msix -Recurse | %{$_.FullName}
echo "PACKAGE_PATH=$msixPath" >> $env:GITHUB_OUTPUT
# No secrets needed, uses the GitHub OIDC token's subject identifier "repo:LanceMcCarthy/DevOpsExamples:ref:refs/heads/main"
# Entra ID App Registration > Certificates and Secrets > Federated Credentials
- name: Azure login using OIDC via GitHub
uses: azure/login@v2
id: azlogin
with:
client-id: "32daa13b-f4bb-4809-8ef6-58cb39051acd"
tenant-id: "bd47e796-3473-4b8a-9101-1f4c0c7af31a"
subscription-id: "48ab4839-62af-4ab3-afe6-043ea4d7c137"
# CODESIGN (uses Lance's certificate for now)
- name: Sign files with Trusted Signing
uses: azure/[email protected]
with:
endpoint: https://eus.codesigning.azure.net/
trusted-signing-account-name: PrimaryCodeSign
certificate-profile-name: lancemccarthylivepublic
timestamp-rfc3161: http://timestamp.acs.microsoft.com
timestamp-digest: SHA256
file-digest: SHA256
files: ${{steps.find-msix-file.outputs.PACKAGE_PATH}}
exclude-azure-cli-credential: false
exclude-environment-credential: true
exclude-workload-identity-credential: true
exclude-managed-identity-credential: true
exclude-shared-token-cache-credential: true
exclude-visual-studio-credential: true
exclude-visual-studio-code-credential: true
exclude-azure-powershell-credential: true
exclude-azure-developer-cli-credential: true
exclude-interactive-browser-credential: true
- name: Attach artifacts to workflow run
uses: actions/upload-artifact@v4
with:
name: "MauiDemo_v${{needs.shared-resources.outputs.app_version}}_${{matrix.RID}}.msix"
path: ${{steps.find-msix-file.outputs.PACKAGE_PATH}}
if-no-files-found: error
retention-days: 30
# ********************************* #
# >>>>>>> MacCatalyst Build <<<<<<< #
# ********************************* #
maui-macos:
name: Build MacCatalyst
needs: shared-resources
runs-on: macos-latest
if: ${{ needs.shared-resources.outputs.app_version != ''}}
strategy:
matrix:
RID: [maccatalyst-arm64, maccatalyst-x64]
# Consider matrix for test flight and sideload
env:
CODESIGN_KEY: "Apple Distribution: Lancelot Software (XXXXXXXXXX)"
CODESIGN_PROV_PROFILE: "MauiDemo_maccatalyst_appstore"
CODESIGN_PROFILE_TYPE: "MAC_APP_STORE"
CODESIGN_ENTITLEMENTS: "Platforms/MacCatalyst/Entitlements.plist"
APP_ID: "com.LancelotSoftware.MauiDemo"
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: 16.1
- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{env.DOTNET_VERSION}}
- name: Install MAUI workloads
run: dotnet workload install maui --source https://api.nuget.org/v3/index.json
- name: Restore NuGet packages
run: dotnet restore ${{env.CSPROJ_PATH}} -r ${{matrix.RID}} --configfile ${{env.NUGETCONFIG_PATH}}
# ------- Placeholder debug build ------- #
- name: Build MAUI MacCatalyst project
run: dotnet build ${{env.CSPROJ_PATH}} -c Debug -f ${{env.MACCATALYST_TFM}} -p:RuntimeIdentifier=${{matrix.RID}} -p:PublishTrimmed=true -p:MtouchLink=SdkOnly
# ------- When you have an Apple account and certificates, you can replace the previous step, with these steps for a Release build. ------- #
# # Docs https://github.com/Apple-Actions/import-codesign-certs
# - name: Import Code-Signing Certificates
# uses: Apple-Actions/import-codesign-certs@v3
# with:
# p12-file-base64: "${{secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64}}"
# p12-password: "${{secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD}}"
# # Docs https://github.com/Apple-Actions/download-provisioning-profiles
# - uses: Apple-Actions/download-provisioning-profiles@v3
# id: provisioning
# with:
# profile-type: ${{env.CODESIGN_PROFILE_TYPE}}
# bundle-id: "${{env.APP_ID}}"
# issuer-id: "${{secrets.APPSTORE_API_ISSUER_ID}}"
# api-key-id: "${{secrets.APPSTORE_API_KEY_ID}}"
# api-private-key: "${{secrets.APPSTORE_API_PRIVATE_KEY}}"
# # Docs https://learn.microsoft.com/en-us/dotnet/maui/mac-catalyst/deployment/publish-app-store?view=net-maui-8.0
# # Carefully follow the intructions about entitlements.plist and info.plist
# - name: Build MAUI MacCatalyst project
# run: |
# dotnet publish ${{env.CSPROJ_PATH}} -c Release -f ${{env.MACCATALYST_TFM}} -p:RuntimeIdentifier=${{env.RID}} -p:EnableCodeSigning=true -p:EnablePackageSigning=true -p:PublishTrimmed=true -p:MtouchLink=SdkOnly -p:ApplicationId="${{env.APP_ID}}" -p:CodesignProvision="${{env.CODESIGN_PROV_PROFILE}}" -p:CodesignKey=${{env.CODESIGN_KEY}} -p:CodesignEntitlements=${{env.CODESIGN_ENTITLEMENTS}}
# # Docs https://github.com/Apple-Actions/upload-testflight-build
# - name: 'Upload app to TestFlight'
# uses: apple-actions/upload-testflight-build@v1
# with:
# app-path: "${{github.workspace}}/**/*.pkg"
# issuer-id: ${{secrets.APPSTORE_API_ISSUER_ID}}
# api-key-id: "${{secrets.APPSTORE_API_KEY_ID}}"
# api-private-key: "${{secrets.APPSTORE_API_PRIVATE_KEY}}"
- name: Publish MacCatalyst build artifacts
uses: actions/upload-artifact@v4
with:
name: "MacCatalyst artifacts"
path: "*.pkg"
if-no-files-found: warn
retention-days: 30
# ************************* #
# >>>>>>> iOS Build <<<<<<< #
# ************************* #
# maui-ios:
# name: Build iOS
# needs: shared-resources
# runs-on: macos-latest
# if: ${{ needs.shared-resources.outputs.app_version != ''}}
# env:
# RID: ios-arm64
# CODESIGN_KEY: "Apple Distribution: Lancelot Software (XXXXXXXXXX)"
# CODESIGN_PROV_PROFILE: "MauiDemo_ios_appstore"
# CODESIGN_PROFILE_TYPE: "IOS_APP_STORE"
# APP_ID: "com.LancelotSoftware.mauidemo"
# steps:
# - name: Checkout
# uses: actions/checkout@v4
# with:
# fetch-depth: 0
# - uses: maxim-lobanov/setup-xcode@v1
# with:
# xcode-version: 16.1
# - name: Setup .NET Core SDK
# uses: actions/setup-dotnet@v4
# with:
# dotnet-version: ${{env.DOTNET_VERSION}}
# - name: Install MAUI workloads
# run: dotnet workload install maui --source https://api.nuget.org/v3/index.json
# - name: Restore NuGet packages
# run: dotnet restore ${{env.CSPROJ_PATH}} -r ${{env.RID}} --configfile ${{env.NUGETCONFIG_PATH}}
# # Docs https://github.com/Apple-Actions/import-codesign-certs
# - name: Import Code-Signing Certificates
# uses: Apple-Actions/import-codesign-certs@v3
# with:
# p12-file-base64: "${{secrets.APPLE_DISTRIBUTION_CERT_BASE64}}"
# p12-password: "${{secrets.APPLE_DISTRIBUTION_CERT_PASSWORD}}"
# # Docs https://github.com/Apple-Actions/download-provisioning-profiles
# - uses: Apple-Actions/download-provisioning-profiles@v3
# id: provisioning
# with:
# profile-type: ${{env.CODESIGN_PROFILE_TYPE}}
# bundle-id: "${{env.APP_ID}}"
# issuer-id: "${{secrets.APPSTORE_API_ISSUER_ID}}"
# api-key-id: "${{secrets.APPSTORE_API_KEY_ID}}"
# api-private-key: "${{secrets.APPSTORE_API_PRIVATE_KEY}}"
# # Docs https://learn.microsoft.com/en-us/dotnet/maui/ios/deployment/publish-cli?view=net-maui-8.0
# - name: Build MAUI iOS project
# run: |
# dotnet publish ${{env.CSPROJ_PATH}} -f ${{env.IOS_TFM}} -p:RuntimeIdentifier=${{env.RID}} -p:PublishTrimmed=true -p:MtouchLink=SdkOnly -p:ApplicationId=${{env.APP_ID}} -p:CodesignProvision="${{env.CODESIGN_PROV_PROFILE}}" -p:CodesignKey=${{env.CODESIGN_KEY}}
# # Docs https://github.com/Apple-Actions/upload-testflight-build
# - name: 'Upload app to TestFlight'
# uses: apple-actions/upload-testflight-build@v1
# with:
# app-path: "${{github.workspace}}/**/*.ipa"
# issuer-id: ${{secrets.APPSTORE_API_ISSUER_ID}}
# api-key-id: "${{secrets.APPSTORE_API_KEY_ID}}"
# api-private-key: "${{secrets.APPSTORE_API_PRIVATE_KEY}}"
# - name: Publish iOS build artifacts
# uses: actions/upload-artifact@v4
# with:
# name: "iOS artifacts"
# path: "*.app"
# if-no-files-found: warn
# retention-days: 30
# ***************************** #
# >>>>>>> Android build <<<<<<< #
# ***************************** #
# maui-android:
# name: Build Android
# needs: shared-resources
# runs-on: windows-2022
# if: ${{ needs.shared-resources.outputs.app_version != ''}}
# env:
# RID: android-arm64
# steps:
# - name: Checkout
# uses: actions/checkout@v4
# with:
# fetch-depth: 0
# - name: Setup .NET Core SDK
# uses: actions/setup-dotnet@v4
# with:
# dotnet-version: ${{env.DOTNET_VERSION}}
# - uses: actions/setup-java@v4
# with:
# distribution: 'microsoft'
# java-version: '11'
# - name: Install MAUI workloads
# run: dotnet workload install maui --source https://api.nuget.org/v3/index.json
# - name: Restore NuGet packages
# run: dotnet restore ${{env.CSPROJ_PATH}} --configfile ${{env.NUGETCONFIG_PATH}}
# # When you have a Google Play account and certificates, we can switch to this release setup
# # Decode keystore base64 secret into a local file
# - name: Decode the Keystore into File
# run: |
# $file_bytes = [System.Convert]::FromBase64String("${{secrets.ANDROID_SIGNING_KEYSTORE_BASE64}}")
# [IO.File]::WriteAllBytes("${{github.workspace}}/${{secrets.ANDROID_SIGNING_KEYSTORE_FILENAME}}", $file_bytes)
# # Docs https://learn.microsoft.com/en-us/dotnet/maui/android/deployment/publish-cli?view=net-maui-8.0
# - name: Build MAUI Android project
# run: dotnet publish ${{env.CSPROJ_PATH}} -c ${{env.BUILD_CONFIGURATION}} -f ${{env.ANDROID_TFM}} -p:AndroidKeyStore=true -p:AndroidSigningKeyStore="${{github.workspace}}/${{secrets.ANDROID_SIGNING_KEYSTORE_FILENAME}}" -p:AndroidSigningStorePass="${{secrets.ANDROID_SIGNING_STORE_PASS}}" -p:AndroidSigningKeyAlias="${{secrets.ANDROID_SIGNING_KEY_ALIAS}}" -p:AndroidSigningKeyPass="${{secrets.ANDROID_SIGNING_KEY_PASS}}"
# # Upload the artifact the Action's result
# # To publish to the store, see https://github.com/marketplace/actions/upload-android-release-to-play-store
# - name: Upload Android AAB artifacts (better than APKs)
# uses: actions/upload-artifact@v4
# with:
# name: "Android Artifacts"
# path: "${{github.workspace}}/**/*Signed.aab"
# if-no-files-found: warn
# retention-days: 10
# ****************************** #
# >>>>>>> GitHub Release <<<<<<< #
# ****************************** #
# create_release:
# name: Create a new release
# if: ${{success()}}
# needs: [shared-resources, maui-macos, maui-windows-sideload, maui-windows-msstore] #, maui-ios, maui-android
# runs-on: ubuntu-latest
# defaults:
# run:
# shell: bash
# steps:
# - name: Download Artifacts
# uses: actions/download-artifact@v4
# with:
# pattern: MauiDemo*
# - name: Confirm downloaded files
# run: ls -R
# - name: Install zip tools
# run: |
# sudo apt-get update
# sudo apt-get install zip
# - name: Archive each release asset
# run: |
# for file in *; do
# if [ -f "$file" ]; then
# echo "zipping up $file ..."
# zip -r "$file.zip" "$file"
# fi
# done
# - name: Delete original files
# run: find . -type f -not -name '*.zip' -delete
# - name: Confirm processed files
# run: ls
# - name: Create list of zip files
# id: prepare-files-list
# run: |
# files=("*.zip")
# echo "release_files=$files" >> $env:GITHUB_OUTPUT
# - name: Release
# uses: softprops/action-gh-release@v2
# with:
# name: "${{needs.shared-resources.outputs.app_version}}"
# tag_name: "${{needs.shared-resources.outputs.app_version}}"
# fail_on_unmatched_files: true
# files: ${steps.prepare-files-list.outputs.release_files}