diff --git a/CHANGELOG.md b/CHANGELOG.md
index b32853db5b..07abbbdb85 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,8 @@
 ### BREAKING CHANGES
 
 - This release adds support for .NET 10 and drops support for net8.0-android, net8.0-ios, net8.0-maccatalyst and net8.0-windows10.0.19041.0 ([#4461](https://github.com/getsentry/sentry-dotnet/pull/4461))
+- Added support for v3 of the Android AssemblyStore format that is used in .NET 10 and dropped support for v1 that was used in .NET 8 ([#4576](https://github.com/getsentry/sentry-dotnet/pull/4576))
+
 ## Unreleased
 
 ### Features
diff --git a/src/Sentry.Android.AssemblyReader/AndroidAssemblyReaderFactory.cs b/src/Sentry.Android.AssemblyReader/AndroidAssemblyReaderFactory.cs
index e111a46f71..2e4b8d03ab 100644
--- a/src/Sentry.Android.AssemblyReader/AndroidAssemblyReaderFactory.cs
+++ b/src/Sentry.Android.AssemblyReader/AndroidAssemblyReaderFactory.cs
@@ -1,4 +1,3 @@
-using Sentry.Android.AssemblyReader.V1;
 using Sentry.Android.AssemblyReader.V2;
 
 namespace Sentry.Android.AssemblyReader;
@@ -19,28 +18,13 @@ public static IAndroidAssemblyReader Open(string apkPath, IList<string> supporte
     {
         logger?.Invoke(DebugLoggerLevel.Debug, "Opening APK: {0}", apkPath);
 
-#if NET9_0
-        logger?.Invoke(DebugLoggerLevel.Debug, "Reading files using V2 APK layout.");
-        if (AndroidAssemblyStoreReaderV2.TryReadStore(apkPath, supportedAbis, logger, out var readerV2))
+        if (AndroidAssemblyStoreReader.TryReadStore(apkPath, supportedAbis, logger, out var readerV2))
         {
-            logger?.Invoke(DebugLoggerLevel.Debug, "APK uses AssemblyStore V2");
+            logger?.Invoke(DebugLoggerLevel.Debug, "APK uses AssemblyStore");
             return readerV2;
         }
 
         logger?.Invoke(DebugLoggerLevel.Debug, "APK doesn't use AssemblyStore");
-        return new AndroidAssemblyDirectoryReaderV2(apkPath, supportedAbis, logger);
-#else
-        logger?.Invoke(DebugLoggerLevel.Debug, "Reading files using V1 APK layout.");
-
-        var zipArchive = ZipFile.OpenRead(apkPath);
-        if (zipArchive.GetEntry("assemblies/assemblies.manifest") is not null)
-        {
-            logger?.Invoke(DebugLoggerLevel.Debug, "APK uses AssemblyStore V1");
-            return new AndroidAssemblyStoreReaderV1(zipArchive, supportedAbis, logger);
-        }
-
-        logger?.Invoke(DebugLoggerLevel.Debug, "APK doesn't use AssemblyStore");
-        return new AndroidAssemblyDirectoryReaderV1(zipArchive, supportedAbis, logger);
-#endif
+        return new AndroidAssemblyDirectoryReader(apkPath, supportedAbis, logger);
     }
 }
diff --git a/src/Sentry.Android.AssemblyReader/V2/AndroidAssemblyDirectoryReader.cs b/src/Sentry.Android.AssemblyReader/V2/AndroidAssemblyDirectoryReader.cs
new file mode 100644
index 0000000000..ca2b96d886
--- /dev/null
+++ b/src/Sentry.Android.AssemblyReader/V2/AndroidAssemblyDirectoryReader.cs
@@ -0,0 +1,301 @@
+namespace Sentry.Android.AssemblyReader.V2;
+
+// The "Old" app type - where each DLL is placed in the 'assemblies' directory as an individual file.
+internal sealed class AndroidAssemblyDirectoryReader : IAndroidAssemblyReader
+{
+    private DebugLogger? Logger { get; }
+    private HashSet<AndroidTargetArch> SupportedArchitectures { get; } = new();
+    private readonly ArchiveAssemblyHelper _archiveAssemblyHelper;
+
+    public AndroidAssemblyDirectoryReader(string apkPath, IList<string> supportedAbis, DebugLogger? logger)
+    {
+        Logger = logger;
+        foreach (var abi in supportedAbis)
+        {
+            logger?.Invoke(DebugLoggerLevel.Debug, "Adding {0} to supported architectures for Directory Reader", abi);
+            SupportedArchitectures.Add(abi.AbiToDeviceArchitecture());
+        }
+        _archiveAssemblyHelper = new ArchiveAssemblyHelper(apkPath, logger, supportedAbis);
+    }
+
+    public PEReader? TryReadAssembly(string name)
+    {
+        if (File.Exists(name))
+        {
+            // The assembly is already extracted to the file system.  Just read it.
+            var stream = File.OpenRead(name);
+            return new PEReader(stream);
+        }
+        Logger?.Invoke(DebugLoggerLevel.Debug, "File {0} does not exist in the APK", name);
+
+        foreach (var arch in SupportedArchitectures)
+        {
+            if (_archiveAssemblyHelper.ReadEntry($"assemblies/{name}", arch) is not { } memStream)
+            {
+                Logger?.Invoke(DebugLoggerLevel.Debug, "Couldn't find entry {0} in the APK for the {1} architecture", name, arch);
+                continue;
+            }
+
+            Logger?.Invoke(DebugLoggerLevel.Debug, "Resolved assembly {0} in the APK", name);
+            return ArchiveUtils.CreatePEReader(name, memStream, Logger);
+        }
+
+        Logger?.Invoke(DebugLoggerLevel.Debug, "Couldn't find assembly {0} in the APK", name);
+        return null;
+    }
+
+    public void Dispose()
+    {
+        // No-op
+    }
+
+    /*
+     * Adapted from https://github.com/dotnet/android/blob/6394773fad5108b0d7b4e6f087dc3e6ea997401a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ArchiveAssemblyHelper.cs
+     * Original code licensed under the MIT License (https://github.com/dotnet/android-tools/blob/ab2165daf27d4fcb29e88bc022e0ab0be33aff69/LICENSE)
+     */
+    internal class ArchiveAssemblyHelper
+    {
+        private static readonly ArrayPool<byte> Buffers = ArrayPool<byte>.Shared;
+
+        private readonly string _archivePath;
+        private readonly DebugLogger? _logger;
+        private readonly IList<string> _supportedAbis;
+
+        public ArchiveAssemblyHelper(string archivePath, DebugLogger? logger, IList<string> supportedAbis)
+        {
+            if (string.IsNullOrEmpty(archivePath))
+            {
+                throw new ArgumentException("must not be null or empty", nameof(archivePath));
+            }
+
+            _archivePath = archivePath;
+            _logger = logger;
+            _supportedAbis = supportedAbis;
+        }
+
+        public MemoryStream? ReadEntry(string path, AndroidTargetArch arch = AndroidTargetArch.None, bool uncompressIfNecessary = false)
+        {
+            var ret = ReadZipEntry(path, arch);
+            if (ret == null)
+            {
+                return null;
+            }
+
+            ret.Flush();
+            ret.Seek(0, SeekOrigin.Begin);
+            var (elfPayloadOffset, elfPayloadSize, error) = Utils.FindELFPayloadSectionOffsetAndSize(ret);
+
+            if (error != ELFPayloadError.None)
+            {
+                var message = error switch
+                {
+                    ELFPayloadError.NotELF => $"Entry '{path}' is not a valid ELF binary",
+                    ELFPayloadError.LoadFailed => $"Entry '{path}' could not be loaded",
+                    ELFPayloadError.NotSharedLibrary => $"Entry '{path}' is not a shared ELF library",
+                    ELFPayloadError.NotLittleEndian => $"Entry '{path}' is not a little-endian ELF image",
+                    ELFPayloadError.NoPayloadSection => $"Entry '{path}' does not contain the 'payload' section",
+                    _ => $"Unknown ELF payload section error for entry '{path}': {error}"
+                };
+                _logger?.Invoke(DebugLoggerLevel.Debug, message);
+            }
+            else
+            {
+                _logger?.Invoke(DebugLoggerLevel.Debug, $"Extracted content from ELF image '{path}'");
+            }
+
+            if (elfPayloadOffset == 0)
+            {
+                ret.Seek(0, SeekOrigin.Begin);
+                return ret;
+            }
+
+            // Make a copy of JUST the payload section, so that it contains only the data the tests expect and support
+            var payload = new MemoryStream();
+            var data = Buffers.Rent(16384);
+            var toRead = data.Length;
+            var nRead = 0;
+            var remaining = elfPayloadSize;
+
+            ret.Seek((long)elfPayloadOffset, SeekOrigin.Begin);
+            while (remaining > 0 && (nRead = ret.Read(data, 0, toRead)) > 0)
+            {
+                payload.Write(data, 0, nRead);
+                remaining -= (ulong)nRead;
+
+                if (remaining < (ulong)data.Length)
+                {
+                    // Make sure the last chunk doesn't gobble in more than we need
+                    toRead = (int)remaining;
+                }
+            }
+            Buffers.Return(data);
+
+            payload.Flush();
+            ret.Dispose();
+
+            payload.Seek(0, SeekOrigin.Begin);
+            return payload;
+        }
+
+        private MemoryStream? ReadZipEntry(string path, AndroidTargetArch arch)
+        {
+            var potentialEntries = TransformArchiveAssemblyPath(path, arch);
+            if (potentialEntries == null || potentialEntries.Count == 0)
+            {
+                _logger?.Invoke(DebugLoggerLevel.Debug, "No potential entries for path '{0}' with arch '{1}'", path, arch);
+                return null;
+            }
+
+            // First we check the base.apk
+            if (ReadEntryFromApk(_archivePath) is { } baseEntry)
+            {
+                _logger?.Invoke(DebugLoggerLevel.Debug, "Found entry '{0}' in base archive '{1}'", path, _archivePath);
+                return baseEntry;
+            }
+
+            // Otherwise check in the device specific APKs
+            foreach (var supportedAbi in _supportedAbis)
+            {
+                var splitFilePath = _archivePath.GetArchivePathForAbi(supportedAbi, _logger);
+                if (!File.Exists(splitFilePath))
+                {
+                    _logger?.Invoke(DebugLoggerLevel.Debug, "No split config detected at: '{0}'", splitFilePath);
+                }
+                else if (ReadEntryFromApk(splitFilePath) is { } splitEntry)
+                {
+                    return splitEntry;
+                }
+            }
+
+            // Finally admit defeat
+            return null;
+
+            MemoryStream? ReadEntryFromApk(string archivePath)
+            {
+                using var zip = ZipFile.OpenRead(archivePath);
+                foreach (var assemblyPath in potentialEntries)
+                {
+                    if (zip.GetEntry(assemblyPath) is not { } entry)
+                    {
+                        _logger?.Invoke(DebugLoggerLevel.Debug, "No entry found for path '{0}' in archive '{1}'", assemblyPath, archivePath);
+                        continue;
+                    }
+
+                    var ret = entry.Extract();
+                    ret.Flush();
+                    return ret;
+                }
+
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// Takes "old style" `assemblies/assembly.dll` path and returns (if possible) a set of paths that reflect the new
+        /// location of `lib/{ARCH}/assembly.dll.so`. A list is returned because, if `arch` is `None`, we'll return all
+        /// the possible architectural paths.
+        /// An exception is thrown if we cannot transform the path for some reason. It should **not** be handled.
+        /// </summary>
+        private static List<string>? TransformArchiveAssemblyPath(string path, AndroidTargetArch arch)
+        {
+            if (string.IsNullOrEmpty(path))
+            {
+                throw new ArgumentException(nameof(path), "must not be null or empty");
+            }
+
+            if (!path.StartsWith("assemblies/", StringComparison.Ordinal))
+            {
+                return [path];
+            }
+
+            var parts = path.Split('/');
+            if (parts.Length < 2)
+            {
+                throw new InvalidOperationException($"Path '{path}' must consist of at least two segments separated by `/`");
+            }
+
+            // We accept:
+            //   assemblies/assembly.dll
+            //   assemblies/{CULTURE}/assembly.dll
+            //   assemblies/{ABI}/assembly.dll
+            //   assemblies/{ABI}/{CULTURE}/assembly.dll
+            if (parts.Length > 4)
+            {
+                throw new InvalidOperationException($"Path '{path}' must not consist of more than 4 segments separated by `/`");
+            }
+
+            string? fileName = null;
+            string? culture = null;
+            string? abi = null;
+
+            switch (parts.Length)
+            {
+                // Full satellite assembly path, with abi
+                case 4:
+                    abi = parts[1];
+                    culture = parts[2];
+                    fileName = parts[3];
+                    break;
+
+                // Assembly path with abi or culture
+                case 3:
+                    // If the middle part isn't a valid abi, we treat it as a culture name
+                    if (MonoAndroidHelper.IsValidAbi(parts[1]))
+                    {
+                        abi = parts[1];
+                    }
+                    else
+                    {
+                        culture = parts[1];
+                    }
+                    fileName = parts[2];
+                    break;
+
+                // Assembly path without abi or culture
+                case 2:
+                    fileName = parts[1];
+                    break;
+            }
+
+            var fileTypeMarker = MonoAndroidHelper.MANGLED_ASSEMBLY_REGULAR_ASSEMBLY_MARKER;
+            var abis = new List<string>();
+            if (!string.IsNullOrEmpty(abi))
+            {
+                abis.Add(abi);
+            }
+            else if (arch == AndroidTargetArch.None)
+            {
+                foreach (AndroidTargetArch targetArch in MonoAndroidHelper.SupportedTargetArchitectures)
+                {
+                    abis.Add(MonoAndroidHelper.ArchToAbi(targetArch));
+                }
+            }
+            else
+            {
+                abis.Add(MonoAndroidHelper.ArchToAbi(arch));
+            }
+
+            if (!string.IsNullOrEmpty(culture))
+            {
+                // Android doesn't allow us to put satellite assemblies in lib/{CULTURE}/assembly.dll.so, we must instead
+                // mangle the name.
+                fileTypeMarker = MonoAndroidHelper.MANGLED_ASSEMBLY_SATELLITE_ASSEMBLY_MARKER;
+                fileName = $"{culture}{MonoAndroidHelper.SATELLITE_CULTURE_END_MARKER_CHAR}{fileName}";
+            }
+
+            var ret = new List<string>();
+            var newParts = new List<string> {
+                string.Empty, // ABI placeholder
+			    $"{fileTypeMarker}{fileName}.so",
+            };
+
+            foreach (var a in abis)
+            {
+                newParts[0] = a;
+                ret.Add(MonoAndroidHelper.MakeZipArchivePath("lib", newParts));
+            }
+
+            return ret;
+        }
+    }
+}
diff --git a/src/Sentry.Android.AssemblyReader/V2/AndroidAssemblyStoreReader.cs b/src/Sentry.Android.AssemblyReader/V2/AndroidAssemblyStoreReader.cs
new file mode 100644
index 0000000000..0e9c6586f4
--- /dev/null
+++ b/src/Sentry.Android.AssemblyReader/V2/AndroidAssemblyStoreReader.cs
@@ -0,0 +1,146 @@
+namespace Sentry.Android.AssemblyReader.V2;
+
+internal class AndroidAssemblyStoreReader : IAndroidAssemblyReader
+{
+    private readonly IList<AssemblyStoreExplorer> _explorers;
+    private readonly DebugLogger? _logger;
+
+    private AndroidAssemblyStoreReader(IList<AssemblyStoreExplorer> explorers, DebugLogger? logger)
+    {
+        _explorers = explorers;
+        _logger = logger;
+    }
+
+    public static bool TryReadStore(string inputFile, IList<string> supportedAbis, DebugLogger? logger, [NotNullWhen(true)] out AndroidAssemblyStoreReader? reader)
+    {
+        List<AssemblyStoreExplorer> supportedExplorers = [];
+
+        // First we check the base.apk for an assembly store
+        var (explorers, errorMessage) = AssemblyStoreExplorer.Open(inputFile, logger);
+        if (explorers is null)
+        {
+            logger?.Invoke(DebugLoggerLevel.Debug, "Unable to read store information for {0}: {1}", inputFile, errorMessage);
+
+            // Check for assembly stores in any device specific APKs
+            foreach (var supportedAbi in supportedAbis)
+            {
+                var splitFilePath = inputFile.GetArchivePathForAbi(supportedAbi, logger);
+                if (!File.Exists(splitFilePath))
+                {
+                    logger?.Invoke(DebugLoggerLevel.Debug, "No split config detected at: '{0}'", splitFilePath);
+                    continue;
+                }
+                (explorers, errorMessage) = AssemblyStoreExplorer.Open(splitFilePath, logger);
+                if (explorers is not null)
+                {
+                    supportedExplorers.AddRange(explorers); // If the error is null then this is not null
+                }
+                else
+                {
+                    logger?.Invoke(DebugLoggerLevel.Debug, "Unable to read store information for {0}: {1}", splitFilePath, errorMessage);
+                }
+            }
+        }
+        else
+        {
+            foreach (var explorer in explorers)
+            {
+                if (explorer.TargetArch is null)
+                {
+                    continue;
+                }
+
+                foreach (var supportedAbi in supportedAbis)
+                {
+                    if (supportedAbi.AbiToDeviceArchitecture() == explorer.TargetArch)
+                    {
+                        supportedExplorers.Add(explorer);
+                    }
+                }
+            }
+        }
+
+        if (supportedExplorers.Count == 0)
+        {
+            logger?.Invoke(DebugLoggerLevel.Debug, "Could not find V2 AssemblyStoreExplorer for the supported ABIs: {0}", string.Join(", ", supportedAbis));
+            reader = null;
+            return false;
+        }
+
+        reader = new AndroidAssemblyStoreReader(supportedExplorers, logger);
+        return true;
+    }
+
+    public PEReader? TryReadAssembly(string name)
+    {
+        var explorerAssembly = TryFindAssembly(name);
+        if (explorerAssembly is null)
+        {
+            _logger?.Invoke(DebugLoggerLevel.Debug, "Couldn't find assembly {0} in the APK AssemblyStore", name);
+            return null;
+        }
+
+        var (explorer, storeItem) = explorerAssembly;
+        _logger?.Invoke(DebugLoggerLevel.Debug, "Resolved assembly {0} in the APK {1} AssemblyStore", name, storeItem.TargetArch);
+
+        var stream = explorer.ReadImageData(storeItem, false);
+        if (stream is null)
+        {
+            _logger?.Invoke(DebugLoggerLevel.Debug, "Couldn't access assembly {0} image stream", name);
+            return null;
+        }
+
+        return ArchiveUtils.CreatePEReader(name, stream, _logger);
+    }
+
+    private ExplorerStoreItem? TryFindAssembly(string name)
+    {
+        if (FindBestAssembly(name, out var assembly))
+        {
+            return assembly;
+        }
+
+        // If the assembly name ends with .dll or .exe, try to find it without the extension.
+        if ((IsFileType(".dll") || IsFileType(".exe")) && FindBestAssembly(name[..^4], out assembly))
+        {
+            return assembly;
+        }
+
+        // Conversely, if there is no extension, try with the dll extension (sometimes required for class libraries).
+        // See: https://github.com/getsentry/sentry-dotnet/issues/4278#issuecomment-2986009125
+        if (!IsFileType(".dll") && !IsFileType(".exe") && FindBestAssembly(name + ".dll", out assembly))
+        {
+            return assembly;
+        }
+
+        return null;
+
+        bool IsFileType(string extension)
+        {
+            return name.EndsWith(extension, ignoreCase: true, CultureInfo.InvariantCulture);
+        }
+    }
+
+    private bool FindBestAssembly(string name, out ExplorerStoreItem? explorerAssembly)
+    {
+        foreach (var explorer in _explorers)
+        {
+            if (explorer.AssembliesByName?.TryGetValue(name, out var assembly) is true)
+            {
+                _logger?.Invoke(DebugLoggerLevel.Debug, "Found best assembly {0} in APK AssemblyStore for target arch {1}", name, explorer.TargetArch);
+                explorerAssembly = new(explorer, assembly);
+                return true;
+            }
+        }
+        _logger?.Invoke(DebugLoggerLevel.Warning, "No best assembly for {0} in APK AssemblyStore", name);
+        explorerAssembly = null;
+        return false;
+    }
+
+    private record ExplorerStoreItem(AssemblyStoreExplorer Explorer, AssemblyStoreItem StoreItem);
+
+    public void Dispose()
+    {
+        // No-op
+    }
+}
diff --git a/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreExplorer.cs b/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreExplorer.cs
index 0ab9c04e2e..5854d3c070 100644
--- a/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreExplorer.cs
+++ b/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreExplorer.cs
@@ -79,28 +79,19 @@ public static (IList<AssemblyStoreExplorer>? explorers, string? errorMessage) Op
     }
 
     private static (IList<AssemblyStoreExplorer>? explorers, string? errorMessage) OpenAab(FileInfo fi, DebugLogger? logger)
-        => OpenCommon(fi, [StoreReaderV2.AabPaths, StoreReader_V1.AabPaths], logger);
+        => OpenCommon(fi, StoreReader.AabPaths, logger);
 
     private static (IList<AssemblyStoreExplorer>? explorers, string? errorMessage) OpenAabBase(FileInfo fi, DebugLogger? logger)
-        => OpenCommon(fi, [StoreReaderV2.AabBasePaths, StoreReader_V1.AabBasePaths], logger);
+        => OpenCommon(fi, StoreReader.AabBasePaths, logger);
 
     private static (IList<AssemblyStoreExplorer>? explorers, string? errorMessage) OpenApk(FileInfo fi, DebugLogger? logger)
-        => OpenCommon(fi, [StoreReaderV2.ApkPaths, StoreReader_V1.ApkPaths], logger);
+        => OpenCommon(fi, StoreReader.ApkPaths, logger);
 
-    private static (IList<AssemblyStoreExplorer>? explorers, string? errorMessage) OpenCommon(FileInfo fi, List<IList<string>> pathLists, DebugLogger? logger)
+    private static (IList<AssemblyStoreExplorer>? explorers, string? errorMessage) OpenCommon(FileInfo fi, IList<string> paths, DebugLogger? logger)
     {
         using var zip = ZipFile.OpenRead(fi.FullName);
-
-        foreach (var paths in pathLists)
-        {
-            var (explorers, errorMessage, pathsFound) = TryLoad(fi, zip, paths, logger);
-            if (pathsFound)
-            {
-                return (explorers, errorMessage);
-            }
-        }
-
-        return (null, "Unable to find any blob entries");
+        var (explorers, errorMessage, pathsFound) = TryLoad(fi, zip, paths, logger);
+        return pathsFound ? (explorers, errorMessage) : (null, "Unable to find any blob entries");
     }
 
     private static (IList<AssemblyStoreExplorer>? explorers, string? errorMessage, bool pathsFound) TryLoad(FileInfo fi, ZipArchive zip, IList<string> paths, DebugLogger? logger)
diff --git a/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreItem.cs b/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreItem.cs
index a132f51ead..2ecde5fd48 100644
--- a/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreItem.cs
+++ b/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreItem.cs
@@ -1,5 +1,7 @@
 /*
  * Adapted from https://github.com/dotnet/android/blob/86260ed36dfe1a90c8ed6a2bb1cd0607d637f403/tools/assembly-store-reader-mk2/AssemblyStore/AssemblyStoreItem.cs
+ * Updated from https://github.com/dotnet/android/blob/64018e13e53cec7246e54866b520d3284de344e0/tools/assembly-store-reader-mk2/AssemblyStore/AssemblyStoreItem.cs
+ *     - Adding support for AssemblyStore v3 format that shipped in .NET 10 (https://github.com/dotnet/android/pull/10249)
  * Original code licensed under the MIT License (https://github.com/dotnet/android/blob/5ebcb1dd1503648391e3c0548200495f634d90c6/LICENSE.TXT)
  */
 
@@ -17,11 +19,13 @@ internal abstract class AssemblyStoreItem
     public uint ConfigOffset { get; protected set; }
     public uint ConfigSize { get; protected set; }
     public AndroidTargetArch TargetArch { get; protected set; }
+    public bool Ignore { get; }
 
-    protected AssemblyStoreItem(string name, bool is64Bit, List<ulong> hashes)
+    protected AssemblyStoreItem(string name, bool is64Bit, List<ulong> hashes, bool ignore)
     {
         Name = name;
         Hashes = hashes.AsReadOnly();
         Is64Bit = is64Bit;
+        Ignore = ignore;
     }
 }
diff --git a/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreReader.cs b/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreReader.cs
index 834cb2c36d..a3201754e1 100644
--- a/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreReader.cs
+++ b/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreReader.cs
@@ -32,23 +32,7 @@ protected AssemblyStoreReader(Stream store, string path, DebugLogger? logger)
 
     public static AssemblyStoreReader? Create(Stream store, string path, DebugLogger? logger)
     {
-        var reader = MakeReaderReady(new StoreReader_V1(store, path, logger));
-        if (reader != null)
-        {
-            return reader;
-        }
-
-        reader = MakeReaderReady(new StoreReaderV2(store, path, logger));
-        if (reader != null)
-        {
-            return reader;
-        }
-
-        return null;
-    }
-
-    private static AssemblyStoreReader? MakeReaderReady(AssemblyStoreReader reader)
-    {
+        var reader = new StoreReader(store, path, logger);
         if (!reader.IsSupported())
         {
             return null;
diff --git a/src/Sentry.Android.AssemblyReader/V2/StoreReader.Classes.cs b/src/Sentry.Android.AssemblyReader/V2/StoreReader.Classes.cs
new file mode 100644
index 0000000000..5ed713b6be
--- /dev/null
+++ b/src/Sentry.Android.AssemblyReader/V2/StoreReader.Classes.cs
@@ -0,0 +1,103 @@
+/*
+ * Adapted from https://github.com/dotnet/android/blob/5ebcb1dd1503648391e3c0548200495f634d90c6/tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.Classes.cs
+ * Updated from https://github.com/dotnet/android/blob/64018e13e53cec7246e54866b520d3284de344e0/tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.Classes.cs
+ *     - Adding support for AssemblyStore v3 format that shipped in .NET 10 (https://github.com/dotnet/android/pull/10249)
+ * Original code licensed under the MIT License (https://github.com/dotnet/android/blob/5ebcb1dd1503648391e3c0548200495f634d90c6/LICENSE.TXT)
+ */
+
+namespace Sentry.Android.AssemblyReader.V2;
+
+internal partial class StoreReader
+{
+    private sealed class Header
+    {
+        public const uint NativeSize = 5 * sizeof(uint);
+
+        public readonly uint magic;
+        public readonly uint version;
+        public readonly uint entry_count;
+        public readonly uint index_entry_count;
+
+        // Index size in bytes
+        public readonly uint index_size;
+
+        public Header(uint magic, uint version, uint entry_count, uint index_entry_count, uint index_size)
+        {
+            this.magic = magic;
+            this.version = version;
+            this.entry_count = entry_count;
+            this.index_entry_count = index_entry_count;
+            this.index_size = index_size;
+        }
+    }
+
+    private sealed class IndexEntry
+    {
+        public readonly ulong name_hash;
+        public readonly uint descriptor_index;
+        public readonly bool ignore;
+
+        public IndexEntry(ulong name_hash, uint descriptor_index, bool ignore)
+        {
+            this.name_hash = name_hash;
+            this.descriptor_index = descriptor_index;
+            this.ignore = ignore;
+        }
+    }
+
+    private sealed class EntryDescriptor
+    {
+        public uint mapping_index;
+
+        public uint data_offset;
+        public uint data_size;
+
+        public uint debug_data_offset;
+        public uint debug_data_size;
+
+        public uint config_data_offset;
+        public uint config_data_size;
+    }
+
+    private sealed class StoreItemV2 : AssemblyStoreItem
+    {
+        public StoreItemV2(AndroidTargetArch targetArch, string name, bool is64Bit, List<IndexEntry> indexEntries,
+            EntryDescriptor descriptor, bool ignore)
+            : base(name, is64Bit, IndexToHashes(indexEntries), ignore)
+        {
+            DataOffset = descriptor.data_offset;
+            DataSize = descriptor.data_size;
+            DebugOffset = descriptor.debug_data_offset;
+            DebugSize = descriptor.debug_data_size;
+            ConfigOffset = descriptor.config_data_offset;
+            ConfigSize = descriptor.config_data_size;
+            TargetArch = targetArch;
+        }
+
+        private static List<ulong> IndexToHashes(List<IndexEntry> indexEntries)
+        {
+            var ret = new List<ulong>();
+            foreach (var ie in indexEntries)
+            {
+                ret.Add(ie.name_hash);
+            }
+
+            return ret;
+        }
+    }
+
+    private sealed class TemporaryItem
+    {
+        public readonly string Name;
+        public readonly List<IndexEntry> IndexEntries = new List<IndexEntry>();
+        public readonly EntryDescriptor Descriptor;
+        public readonly bool Ignored;
+
+        public TemporaryItem(string name, EntryDescriptor descriptor, bool ignored)
+        {
+            Name = name;
+            Descriptor = descriptor;
+            Ignored = ignored;
+        }
+    }
+}
diff --git a/src/Sentry.Android.AssemblyReader/V2/StoreReader.cs b/src/Sentry.Android.AssemblyReader/V2/StoreReader.cs
new file mode 100644
index 0000000000..5220bf7dc7
--- /dev/null
+++ b/src/Sentry.Android.AssemblyReader/V2/StoreReader.cs
@@ -0,0 +1,253 @@
+/*
+ * Adapted from https://github.com/dotnet/android/blob/5ebcb1dd1503648391e3c0548200495f634d90c6/tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.cs
+ * Updated from https://github.com/dotnet/android/blob/64018e13e53cec7246e54866b520d3284de344e0/tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.cs
+ *     - Adding support for AssemblyStore v3 format that shipped in .NET 10 (https://github.com/dotnet/android/pull/10249)
+ * Original code licensed under the MIT License (https://github.com/dotnet/android/blob/5ebcb1dd1503648391e3c0548200495f634d90c6/LICENSE.TXT)
+ */
+
+namespace Sentry.Android.AssemblyReader.V2;
+
+internal partial class StoreReader : AssemblyStoreReader
+{
+    // Bit 31 is set for 64-bit platforms, cleared for the 32-bit ones
+#if NET9_0
+    private const uint ASSEMBLY_STORE_FORMAT_VERSION_64BIT = 0x80000002; // Must match the ASSEMBLY_STORE_FORMAT_VERSION native constant
+    private const uint ASSEMBLY_STORE_FORMAT_VERSION_32BIT = 0x00000002;
+#else
+    private const uint ASSEMBLY_STORE_FORMAT_VERSION_64BIT = 0x80000003; // Must match the ASSEMBLY_STORE_FORMAT_VERSION native constant
+    private const uint ASSEMBLY_STORE_FORMAT_VERSION_32BIT = 0x00000003;
+#endif
+    private const uint ASSEMBLY_STORE_FORMAT_VERSION_MASK = 0xF0000000;
+    private const uint ASSEMBLY_STORE_ABI_AARCH64 = 0x00010000;
+    private const uint ASSEMBLY_STORE_ABI_ARM = 0x00020000;
+    private const uint ASSEMBLY_STORE_ABI_X64 = 0x00030000;
+    private const uint ASSEMBLY_STORE_ABI_X86 = 0x00040000;
+    private const uint ASSEMBLY_STORE_ABI_MASK = 0x00FF0000;
+
+    public override string Description => "Assembly store v2";
+    public override bool NeedsExtensionInName => true;
+
+    public static IList<string> ApkPaths { get; }
+    public static IList<string> AabPaths { get; }
+    public static IList<string> AabBasePaths { get; }
+
+    private readonly HashSet<uint> supportedVersions;
+    private Header? header;
+    private ulong elfOffset = 0;
+
+    static StoreReader()
+    {
+        var paths = new List<string> {
+            GetArchPath (AndroidTargetArch.Arm64),
+            GetArchPath (AndroidTargetArch.Arm),
+            GetArchPath (AndroidTargetArch.X86_64),
+            GetArchPath (AndroidTargetArch.X86),
+        };
+        ApkPaths = paths.AsReadOnly();
+        AabBasePaths = ApkPaths;
+
+        const string AabBaseDir = "base";
+        paths = new List<string> {
+            GetArchPath (AndroidTargetArch.Arm64, AabBaseDir),
+            GetArchPath (AndroidTargetArch.Arm, AabBaseDir),
+            GetArchPath (AndroidTargetArch.X86_64, AabBaseDir),
+            GetArchPath (AndroidTargetArch.X86, AabBaseDir),
+        };
+        AabPaths = paths.AsReadOnly();
+
+        string GetArchPath(AndroidTargetArch arch, string? root = null)
+        {
+            const string LibDirName = "lib";
+
+            string abi = MonoAndroidHelper.ArchToAbi(arch);
+            var parts = new List<string>();
+            if (!string.IsNullOrEmpty(root))
+            {
+                parts.Add(LibDirName);
+            }
+            else
+            {
+                root = LibDirName;
+            }
+            parts.Add(abi);
+            parts.Add(GetBlobName(abi));
+
+            return MonoAndroidHelper.MakeZipArchivePath(root, parts);
+        }
+    }
+
+    public StoreReader(Stream store, string path, DebugLogger? logger)
+        : base(store, path, logger)
+    {
+        supportedVersions = new HashSet<uint> {
+            ASSEMBLY_STORE_FORMAT_VERSION_64BIT | ASSEMBLY_STORE_ABI_AARCH64,
+            ASSEMBLY_STORE_FORMAT_VERSION_64BIT | ASSEMBLY_STORE_ABI_X64,
+            ASSEMBLY_STORE_FORMAT_VERSION_32BIT | ASSEMBLY_STORE_ABI_ARM,
+            ASSEMBLY_STORE_FORMAT_VERSION_32BIT | ASSEMBLY_STORE_ABI_X86,
+        };
+    }
+
+    private static string GetBlobName(string abi) => $"libassemblies.{abi}.blob.so";
+
+    protected override ulong GetStoreStartDataOffset() => elfOffset;
+
+    protected override bool IsSupported()
+    {
+        StoreStream.Seek(0, SeekOrigin.Begin);
+        using var reader = CreateReader();
+
+        uint magic = reader.ReadUInt32();
+        if (magic == Utils.ELFMagic)
+        {
+            ELFPayloadError error;
+            (elfOffset, _, error) = Utils.FindELFPayloadSectionOffsetAndSize(StoreStream);
+
+            if (error != ELFPayloadError.None)
+            {
+                string message = error switch
+                {
+                    ELFPayloadError.NotELF => $"Store '{StorePath}' is not a valid ELF binary",
+                    ELFPayloadError.LoadFailed => $"Store '{StorePath}' could not be loaded",
+                    ELFPayloadError.NotSharedLibrary => $"Store '{StorePath}' is not a shared ELF library",
+                    ELFPayloadError.NotLittleEndian => $"Store '{StorePath}' is not a little-endian ELF image",
+                    ELFPayloadError.NoPayloadSection => $"Store '{StorePath}' does not contain the 'payload' section",
+                    _ => $"Unknown ELF payload section error for store '{StorePath}': {error}"
+                };
+                Logger?.Invoke(DebugLoggerLevel.Debug, message);
+                // Was originally:
+                // ```
+                // } else if (elfOffset >= 0) {
+                // ```
+                // However since elfOffset is an ulong, it will never be less than 0
+            }
+            else
+            {
+                StoreStream.Seek((long)elfOffset, SeekOrigin.Begin);
+                magic = reader.ReadUInt32();
+            }
+        }
+
+        if (magic != Utils.AssemblyStoreMagic)
+        {
+            Logger?.Invoke(DebugLoggerLevel.Debug, "Store '{0}' has invalid header magic number.", StorePath);
+            return false;
+        }
+
+        uint version = reader.ReadUInt32();
+        if (!supportedVersions.Contains(version))
+        {
+            Logger?.Invoke(DebugLoggerLevel.Debug, "Store '{0}' has unsupported version 0x{1:x}", StorePath, version);
+            return false;
+        }
+
+        uint entry_count = reader.ReadUInt32();
+        uint index_entry_count = reader.ReadUInt32();
+        uint index_size = reader.ReadUInt32();
+
+        header = new Header(magic, version, entry_count, index_entry_count, index_size);
+        return true;
+    }
+
+    protected override void Prepare()
+    {
+        if (header == null)
+        {
+            throw new InvalidOperationException("Internal error: header not set, was IsSupported() called?");
+        }
+
+        TargetArch = (header.version & ASSEMBLY_STORE_ABI_MASK) switch
+        {
+            ASSEMBLY_STORE_ABI_AARCH64 => AndroidTargetArch.Arm64,
+            ASSEMBLY_STORE_ABI_ARM => AndroidTargetArch.Arm,
+            ASSEMBLY_STORE_ABI_X64 => AndroidTargetArch.X86_64,
+            ASSEMBLY_STORE_ABI_X86 => AndroidTargetArch.X86,
+            _ => throw new NotSupportedException($"Unsupported ABI in store version: 0x{header.version:x}")
+        };
+
+        Is64Bit = (header.version & ASSEMBLY_STORE_FORMAT_VERSION_MASK) != 0;
+        AssemblyCount = header.entry_count;
+        IndexEntryCount = header.index_entry_count;
+
+        StoreStream.Seek((long)elfOffset + Header.NativeSize, SeekOrigin.Begin);
+        using var reader = CreateReader();
+
+        var index = new List<IndexEntry>();
+        for (uint i = 0; i < header.index_entry_count; i++)
+        {
+            ulong name_hash;
+            if (Is64Bit)
+            {
+                name_hash = reader.ReadUInt64();
+            }
+            else
+            {
+                name_hash = (ulong)reader.ReadUInt32();
+            }
+
+            uint descriptor_index = reader.ReadUInt32();
+#if NET10_0_OR_GREATER
+            bool ignore = reader.ReadByte () != 0;
+#else
+            bool ignore = false;
+#endif
+            index.Add(new IndexEntry(name_hash, descriptor_index, ignore));
+        }
+
+        var descriptors = new List<EntryDescriptor>();
+        for (uint i = 0; i < header.entry_count; i++)
+        {
+            uint mapping_index = reader.ReadUInt32();
+            uint data_offset = reader.ReadUInt32();
+            uint data_size = reader.ReadUInt32();
+            uint debug_data_offset = reader.ReadUInt32();
+            uint debug_data_size = reader.ReadUInt32();
+            uint config_data_offset = reader.ReadUInt32();
+            uint config_data_size = reader.ReadUInt32();
+
+            var desc = new EntryDescriptor
+            {
+                mapping_index = mapping_index,
+                data_offset = data_offset,
+                data_size = data_size,
+                debug_data_offset = debug_data_offset,
+                debug_data_size = debug_data_size,
+                config_data_offset = config_data_offset,
+                config_data_size = config_data_size,
+            };
+            descriptors.Add(desc);
+        }
+
+        var names = new List<string>();
+        for (uint i = 0; i < header.entry_count; i++)
+        {
+            uint name_length = reader.ReadUInt32();
+            byte[] name_bytes = reader.ReadBytes((int)name_length);
+            names.Add(Encoding.UTF8.GetString(name_bytes));
+        }
+
+        var tempItems = new Dictionary<uint, TemporaryItem>();
+        foreach (IndexEntry ie in index)
+        {
+            if (!tempItems.TryGetValue(ie.descriptor_index, out TemporaryItem? item))
+            {
+                item = new TemporaryItem(names[(int)ie.descriptor_index], descriptors[(int)ie.descriptor_index], ie.ignore);
+                tempItems.Add(ie.descriptor_index, item);
+            }
+            item.IndexEntries.Add(ie);
+        }
+
+        if (tempItems.Count != descriptors.Count)
+        {
+            throw new InvalidOperationException($"Assembly store '{StorePath}' index is corrupted.");
+        }
+
+        var storeItems = new List<AssemblyStoreItem>();
+        foreach (var kvp in tempItems)
+        {
+            TemporaryItem ti = kvp.Value;
+            var item = new StoreItemV2(TargetArch, ti.Name, Is64Bit, ti.IndexEntries, ti.Descriptor, ti.Ignored);
+            storeItems.Add(item);
+        }
+        Assemblies = storeItems.AsReadOnly();
+    }
+}
diff --git a/test/AndroidTestApp/AndroidTestApp.csproj b/test/AndroidTestApp/AndroidTestApp.csproj
index 261fc05b24..cefce5290f 100644
--- a/test/AndroidTestApp/AndroidTestApp.csproj
+++ b/test/AndroidTestApp/AndroidTestApp.csproj
@@ -2,6 +2,7 @@
   <PropertyGroup>
     <TargetFrameworks>net10.0-android;net9.0-android</TargetFrameworks>
     <IsAotCompatible>false</IsAotCompatible>
+    <UseNativeAot>false</UseNativeAot>
     <SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
     <OutputType>Exe</OutputType>
     <Nullable>enable</Nullable>
@@ -9,5 +10,6 @@
     <ApplicationId>com.companyname.AndroidTestApp</ApplicationId>
     <ApplicationVersion>1</ApplicationVersion>
     <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
+    <RuntimeIdentifier>android-x64</RuntimeIdentifier>
   </PropertyGroup>
 </Project>
diff --git a/test/Sentry.Android.AssemblyReader.Tests/AndroidAssemblyReaderTests.cs b/test/Sentry.Android.AssemblyReader.Tests/AndroidAssemblyReaderTests.cs
index f0d1a50c64..60b56ffc54 100644
--- a/test/Sentry.Android.AssemblyReader.Tests/AndroidAssemblyReaderTests.cs
+++ b/test/Sentry.Android.AssemblyReader.Tests/AndroidAssemblyReaderTests.cs
@@ -1,4 +1,3 @@
-using Sentry.Android.AssemblyReader.V1;
 using Sentry.Android.AssemblyReader.V2;
 
 namespace Sentry.Android.AssemblyReader.Tests;
@@ -6,13 +5,10 @@ namespace Sentry.Android.AssemblyReader.Tests;
 public class AndroidAssemblyReaderTests
 {
     private readonly ITestOutputHelper _output;
-
 #if NET10_0
     private static string TargetFramework => "net10.0";
 #elif NET9_0
     private static string TargetFramework => "net9.0";
-#elif NET8_0
-    private static string TargetFramework => "net8.0";
 #else
     // Adding a new TFM to the project? Include it above
 #error "Target Framework not yet supported for AndroidAssemblyReader"
@@ -54,11 +50,11 @@ public void CreatesCorrectStoreReader()
         using var sut = GetSut(isAot: false, isAssemblyStore: true, isCompressed: true);
         switch (TargetFramework)
         {
-            case "net9.0":
-                Assert.IsType<AndroidAssemblyStoreReaderV2>(sut);
+            case "net10.0":
+                Assert.IsType<AndroidAssemblyStoreReader>(sut);
                 break;
-            case "net8.0":
-                Assert.IsType<AndroidAssemblyStoreReaderV1>(sut);
+            case "net9.0":
+                Assert.IsType<AndroidAssemblyStoreReader>(sut);
                 break;
             default:
                 throw new NotSupportedException($"Unsupported target framework: {TargetFramework}");
@@ -74,11 +70,11 @@ public void CreatesCorrectArchiveReader()
         using var sut = GetSut(isAot: false, isAssemblyStore: false, isCompressed: true);
         switch (TargetFramework)
         {
-            case "net9.0":
-                Assert.IsType<AndroidAssemblyDirectoryReaderV2>(sut);
+            case "net10.0":
+                Assert.IsType<AndroidAssemblyDirectoryReader>(sut);
                 break;
-            case "net8.0":
-                Assert.IsType<AndroidAssemblyDirectoryReaderV1>(sut);
+            case "net9.0":
+                Assert.IsType<AndroidAssemblyDirectoryReader>(sut);
                 break;
             default:
                 throw new NotSupportedException($"Unsupported target framework: {TargetFramework}");
@@ -95,11 +91,7 @@ public void ReturnsNullIfAssemblyDoesntExist(bool isAssemblyStore)
     }
 
     public static IEnumerable<object[]> ReadsAssemblyPermutations =>
-#if NET8_0
-        from isAot in new[] { false }
-#else
         from isAot in new[] { true, false }
-#endif
         from isStore in new[] { true, false }
         from isCompressed in new[] { true, false }
         from assemblyName in new[] { "Mono.Android.dll", "System.Private.CoreLib.dll" }
diff --git a/test/Sentry.Android.AssemblyReader.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt b/test/Sentry.Android.AssemblyReader.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt
new file mode 100644
index 0000000000..67bbca78b3
--- /dev/null
+++ b/test/Sentry.Android.AssemblyReader.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt
@@ -0,0 +1,20 @@
+﻿namespace Sentry.Android.AssemblyReader
+{
+    public static class AndroidAssemblyReaderFactory
+    {
+        public static Sentry.Android.AssemblyReader.IAndroidAssemblyReader Open(string apkPath, System.Collections.Generic.IList<string> supportedAbis, Sentry.Android.AssemblyReader.DebugLogger? logger = null) { }
+    }
+    public delegate void DebugLogger(Sentry.Android.AssemblyReader.DebugLoggerLevel level, string message, params object?[] args);
+    public enum DebugLoggerLevel : short
+    {
+        Debug = 0,
+        Info = 1,
+        Warning = 2,
+        Error = 3,
+        Fatal = 4,
+    }
+    public interface IAndroidAssemblyReader : System.IDisposable
+    {
+        System.Reflection.PortableExecutable.PEReader? TryReadAssembly(string name);
+    }
+}
\ No newline at end of file
diff --git a/test/Sentry.Android.AssemblyReader.Tests/Sentry.Android.AssemblyReader.Tests.csproj b/test/Sentry.Android.AssemblyReader.Tests/Sentry.Android.AssemblyReader.Tests.csproj
index 8d50df6bec..a892724b49 100644
--- a/test/Sentry.Android.AssemblyReader.Tests/Sentry.Android.AssemblyReader.Tests.csproj
+++ b/test/Sentry.Android.AssemblyReader.Tests/Sentry.Android.AssemblyReader.Tests.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks>net9.0</TargetFrameworks>
+    <TargetFrameworks>$(LatestTfm);$(PreviousTfm)</TargetFrameworks>
     <!-- IMPORTANT: We must test with new TFMs as the store format changes with new versions of .NET -->
     <TargetFrameworks Condition="'$(NO_ANDROID)' == ''">$(TargetFrameworks);$(LatestAndroidTfm);$(PreviousAndroidTfm)</TargetFrameworks>
     <Nullable>enable</Nullable>
@@ -20,7 +20,7 @@
   <Target Name="EnsureAndroidTestAppRestored"
           Condition="!Exists('$(MSBuildProjectDirectory)\..\AndroidTestApp\obj\project.assets.json')">
     <Message Importance="high" Text="Restoring AndroidTestApp via MSBuild task..." />
-    <Exec Command="dotnet restore ../AndroidTestApp/AndroidTestApp.csproj --nologo" />
+    <Exec Command="dotnet restore ../AndroidTestApp/AndroidTestApp.csproj -f --nologo" />
   </Target>
 
   <!-- Restore exactly once: https://learn.microsoft.com/en-gb/visualstudio/msbuild/run-target-exactly-once -->
@@ -42,11 +42,10 @@
       <_TestAPK Include="2" Properties="_Aot=False;_Store=False;_Compressed=True" />
       <_TestAPK Include="3" Properties="_Aot=False;_Store=True;_Compressed=False" />
       <_TestAPK Include="4" Properties="_Aot=False;_Store=True;_Compressed=True" />
-
-      <_TestAPK Include="5" Condition="!$(TargetFramework.StartsWith('net8'))" Properties="_Aot=True;_Store=False;_Compressed=False" />
-      <_TestAPK Include="6" Condition="!$(TargetFramework.StartsWith('net8'))" Properties="_Aot=True;_Store=False;_Compressed=True" />
-      <_TestAPK Include="7" Condition="!$(TargetFramework.StartsWith('net8'))" Properties="_Aot=True;_Store=True;_Compressed=False" />
-      <_TestAPK Include="8" Condition="!$(TargetFramework.StartsWith('net8'))" Properties="_Aot=True;_Store=True;_Compressed=True" />
+      <_TestAPK Include="5" Properties="_Aot=True;_Store=False;_Compressed=False" />
+      <_TestAPK Include="6" Properties="_Aot=True;_Store=False;_Compressed=True" />
+      <_TestAPK Include="7" Properties="_Aot=True;_Store=True;_Compressed=False" />
+      <_TestAPK Include="8" Properties="_Aot=True;_Store=True;_Compressed=True" />
     </ItemGroup>
 
     <MSBuild Projects="$(MSBuildProjectFile)" Targets="_BuildTestAPK" Properties="%(_TestAPK.Properties)" BuildInParallel="false" />
@@ -57,7 +56,8 @@
       <SourceAPK>..\AndroidTestApp\bin\$(TargetFramework)\$(_ConfigString)\com.companyname.AndroidTestApp-Signed.apk</SourceAPK>
       <DestinationAPK>TestAPKs\$(TargetFramework)-$(_ConfigString).apk</DestinationAPK>
     </PropertyGroup>
-    <MSBuild Projects="..\AndroidTestApp\AndroidTestApp.csproj" Targets="Build" Properties="Configuration=Release;PublishAot=$(_Aot);_IsPublishing=true;RuntimeIdentifier=android-x64;AndroidUseAssemblyStore=$(_Store);AndroidEnableAssemblyCompression=$(_Compressed);OutDir=bin\$(TargetFramework)\$(_ConfigString)\" Condition="!Exists('$(DestinationAPK)')" />
+    <!-- Note we use RunAOTCompilation rather than PublishAot here - full NativeAOT compilation on Android is still experimental  -->
+    <MSBuild Projects="..\AndroidTestApp\AndroidTestApp.csproj" Targets="Build" Properties="Configuration=Release;RunAOTCompilation=$(_Aot);UseNativeAot=false;_IsPublishing=true;AndroidUseAssemblyStore=$(_Store);AndroidEnableAssemblyCompression=$(_Compressed);OutDir=bin\$(TargetFramework)\$(_ConfigString)\" Condition="!Exists('$(DestinationAPK)')" />
 
     <Message Text="Copying APK from $(SourceAPK) to $(DestinationAPK)" Importance="high" />
     <Copy SourceFiles="$(SourceAPK)" DestinationFiles="$(DestinationAPK)" Condition="!Exists('$(DestinationAPK)')" />
