.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
相关产品推荐
相关产品推荐

