A Microsoft open-source framework for building native device applications spanning mobile, tablet, and desktop.
Hi @Natalie van Gogh ,
Thank you for sharing your final solution.
Here are some additional insights, the key finding here is that setting the project to ios-arm64 alone did not remove the x86_64 slice from the packaged libSkiaSharp.framework. Your lipo result still reported both x86_64 and arm64.
Your workaround addresses that remaining architecture directly as part of the iOS Release build.
Keep the Release build targeted to arm64
The project can remain explicitly configured for the iOS device runtime:
<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
<Platforms>arm64</Platforms>
<RuntimeIdentifier>ios-arm64</RuntimeIdentifier>
<ArchiveOnBuild>true</ArchiveOnBuild>
<BuildIpa>true</BuildIpa>
</PropertyGroup>
Microsoft's MAUI publishing guidance uses ios-arm64 as the Runtime Identifier when publishing an iOS application for device/App Store distribution.
Remove the remaining x86_64 slice during the Release build
Since libSkiaSharp.framework was still being packaged with both architectures, the additional build target uses lipo to inspect the framework and remove x86_64:
<Target Name="StripSkiaSimulatorSlice" Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
<Exec Command="xcrun lipo -info "$(AppBundleDir)/Frameworks/libSkiaSharp.framework/libSkiaSharp"" />
<Exec Command="xcrun lipo -remove x86_64 "$(AppBundleDir)/Frameworks/libSkiaSharp.framework/libSkiaSharp" -output "$(AppBundleDir)/Frameworks/libSkiaSharp.framework/libSkiaSharp" || true" />
<Exec Command="xcrun lipo -info "$(AppBundleDir)/Frameworks/libSkiaSharp.framework/libSkiaSharp"" />
</Target>
This directly removes the architecture identified by the App Store validation error while leaving the required arm64 slice in the framework. In your case, this was necessary because explicitly publishing with ios-arm64 had still produced a framework containing both architectures.
Run the target as part of the signing flow
Adding the target to CodesignDependsOn makes the workaround part of the Release build process:
<CodesignDependsOn>
$(CodesignDependsOn);StripSkiaSimulatorSlice
</CodesignDependsOn>
This is particularly useful in your scenario because the adjustment is made to the framework included in the iOS build rather than modifying the SkiaSharp package in the local NuGet cache. You had specifically noted that you did not want to modify the NuGet package because the same machine is also used to build the Android version.
So, in summary, the approach is:
Release iOS build
↓
Target ios-arm64
↓
Inspect packaged libSkiaSharp
↓
Remove remaining x86_64 slice
↓
Verify the resulting architecture
↓
Continue with code signing / IPA generation
Thank you again for taking the time to share your findings with the community. If you found my explanation was helpful or informative to your solution, I would greatly appreciate it if you could follow this guide so others with the same issue can benefit as well.
Thank you.