xamarin-ios-migration
Xamarin.iOS / Xamarin.Mac / Xamarin.tvOS → .NET Migration
Use this skill when migrating Xamarin.iOS, Xamarin.Mac, or Xamarin.tvOS native apps (not Xamarin.Forms) to .NET for iOS, .NET for macOS, or .NET for tvOS.
Migration Workflow Overview
- Create a new .NET for iOS/macOS/tvOS project
- Convert project file to SDK-style format
- Update MSBuild properties (MtouchArch, HttpClientHandler, code signing)
- Migrate Info.plist values to csproj
- Copy code and resources
- Update NuGet dependencies
- Migrate binding libraries (if applicable)
- Set up Xamarin.Essentials replacement (if applicable)
- Handle configuration file removal
- Build, verify code signing, test on device
Migration Strategy
Create a new .NET project of the same type and name, then copy code into it. This is simpler than converting the existing project file in place.
Step 1 — SDK-Style Project File
.NET for iOS
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-ios</TargetFramework>
<OutputType>Exe</OutputType>
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<SupportedOSPlatformVersion>13.0</SupportedOSPlatformVersion>
</PropertyGroup>
</Project>
.NET for macOS (Mac Catalyst)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-macos</TargetFramework>
<OutputType>Exe</OutputType>
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<SupportedOSPlatformVersion>10.15</SupportedOSPlatformVersion>
</PropertyGroup>
</Project>
.NET for tvOS
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-tvos</TargetFramework>
<OutputType>Exe</OutputType>
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<SupportedOSPlatformVersion>13.0</SupportedOSPlatformVersion>
</PropertyGroup>
</Project>
For library projects, omit <OutputType> or set to Library.
Replace
net8.0withnet9.0ornet10.0as appropriate. Valid TFMs:net8.0-ios,net8.0-macos,net8.0-tvos.
Step 2 — MSBuild Property Changes
| Xamarin Property | .NET Equivalent | Action |
|---|---|---|
MtouchArch / XamMacArch |
RuntimeIdentifier / RuntimeIdentifiers |
Convert (see table below) |
HttpClientHandler / MtouchHttpClientHandler |
UseNativeHttpHandler |
Convert (see table below) |
MtouchExtraArgs |
(some still apply) | Copy and test |
EnableCodeSigning |
(unchanged) | Copy |
CodeSigningKey |
CodesignKey |
Rename |
CodesignKey |
(unchanged) | Copy |
CodesignProvision |
(unchanged) | Copy |
CodesignEntitlements |
(unchanged) | Copy |
CodesignExtraArgs |
(unchanged) | Copy |
PackageSigningKey |
(unchanged) | Copy |
PackagingExtraArgs |
(unchanged) | Copy |
ProductDefinition |
(unchanged) | Copy |
MtouchEnableSGenConc |
EnableSGenConc |
Rename |
LinkDescription |
(unchanged) | Copy |
MtouchArch → RuntimeIdentifier (iOS)
| MtouchArch Value | RuntimeIdentifier | RuntimeIdentifiers |
|---|---|---|
ARMv7 |
ios-arm |
|
ARMv7s |
ios-arm |
|
ARMv7+ARMv7s |
ios-arm |
|
ARM64 |
ios-arm64 |
|
ARMv7+ARM64 |
ios-arm;ios-arm64 |
|
ARMv7+ARMv7s+ARM64 |
ios-arm;ios-arm64 |
|
x86_64 |
iossimulator-x64 |
|
i386 |
iossimulator-x86 |
|
x86_64+i386 |
iossimulator-x86;iossimulator-x64 |
Use
RuntimeIdentifiers(plural) when targeting multiple architectures.
MtouchArch → RuntimeIdentifier (macOS)
| Value | RuntimeIdentifier |
|---|---|
x86_64 |
osx-x64 |
MtouchArch → RuntimeIdentifier (tvOS)
| Value | RuntimeIdentifier |
|---|---|
ARM64 |
tvos-arm64 |
x86_64 |
tvossimulator-x64 |
HttpClientHandler Conversion
| Xamarin Value | UseNativeHttpHandler |
|---|---|
HttpClientHandler |
false |
NSUrlSessionHandler |
(don't set — default) |
CFNetworkHandler |
(don't set — default) |
Step 3 — Info.plist Changes
MinimumOSVersion / LSMinimumSystemVersion
Move from Info.plist to the project file:
<!-- BEFORE (Info.plist) -->
<key>MinimumOSVersion</key>
<string>13.0</string>
<!-- AFTER (csproj) -->
<PropertyGroup>
<SupportedOSPlatformVersion>13.0</SupportedOSPlatformVersion>
</PropertyGroup>
Other Info.plist entries (display name, bundle identifier, permissions, etc.) remain in Info.plist.
Step 4 — Copy Code and Resources
- Copy source files, storyboards, XIBs, assets, and other resources from the Xamarin project to the new project.
- Copy project properties (code signing, entitlements, linker settings) by comparing project files side-by-side.
- Copy or merge any linker XML files (
LinkDescriptionitems).
Step 5 — Update NuGet Dependencies
| Compatible Frameworks | Incompatible Frameworks |
|---|---|
net8.0-ios |
monotouch, xamarinios, xamarinios10 |
net8.0-macos |
monomac, xamarinmac, xamarinmac20 |
net8.0-tvos |
xamarintvos |
Unlike Android, there is no backward compatibility with old Xamarin iOS/Mac TFMs. Packages must be recompiled for
net8.0-iosetc.
.NET Standard libraries without incompatible dependencies remain compatible.
If no compatible version exists:
- Recompile with .NET TFMs (if you own it)
- Look for a preview .NET version
- Replace with a .NET-compatible alternative
Step 6 — iOS Binding Library Migration
For binding libraries wrapping Objective-C/Swift frameworks:
- Use SDK-style project format with
net8.0-iosTFM - The binding generator and API definitions work the same way
- Verify that native frameworks are updated for the target iOS version
- Test thoroughly — binding edge cases are common
Step 7 — Xamarin.Essentials in Native Apps
If your Xamarin.iOS app used Xamarin.Essentials:
- Remove the
Xamarin.EssentialsNuGet package - Add
<UseMauiEssentials>true</UseMauiEssentials>to your project file - Initialize in your AppDelegate:
using Microsoft.Maui.ApplicationModel;
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
public override UIWindow? Window { get; set; }
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
Window = new UIWindow(UIScreen.MainScreen.Bounds);
var vc = new UIViewController();
Window.RootViewController = vc;
Platform.Init(() => vc);
Window.MakeKeyAndVisible();
return true;
}
}
- Update
usingdirectives:
| Xamarin.Essentials | .NET MAUI Namespace |
|---|---|
| App actions, permissions, version tracking | Microsoft.Maui.ApplicationModel |
| Contacts, email, networking | Microsoft.Maui.ApplicationModel.Communication |
| Battery, sensors, flashlight, haptics | Microsoft.Maui.Devices |
| Media picking, text-to-speech | Microsoft.Maui.Media |
| Clipboard, file sharing | Microsoft.Maui.ApplicationModel.DataTransfer |
| File picking, secure storage, preferences | Microsoft.Maui.Storage |
- For app actions, override
PerformActionForShortcutItem:
public override void PerformActionForShortcutItem(
UIApplication application,
UIApplicationShortcutItem shortcutItem,
UIOperationHandler completionHandler)
{
Platform.PerformActionForShortcutItem(application, shortcutItem, completionHandler);
}
Step 8 — Configuration Files
There is no support for .dll.config or .exe.config files in .NET for iOS/macOS.
<dllmap> elements are not supported in .NET Core. Migrate configuration to
appsettings.json, embedded resources, or platform preferences.
Step 9 — watchOS
Xamarin.watchOS is not supported in .NET. The recommendation is to bundle Swift extensions with .NET for iOS apps instead.
Step 10 — Unsupported Projects
| Project Type | Status |
|---|---|
| Xamarin.iOS | ✅ Supported |
| Xamarin.Mac | ✅ Supported |
| Xamarin.tvOS | ✅ Supported |
| iOS App Extensions | ✅ Supported |
| SpriteKit / SceneKit / Metal | ✅ Supported |
| Xamarin.watchOS | ❌ Not supported |
| OpenGL (iOS) | ❌ Not supported (OpenTK unavailable) |
Build and Troubleshoot
- Delete all
bin/andobj/folders - Build and fix compiler errors iteratively
- Verify code signing settings match your provisioning profiles
- Test on physical devices (especially for App Store builds)
Common issues:
- Namespace not found: Replace
Xamarin.iOS/UIKitimports — most UIKit namespaces remain the same, but verify against the .NET for iOS API surface. - Linker errors: Update
LinkDescriptionXML files if custom linker configuration was used. The linker behavior is similar but stricter in .NET. - Entitlements: Ensure
CodesignEntitlementspoints to the correct file.
API Currency Note
If your migrated app will also adopt .NET MAUI controls (e.g., via UseMaui),
check the maui-current-apis skill for deprecated MAUI APIs to avoid
(ListView, Frame, Device.*, etc.).
Quick Checklist
- ☐ Created new .NET for iOS/macOS/tvOS project
- ☐ Set
TargetFrameworktonet8.0-ios(ornet8.0-macos/net8.0-tvos) - ☐ Set
SupportedOSPlatformVersion(moved from Info.plist) - ☐ Converted
MtouchArch→RuntimeIdentifier(s) - ☐ Converted
HttpClientHandler→UseNativeHttpHandler - ☐ Renamed
CodeSigningKey→CodesignKey(if applicable) - ☐ Renamed
MtouchEnableSGenConc→EnableSGenConc(if applicable) - ☐ Copied source, resources, storyboards, entitlements
- ☐ Updated NuGet dependencies for
net8.0-ioscompatibility - ☐ Added
UseMauiEssentialsif using Essentials - ☐ Removed
.dll.configfiles (not supported) - ☐ Deleted
bin/andobj/folders - ☐ Verified code signing and provisioning
- ☐ Tested on physical device