
Xamarin Android Migration
- 22 installs
- 163 repo stars
- Updated July 6, 2026
- davidortinau/maui-skills
Migrates Xamarin.Android native apps to .NET for Android, covering SDK-style project conversion, TFMs, MSBuild property changes, and manifest updates.
About
A workflow guide for migrating Xamarin.Android native apps to .NET for Android, covering SDK-style project conversion, target framework monikers, MSBuild property changes, AndroidManifest.xml updates and NuGet compatibility. A developer uses it when porting a Xamarin.Android app to modern .NET.
- SDK-style project conversion and target framework monikers
- AndroidManifest.xml updates and NuGet dependency compatibility
Xamarin Android Migration by the numbers
- 22 all-time installs (skills.sh)
- Ranked #735 of 1,039 Mobile Development skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/davidortinau/maui-skills --skill xamarin-android-migrationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 22 |
|---|---|
| repo stars | ★ 163 |
| Last updated | July 6, 2026 |
| Repository | davidortinau/maui-skills ↗ |
What it does
Migrates Xamarin.Android native apps to .NET for Android, covering SDK-style project conversion, TFMs, MSBuild property changes, and manifest updates.
Files
Xamarin.Android → .NET for Android Migration
For SDK-style project templates, MSBuild property tables, ABI conversion, namespace mappings, and CLI commands, see references/android-migration-api.md.
⚠️ Field-tested advice: Android migration is significantly harder than iOS.
Expect more UI bugs, OEM-specific rendering differences, and issues not
reproducible on emulators. Test on physical devices.
Migration Workflow
1. Create new .NET for Android project (dotnet new android) 2. Copy code and resources into the new project 3. Update MSBuild properties (see references/android-migration-api.md) 4. Update AndroidManifest.xml — remove <uses-sdk>, use csproj properties 5. Delete Resource.designer.cs (regenerated automatically) 6. Update NuGet dependencies 7. Migrate binding libraries (if applicable) 8. Replace Xamarin.Essentials with <UseMauiEssentials>true</UseMauiEssentials> 9. Handle encoding changes 10. Delete bin//obj/, build, test on physical devices
Strategy: Create a new project and copy code into it — don't edit the existing project file in place.
Critical Gotchas
⚠️ Remove <uses-sdk> from AndroidManifest.xml
<!-- ❌ Xamarin-style — causes build warnings/errors -->
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" />
<!-- ✅ Use MSBuild properties instead -->
<TargetFramework>net8.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>⚠️ Delete Resource.designer.cs
This file is auto-generated. Leftover copies from Xamarin cause duplicate symbol errors. Delete it — it will be regenerated.
⚠️ No .dll.config or .exe.config Support
.dll.config and <dllmap> are not supported in .NET Core. If your app uses System.Configuration.ConfigurationManager, migrate to appsettings.json or platform preferences.
⚠️ Essentials: Override Permissions in Every Activity
// ❌ Forgetting this → permissions silently fail
// ✅ Required in EVERY Activity that uses Essentials
public override void OnRequestPermissionsResult(
int requestCode, string[] permissions, Permission[] grantResults)
{
Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}⚠️ AndroidManifest.xml Location Changed
AndroidManifest.xml is now in the project root (not Properties/). The SDK-style project finds it there by default.
Platform-Specific Pitfalls
| Pitfall | Impact | Mitigation |
|---|---|---|
| OEM rendering differences | UI bugs not visible on emulators | Test on physical devices from multiple vendors |
| Shadow rendering varies by OEM/API level | Inconsistent shadow appearance | Implement shadows in platform-specific handler code |
| Android Wear references | Not supported in .NET for Android | Remove Wear project references |
MAndroidI18n removed | Encoding errors at runtime | Replace with System.Text.Encoding.CodePages NuGet |
AotAssemblies deprecated | Build warnings | Use RunAOTCompilation instead |
jar2xml not supported | Binding library build failures | Use default class-parse parser |
DebugType=full not supported | Build errors | Use default portable |
NuGet Compatibility Note
Android is unique: packages targeting monoandroid still work on .NET for Android. No recompilation needed for most Android-specific packages. This is NOT true for iOS/Mac.
If no compatible version exists: 1. Recompile with .NET TFMs (if you own it) 2. Look for a preview .NET version 3. Replace with a .NET-compatible alternative
API Currency Warning
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
1. ☐ Created new .NET for Android project (dotnet new android) 2. ☐ Set TargetFramework to net8.0-android (or later) 3. ☐ Set SupportedOSPlatformVersion for minimum SDK 4. ☐ Converted AndroidSupportedAbis → RuntimeIdentifiers 5. ☐ Removed <uses-sdk> from AndroidManifest.xml 6. ☐ Copied source, resources, and project properties 7. ☐ Deleted Resource.designer.cs, bin/, obj/ 8. ☐ Updated NuGet dependencies 9. ☐ Added UseMauiEssentials + Platform.Init() if using Essentials 10. ☐ Overridden OnRequestPermissionsResult in every Activity 11. ☐ Replaced MAndroidI18n with System.Text.Encoding.CodePages 12. ☐ Verified AOT settings (RunAOTCompilation, not AotAssemblies) 13. ☐ Tested on physical Android device(s) from multiple vendors
Xamarin.Android Migration API Reference
SDK-Style Project File Template
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<OutputType>Exe</OutputType>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<ApplicationId>com.companyname.myapp</ApplicationId>
<ApplicationVersion>1</ApplicationVersion>
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
</PropertyGroup>
</Project>For library projects, omit <OutputType> or set it to Library.
Replacenet8.0-androidwithnet9.0-androidornet10.0-androidas needed.
---
MSBuild Property Changes
| Xamarin.Android Property | .NET for Android Equivalent | Notes |
|---|---|---|
AndroidSupportedAbis | RuntimeIdentifiers | See conversion table below |
AotAssemblies | RunAOTCompilation | Deprecated in .NET 7 |
AndroidClassParser | (default: `class-parse`) | jar2xml not supported |
AndroidDexTool | (default: `d8`) | dx not supported |
AndroidCodegenTarget | (default: `XAJavaInterop1`) | XamarinAndroid not supported |
AndroidManifest | (default: `AndroidManifest.xml` in root) | No longer in Properties/ |
DebugType | (default: `portable`) | full and pdbonly not supported |
MonoSymbolArchive | (removed) | mono-symbolicate not supported |
MAndroidI18n | System.Text.Encoding.CodePages NuGet | See encoding section |
AndroidUseIntermediateDesignerFile | (default: `True`) | |
AndroidBoundExceptionType | (default: `System`) | Aligns with .NET semantics |
ABI → RuntimeIdentifier Conversion
AndroidSupportedAbis | RuntimeIdentifiers |
|---|---|
armeabi-v7a | android-arm |
arm64-v8a | android-arm64 |
x86 | android-x86 |
x86_64 | android-x64 |
<!-- Xamarin.Android -->
<AndroidSupportedAbis>armeabi-v7a;arm64-v8a;x86;x86_64</AndroidSupportedAbis>
<!-- .NET for Android -->
<RuntimeIdentifiers>android-arm;android-arm64;android-x86;android-x64</RuntimeIdentifiers>---
AndroidManifest.xml Changes
Remove <uses-sdk> from AndroidManifest.xml. Use MSBuild properties instead:
<!-- BEFORE (Xamarin.Android AndroidManifest.xml) -->
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" />
<!-- AFTER (.NET for Android csproj) -->
<PropertyGroup>
<TargetFramework>net8.0-android</TargetFramework> <!-- targetSdkVersion -->
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion> <!-- minSdkVersion -->
</PropertyGroup>---
NuGet Dependency Compatibility
| Compatible Frameworks | Incompatible |
|---|---|
net8.0-android | |
monoandroid | |
monoandroidXX.X |
Android is unique: NuGet packages targeting monoandroid still work on .NET for Android..NET Standard libraries without incompatible dependencies are also compatible.
---
Binding Library Migration
For binding libraries, create a new project and copy bindings:
dotnet new android-bindinglib --output MyJavaBindingKey changes:
- Use SDK-style project format
@(InputJar),@(EmbeddedJar), or@(LibraryProjectZip)auto-enable
$(AllowUnsafeBlocks)
AndroidClassParserdefaults toclass-parse(nojar2xml)
---
Xamarin.Essentials Namespace Mapping
| 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 |
Essentials Initialization
using Microsoft.Maui.ApplicationModel;
[Activity(Label = "@string/app_name", MainLauncher = true)]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
Platform.Init(this, savedInstanceState);
}
}Override OnRequestPermissionsResult in every Activity:
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}---
Encoding Changes
Replace MAndroidI18n with the System.Text.Encoding.CodePages NuGet package:
// At app startup
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);---
AOT Compilation
Release builds default to profiled AOT:
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<RunAOTCompilation>true</RunAOTCompilation>
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
</PropertyGroup>To disable AOT, explicitly set both to false.
---
.NET CLI Commands
| Command | Description |
|---|---|
dotnet new android | Create new app |
dotnet new androidlib | Create class library |
dotnet new android-bindinglib | Create binding library |
dotnet new android-activity --name LoginActivity | Add activity |
dotnet new android-layout --name MyLayout --output Resources/layout | Add layout |
dotnet build | Build (produces .apk/.aab) |
dotnet run --project MyApp.csproj | Deploy and run on device/emulator |
dotnet publish | Publish for distribution |
Note:dotnet buildproduces a runnable.apk/.aabdirectly (unlike desktop
.NET wherepublishis typically needed). Inside IDEs, theInstalltarget handles
deployment instead.