1

I've got a new MAUI project and I'm trying to set up a basic CI pipeline for it.

I've got this as my workflow definition:

name: MAUI Continuous Integration

on:
  pull_request: 
    branches:
      - master
  push:
    branches:
      - master
        
jobs:        
  build-android:
    name: "Build Android"
    runs-on: windows-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
      - name: Setup .NET
        uses: actions/setup-dotnet@v1
        with:
          dotnet-version: 8.0.x
      - name: Install MAUI Workloads
        run: |
          dotnet workload install maui
          dotnet workload install android
      - name: Restore Dependencies
        run: dotnet restore ./src/OpenEqiSports/OpenEqiSports.csproj
      - name: Build Android
        run: dotnet build ./src/OpenEqiSports/OpenEqiSports.csproj  -c Release -f net8.0-android --no-restore
      - name: Upload Android Artifact
        uses: actions/upload-artifact@v2
        with:
          name: OpenEqiSports-Android
          path: ./src/OpenEqiSports/bin/Release/net8.0-android/*Signed.a*
          
  build-windows:
    name: "Build Windows"
    runs-on: windows-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
      - name: Setup .NET
        uses: actions/setup-dotnet@v1
        with:
          dotnet-version: 8.0.x
      - name: Install MAUI Workloads
        run: dotnet workload install maui
      - name: Restore Dependencies
        run: dotnet restore ./src/OpenEqiSports/OpenEqiSports.csproj
      - name: Build Windows
        run: dotnet build ./src/OpenEqiSports/OpenEqiSports.csproj -c Release -f net8.0-windows --no-restore
      - name: Upload Windows Artifact
        uses: actions/upload-artifact@v2
        with:
          name: OpenEqiSports-Windows
          path: ./src/OpenEqiSports/bin/Release/net8.0-windows*/**/OpenEqiSports*.msix   

  build-ios:
    name: "Build iOS"
    runs-on: macos-14
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
      - name: Select Xcode 15.2
        run: sudo xcode-select -s /Applications/Xcode_15.1.app/Contents/Developer
      - name: Setup .NET
        uses: actions/setup-dotnet@v1
        with:
          dotnet-version: 8.0.x
      - name: Install MAUI Workloads
        run: |
          dotnet workload install maui
          dotnet workload install ios
      - name: Restore Dependencies
        run: dotnet restore ./src/OpenEqiSports/OpenEqiSports.csproj
      - name: Build iOS
        run: dotnet build ./src/OpenEqiSports/OpenEqiSports.csproj -c Release -f net8.0-ios --no-restore
      - name: Upload iOS Artifact
        uses: actions/upload-artifact@v2
        with:
          name: OpenEqiSports-iOS
          path: ./src/OpenEqiSports/bin/Release/net8.0-ios/**/*.app/
          
  build-maccatalyst:
    name: "Build MacCatalyst"
    runs-on: macos-14
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
      - name: Select Xcode 15.2
        run: sudo xcode-select -s /Applications/Xcode_15.1.app/Contents/Developer
      - name: Setup .NET
        uses: actions/setup-dotnet@v1
        with:
          dotnet-version: 8.0.x
      - name: Install MAUI Workloads
        run: |
          dotnet workload install maui
          dotnet workload install maccatalyst
      - name: Restore Dependencies
        run: dotnet restore ./src/OpenEqiSports/OpenEqiSports.csproj
      - name: Build MacCatalyst
        run: dotnet build ./src/OpenEqiSports/OpenEqiSports.csproj -c Release -f net8.0-maccatalyst --no-restore
      - name: Upload MacCatalyst Artifact
        uses: actions/upload-artifact@v2
        with:
          name: OpenEqiSports-MacCatalyst
          path: ./src/OpenEqiSports/bin/Release/net8.0-maccatalyst/**/*.app/

(Yes, I know this needs refactoring)

And my csproj looks like:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks>
        <TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.22621.0</TargetFrameworks>

        <OutputType>Exe</OutputType>
        <RootNamespace>OpenEqiSports</RootNamespace>
        <UseMaui>true</UseMaui>
        <SingleProject>true</SingleProject>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>

        <!-- Display name -->
        <ApplicationTitle>OpenEqiSports</ApplicationTitle>

        <!-- App Identifier -->
        <ApplicationId>com.hughesjs.openeqisports</ApplicationId>

        <!-- Versions -->
        <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
        <ApplicationVersion>1</ApplicationVersion>

        <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">17,2</SupportedOSPlatformVersion>
        <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
        <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">24.0</SupportedOSPlatformVersion>
        <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.22621.0</SupportedOSPlatformVersion>
        <TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.22621.0</TargetPlatformMinVersion>
        <LangVersion>latest</LangVersion>
    </PropertyGroup>

    <ItemGroup>
        <!-- App Icon -->
        <MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />

        <!-- Splash Screen -->
        <MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />

        <!-- Images -->
        <MauiImage Include="Resources\Images\*" />
        <MauiImage Update="Resources\Images\dotnet_bot.png" Resize="True" BaseSize="300,185" />

        <!-- Custom Fonts -->
        <MauiFont Include="Resources\Fonts\*" />

        <!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
        <MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
    </ItemGroup>

    <ItemGroup>
        <PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
        <PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
        <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
        <PackageReference Include="Plugin.BLE" Version="3.0.0" />
    </ItemGroup>

