You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Maui在Android端日志写入文件时规避路径访问拒绝问题

.NET Maui Android 13 API33 真机NLog日志路径访问被拒绝问题解决

问题场景

在.NET Maui开发中,已实现Android设备NLog文件日志功能,但在Android 13 API33真机运行时触发System.AggregateException,提示路径/storage/self/primary/Documents/xxx/Logs/xxx.log访问被拒绝,Android 15 API35模拟器可正常运行。

解决方案

1. 替换硬编码路径为MAUI标准存储路径

不要直接写死公共存储路径,改用MAUI提供的FileSystem类获取符合Android版本规范的路径,优先选择应用专属存储路径(无需额外权限,更安全):

  • 获取应用私有文档目录:FileSystem.AppDataDirectory
  • 获取公共文档目录:FileSystem.Current.GetDirectoryPath(SpecialFolder.MyDocuments)

可以通过代码动态配置NLog路径,确保目录存在:

var logDir = Path.Combine(FileSystem.Current.GetDirectoryPath(SpecialFolder.MyDocuments), "HubSurveyor", "Logs");
Directory.CreateDirectory(logDir); // 提前创建目录避免权限或不存在问题

var fileTarget = new NLog.Targets.FileTarget("f")
{
    FileName = Path.Combine(logDir, "HubSurveyor.log"),
    ArchiveFileName = Path.Combine(logDir, "archive", "HubSurveyor-{#}.log"),
    Layout = "${longdate} ${threadid} ${uppercase:${level}} ${callsite} ${message} ${exception:format=Message,StackTrace,Data:maxInnerExceptionLevel=10}",
    ArchiveEvery = NLog.Targets.FileArchivePeriod.Day,
    ArchiveNumbering = NLog.Targets.ArchiveNumberingMode.Date,
    ArchiveDateFormat = "yyyyMMdd",
    MaxArchiveFiles = 21
};

var config = new NLog.Config.LoggingConfiguration();
config.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal, fileTarget);
config.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal, new NLog.Targets.DebuggerTarget("debugger")
{
    Layout = "${longdate} ${threadid} ${uppercase:${level}} ${callsite} ${message} ${exception:format=Message,StackTrace,Data:maxInnerExceptionLevel=10}"
});
NLog.LogManager.Configuration = config;

2. 适配Android 13公共存储权限(如需保留原路径)

如果必须使用公共Documents目录,需处理Android 13的权限限制:

  • 在Platforms/Android/AndroidManifest.xml中添加权限声明:
    <!-- Android 13+ 访问公共存储需要 -->
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
    <!-- 兼容Android 12及以下版本 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
    
  • 在应用启动时主动请求权限:
    var permissionStatus = await Permissions.RequestAsync<Permissions.StorageWrite>();
    if (permissionStatus != PermissionStatus.Granted)
    {
        // 提示用户开启权限,或降级使用应用专属存储
    }
    

注意:MANAGE_EXTERNAL_STORAGE权限需要用户手动在应用设置中开启,Google Play对使用该权限的应用审核严格,非必要不建议使用。

3. 利用NLog内部日志排查细节

你的配置已开启NLog内部日志,可查看/storage/self/primary/Documents/HubSurveyor/Logs/nlog-internal.log中的详细错误信息,确认是否存在目录未创建、权限以外的配置问题。

原NLog配置

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd C:\Users\Ian\.nuget\packages\nlog.schema\5.3.4\contentFiles\any\any\NLog.xsd"
      autoReload="true"
      throwExceptions="true"
      throwConfigExceptions="true"
      internalLogLevel="Error"
      internalLogFile="/storage/self/primary/Documents/HubSurveyor/Logs/nlog-internal.log">

    <targets>
        <!--
            Output to emulator and phone
        -->
        <target 
            xsi:type="File" 
            name="f" 
            fileName="/storage/self/primary/Documents/HubSurveyor/Logs/HubSurveyor.log" 
            layout="${longdate} ${threadid} ${uppercase:${level}} ${callsite} ${message} ${exception:format=Message,StackTrace,Data:maxInnerExceptionLevel=10}" 
            archiveEvery="Day"
            archiveFileName="/storage/self/primary/Documents/HubSurveyor/Logs/archive/HubSurveyor-{#}.log"
            archiveNumbering="Date"
            archiveDateFormat="yyyyMMdd"
            maxArchiveFiles="21"
        />
        <target xsi:type="Debugger" name="debugger" layout="${longdate} ${threadid} ${uppercase:${level}} ${callsite} ${message} ${exception:format=Message,StackTrace,Data:maxInnerExceptionLevel=10}"  />
    </targets>

    <rules>
        <logger name="*" minlevel="Trace" writeTo="f" />
        <logger name="*" minlevel="${when:when='${environment:MAUI_ENVIRONMENT}' == 'Development':inner=Trace:else=Off}" writeTo="debugger" />
    </rules>
</nlog>

内容的提问来源于stack exchange,提问作者Ian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 01:14:54