MAUI Android Debug与Release运行时目录差异致反射问题
MAUI Android Release模式下无法获取程序集的解决方案
问题背景
在MAUI应用中需通过反射获取程序集,使用以下代码实现:
var runtimeAssemblies = new HashSet<string>(Directory.GetFiles(RuntimeEnvironment.GetRuntimeDirectory(), "*.dll"));
该代码在Windows平台的Debug/Release模式下均正常运行,但在Android模拟器的Release模式下失效。经排查:
- Debug模式下,
RuntimeEnvironment.GetRuntimeDirectory()返回/data/data/com.compagnyname.myprojectname/files/.__override__,路径下存在所需DLL文件 - Release模式下,返回路径为
/data/user/0/com.compagnyname.myprojectname,该路径下无任何DLL文件,推测程序集已被嵌入打包到APK中,导致MetadataLoadContext无法通过文件路径解析程序集
核心原因
MAUI Android在Release模式下默认启用程序集嵌入优化,所有程序集会被打包为APK的嵌入资源,而非解压到文件系统目录。Debug模式为了调试便利性,会将DLL文件解压到指定目录,因此可以通过目录扫描读取。
解决方案
方案1:通过应用已加载程序集集合获取(推荐)
直接从当前应用的已加载程序集中获取,无需依赖文件系统:
// 获取所有非动态加载的程序集 var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies() .Where(assembly => !assembly.IsDynamic) .ToList();
如果需要配合MetadataLoadContext使用(需读取程序集元数据),可以将程序集转为字节流加载:
var assemblyBytesList = new List<byte[]>(); foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.IsDynamic)) { using var memoryStream = new MemoryStream(); // 从嵌入资源中读取程序集字节流 var resourceStream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.dll"); resourceStream?.CopyTo(memoryStream); if (memoryStream.Length > 0) { assemblyBytesList.Add(memoryStream.ToArray()); } } // 自定义元数据加载上下文的程序集解析器 public class EmbeddedAssemblyResolver : MetadataAssemblyResolver { private readonly List<byte[]> _assemblyBytes; public EmbeddedAssemblyResolver(List<byte[]> assemblyBytes) { _assemblyBytes = assemblyBytes; } public override Assembly Resolve(MetadataLoadContext context, AssemblyName assemblyName) { // 匹配目标程序集并加载 var targetBytes = _assemblyBytes.FirstOrDefault(bytes => AssemblyName.GetAssemblyName(new MemoryStream(bytes)).Name == assemblyName.Name); return targetBytes != null ? context.LoadFromStream(new MemoryStream(targetBytes)) : null; } } // 使用MetadataLoadContext进行反射操作 using var metadataContext = new MetadataLoadContext(new EmbeddedAssemblyResolver(assemblyBytesList)); // 示例:加载指定类型 var targetType = metadataContext.LoadFromAssemblyName("YourAssemblyName").GetType("YourNamespace.YourType");
方案2:禁用Android程序集嵌入(不推荐)
如果必须通过文件路径读取DLL,可以修改项目配置禁用程序集嵌入,但会带来APK体积增大、启动速度变慢、安全性降低的问题。在项目的.csproj文件中添加:
<PropertyGroup Condition="'$(Configuration)' == 'Release' And '$(TargetFramework)' == 'net7.0-android'"> <!-- 禁用程序集嵌入到APK --> <AndroidEmbedAssembliesIntoApk>false</AndroidEmbedAssembliesIntoApk> </PropertyGroup>
内容的提问来源于stack exchange,提问作者TRex
相关产品推荐
相关产品推荐

