.NET MAUI app crashes on start when testing TestFlight build

Ben Horton 0 Reputation points
2025-08-27T16:40:06.74+00:00

I have a .NET MAUI app that works perfectly fine locally in debug and release mode for iOS (iPhone and iPad) and works fine on Android locally and in production on Google Play. I run it from Visual Studio 2022 paired to my MacBook pro 2021 on real and simulated devices and there are no problems.

However, when I make a release ipa file, add it to App Store Connect and download it to a device using TestFlight the app crashes straight away (it just shows the splash screen briefly).

I've attached the symbolicated.crash file (symbolicated.txt) sent from the iPhone using TestFlight during the crash.

Publish command for ipa file (sensitive content hashed):

dotnet publish App.csproj -f:net9.0-ios -c:Release ^
   /p:PlatformTarget=Arm64 ^
   /p:RuntimeIdentifier=ios-arm64 ^
   /p:ServerAddress=###.###.#.## ^
   /p:ServerUser=######### ^
   /p:ServerPassword=######## ^
   /p:ArchiveOnBuild=true ^
   /p:BuildIpa=true

Relavant Csproj content:

<PropertyGroup>
	<TargetFrameworks>net9.0-android;net9.0-ios;net9.0-maccatalyst;net9.0</TargetFrameworks>
	<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net9.0-windows10.0.19041.0</TargetFrameworks>
	<RuntimeIdentifiers Condition="'$(TargetFramework)' == 'net9.0-android'">android-arm64;android-arm;android-x86;android-x64</RuntimeIdentifiers>
	<OutputType Condition="'$(TargetFramework)' != 'net9.0'">Exe</OutputType>
	<RootNamespace>AppName</RootNamespace>
	<UseMaui>true</UseMaui>
	<SingleProject>true</SingleProject>
	<ImplicitUsings>enable</ImplicitUsings>
	<!-- Display name -->
	<ApplicationTitle>App Name</ApplicationTitle>
	<!-- App Identifier -->
	<ApplicationId>app.b.com.name</ApplicationId>
	<ApplicationIdGuid>########-####-####-####-############</ApplicationIdGuid>
	<!-- Versions -->
	<ApplicationDisplayVersion>1.0.0</ApplicationDisplayVersion>
	<ApplicationVersion>1</ApplicationVersion>
	<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
	<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">14.0</SupportedOSPlatformVersion>
	<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">23.0</SupportedOSPlatformVersion>
	<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
	<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
	<NeutralLanguage>en-GB</NeutralLanguage>
	<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.19041.0</SupportedOSPlatformVersion>
</PropertyGroup>
	<ItemGroup>
		<PackageReference Include="CommunityToolkit.Maui" Version="11.1.0" />
		<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
		<PackageReference Include="DecimalMath.DecimalEx" Version="1.0.2" />
		<PackageReference Include="Plugin.InAppBilling" Version="9.1.0" />
		<PackageReference Include="Plugin.MauiMTAdmob" Version="2.0.2" />
		<PackageReference Include="Plugin.StoreReview" Version="6.2.0" />
		<PackageReference Include="Microsoft.Maui.Controls" Version="9.0.40" />
		<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="9.0.40" />
	</ItemGroup>

The only thing I've found that prevents the crash is to add the following to the csproj:

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net9.0-ios|AnyCPU'">

<MtouchLink>None</MtouchLink>

</PropertyGroup>

However, this massively increases the time the generate the ipa file, the app download size, and means lots of additional info.plist entries are required:

<key>NSCalendarsUsageDescription</key>

<string>We use this data to provide personalized advertising.</string>

<key>NSContactsUsageDescription</key>

<string>We use this data to provide personalized advertising.</string>

<key>NSMicrophoneUsageDescription</key>

<string>We use this data to provide personalized advertising.</string>

<key>NSAppleMusicUsageDescription</key>

<string>We use this data to provide personalized advertising.</string>

<key>NSSiriUsageDescription</key>

<string>We use this data to provide personalized advertising.</string>

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>

<string>We use this data to provide personalized advertising.</string>

<key>NSLocationWhenInUseUsageDescription</key>

<string>We use this data to provide personalized advertising.</string>

<key>NSBluetoothAlwaysUsageDescription</key>

<string>We use this data to provide personalized advertising.</string>  