</Project>

Now, this successfully builds the Android and iOS versions and the others fail with:

Windows:

MSBuild version 17.8.3+195e7f5a3 for .NET Error: C:\Users\runneradmin\AppData\Local\Microsoft\dotnet\sdk\8.0.101\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.TargetFrameworkInference.targets(215,5): error NETSDK1135: SupportedOSPlatformVersion 10.0.22621.0 cannot be higher than TargetPlatformVersion 7.0. [D:\a\OpenEQiSports\OpenEQiSports\src\OpenEqiSports\OpenEqiSports.csproj::TargetFramework=net8.0-windows]

This just has me bamboozled, dotnet 8 is installed so what's the issue?

MacCatalyst:

Error: /Users/runner/.dotnet/sdk/8.0.101/Sdks/Microsoft.NET.Sdk/targets/Microsoft.PackageDependencyResolution.targets(266,5): error NETSDK1047: Assets file '/Users/runner/work/OpenEQiSports/OpenEQiSports/src/OpenEqiSports/obj/project.assets.json' doesn't have a target for 'net8.0-maccatalyst/maccatalyst-x64'. Ensure that restore has run and that you have included 'net8.0-maccatalyst' in the TargetFrameworks for your project. You may also need to include 'maccatalyst-x64' in your project's RuntimeIdentifiers. [/Users/runner/work/OpenEQiSports/OpenEQiSports/src/OpenEqiSports/OpenEqiSports.csproj::TargetFramework=net8.0-maccatalyst]

I have the target framework set...

What's going on here? It all builds fine locally (well, I can't test the Windows one as I'm on a mac, but the rest builds). How can I get this going?

1 Answer 1

0

The issues here were legion:

MacCatalyst

Due to MacOS running on both Arm64 and x64 in a decent proportion, it wouldn't make sense to assume a Runtime ID. As such, I needed to specify the runtime for each and build for each separately. This is done with the --runtime <RID> flag on dotnet build. I coupled that with a matrix so the relevant section of the yml now looks like:

  build-maccatalyst:
    strategy:
      matrix:
        runtime: [maccatalyst-arm64, maccatalyst-x64]
    name: "Build MacCatalyst (${{ matrix.runtime }})"
#    needs: run-tests
    runs-on: macos-14
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Select Xcode 15.2
        run: sudo xcode-select -s /Applications/Xcode_15.1.app/Contents/Developer
      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: 8.0.x
      - name: Install MAUI Workloads
        run: |
          dotnet workload install maui
          dotnet workload install maccatalyst
      - name: Restore Dependencies
        run: dotnet restore ./src/OpenEqiSports/OpenEqiSports.csproj
      - name: Build MacCatalyst
        run: dotnet build ./src/OpenEqiSports/OpenEqiSports.csproj -c Release -f net8.0-maccatalyst --no-restore --runtime ${{ matrix.runtime }}
      - name: Upload MacCatalyst Artifact
        uses: actions/upload-artifact@v4
        with:
          name: OpenEqiSports-${{ matrix.runtime }}
          path: ./src/OpenEqiSports/bin/Release/net8.0-maccatalyst/**/*.app/
          

Windows

So dotnet 8 has a minimum target framework of net8.0-windows10.0.19041.0.

So in the csproj we need:

<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.19041.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.19041.0</TargetPlatformMinVersion>

Unfortunately, there seems to be a bug in dotnet 8 that also causes weird issues when building, so working around that takes a --self-contained build.

This makes the CI section look like:

  build-windows:
    name: "Build Windows"
#    needs: run-tests
    runs-on: windows-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: 8.0.x
      - name: Install MAUI Workloads
        run: dotnet workload install maui
      - name: Build Windows
        run: dotnet build ./src/OpenEqiSports/OpenEqiSports.csproj -c Release -f net8.0-windows10.0.19041.0 --self-contained
      - name: Upload Windows Artifact
        uses: actions/upload-artifact@v4
        with:
          name: OpenEqiSports-Windows
          path: ./src/OpenEqiSports/bin/Release/net8.0-windows*/**/OpenEqiSports*.msix   
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.