I've tried the following to narrow the issue down but nothing else has prevented the crash or made any noticeable difference (EnableAssemblyILStripping, MtouchExtraArgs, and TrimmerRootAssembly):

	<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net9.0-ios|AnyCPU'">
		<MtouchUseLlvm>True</MtouchUseLlvm>
		<MtouchLink>SdkOnly</MtouchLink>
		<EnableAssemblyILStripping>false</EnableAssemblyILStripping>
		<MtouchExtraArgs>
			--setenv=MONO_LOG_LEVEL=debug
			--setenv=MONO_LOG_MASK=assembly,aot
			--linkskip=CommunityToolkit.Maui
			--linkskip=CommunityToolkit.Mvvm
			--linkskip=DecimalEx
			--linkskip=Plugin.InAppBilling
			--linkskip=Plugin.MauiMtAdmob
			--linkskip=Plugin.StoreReview
			--linkskip=Microsoft.Maui.Controls
			--linkskip=Microsoft.Maui.Controls.Compatibility
		</MtouchExtraArgs>
	</PropertyGroup>
	<ItemGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net9.0-ios|AnyCPU'">
		<!-- Root your app's main assembly so it's not trimmed away -->
		<TrimmerRootAssembly Include="AppName" />
		<!-- Root common transitive assemblies often used via reflection -->
		<TrimmerRootAssembly Include="Microsoft.Extensions.DependencyInjection" />
		<TrimmerRootAssembly Include="Microsoft.Extensions.Logging" />
		<TrimmerRootAssembly Include="Microsoft.Extensions.Logging.Abstractions" />
		<TrimmerRootAssembly Include="Microsoft.Extensions.Options" />
		<TrimmerRootAssembly Include="System.Text.Json" />
		
		<!--Nuget packages-->
		<TrimmerRootAssembly Include="CommunityToolkit.Maui" />
		<TrimmerRootAssembly Include="CommunityToolkit.Mvvm" />
		<TrimmerRootAssembly Include="DecimalEx" />
		<TrimmerRootAssembly Include="Plugin.InAppBilling" />
		<TrimmerRootAssembly Include="Plugin.MauiMtAdmob" />
		<TrimmerRootAssembly Include="Plugin.StoreReview" />
		<TrimmerRootAssembly Include="Microsoft.Maui.Controls" />
		<TrimmerRootAssembly Include="Microsoft.Maui.Controls.Compatibility" />
	</ItemGroup>

If anyone can help me to figure out what is causing the issue, can see any issues in my code or has experienced something similar I'd really appreciate your help.

Thanks!

Developer technologies | .NET | .NET MAUI
{count} votes

1 answer

Sort by: Most helpful
  1. Tony Dinh (WICLOUD CORPORATION) 940 Reputation points Microsoft External Staff
    2025-08-28T07:26:02.9233333+00:00

    Hello @Ben Horton !

    The crash you see on TestFlight happens during Mono runtime startup while loading AOT (Ahead-Of-Time) compiled modules. On the macOS/Simulator, JIT (Just-In-Time) compilation is allowed, so any code not compiled ahead-of-time can be compiled at runtime, and the app appears to work. On iOS devices, the runtime is AOT-only. If trimming or AOT didn't produce a native body for a needed method, the runtime falls back to its JIT path as a last resort. Since JIT is forbidden on iOS, the process aborts and terminate the thread.

    Docs: https://learn.microsoft.com/en-us/dotnet/maui/macios/interpreter?view=net-maui-9.0

    You can inspect this in your crash log (symbolicated.txt, thread 0, line at 33-35):

    load_aot_module -> mono_aot_get_method -> mono_jit_compile_method_with_opt -> abort
    

    Here are the solution steps you can try:

    1. Preserve necessary assemblies. You can start by preserving assemblies that are likely used via reflection at startup. This helps narrow down the cause of the crash. Create a linker.xml file in your project:
          <!-- linker.xml -->
          <linker>
            <!-- Start with a small set; add/remove based on tests -->
            <assembly fullname="Plugin.InAppBilling" preserve="all" />
            <assembly fullname="Plugin.MauiMTAdmob" preserve="all" />
            <!-- If included by your ads package -->
            <assembly fullname="Google.MobileAds" preserve="all" />
            <assembly fullname="UserMessagingPlatform" preserve="all" />
          </linker>
      
      Then, include it only for the iOS release build in your .csproj file:
          <ItemGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net9.0-ios|AnyCPU'">
            <TrimmerRootDescriptor Include="linker.xml" />
          </ItemGroup>
      
    2. Use SdkOnly linking. This keeps the linker active on the SDK and MAUI to avoid bloat while only preserving what’s necessary.
          <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net9.0-ios|AnyCPU'">
            <MtouchLink>SdkOnly</MtouchLink>
            <MtouchUseLlvm>true</MtouchUseLlvm>
            <MtouchExtraArgs>
              --aot=verbose
              --setenv=MONO_LOG_MASK=assembly,aot
              --setenv=MONO_LOG_LEVEL=debug
            </MtouchExtraArgs>
          </PropertyGroup>
      
      Avoid using --linkskip on Microsoft.Maui.* or System.* assemblies. This can expose unsupported APIs, leading to JIT attempts, more crashes, App Store issues, or the need for extra Info.plist keys, as you observed.
    3. Inspect device logs. Launch the TestFlight build and capture device logs in Console.app (macOS) > Devices > your iPhone. Filter for AOT module or JIT. Messages like "AOT module ‘X’ not found" or "attempting to JIT compile …" will point to the exact assembly or type that needs to be preserved.
    4. Update your toolchain. Update to the latest .NET 9 SDK/Xcode and ensure your MAUI, Plugin.InAppBilling, and AdMob packages are on their latest compatible versions.

    Following these steps helps pinpoint the cause of the crash, which is a better approach than setting <MtouchLink>None</MtouchLink> and including every assembly.

    I hope this helps! Let me know if you have any question!

    References:

    Related Issues:

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.