Blazor Hybrid安卓应用:授权外部应用编辑自建文件的问题
解决Blazor Hybrid安卓应用文件操作问题
问题背景
使用Visual Studio 2022+C#开发Blazor Hybrid安卓应用,需实现以下功能:
- 创建并存储含基础内容的文本文件(已实现)
- 通过
Launcher.Default.OpenAsync启动应用或Share.RequestAsync分享文件,允许用户选择应用修改该文本文件 - 允许用户将修改后的文件保存回应用初始存放位置
遇到的问题:
- 步骤2:
Launcher能正常打开文件,但Share功能打开空文件;改用原生Intent唤起应用选择后,打开的仍为空文件 - 步骤3:修改后保存回原位置时触发写入权限被拒提示,尝试配置FileProvider编译失败,设置UriPermission未解决
尝试的代码片段:
var fn = "nieuw.txt"; var docsDirectory = Android.App.Application.Context.GetExternalFilesDir(null); var file = Path.Combine($"{docsDirectory.AbsoluteFile.Path}", fn); var myUri = Android.Net.Uri.Parse(file); fileExists = File.Exists(file).ToString(); Android.Content.Intent viewDoc = new Android.Content.Intent(Android.Content.Intent.ActionView); viewDoc.SetDataAndType(myUri,"text/plain"); viewDoc.SetFlags(Android.Content.ActivityFlags.NewTask); viewDoc.AddFlags(Android.Content.ActivityFlags.GrantReadUriPermission); viewDoc.AddFlags(Android.Content.ActivityFlags.GrantWriteUriPermission); Android.App.Application.Context.StartActivity(viewDoc); message = myUri.ToString();
string popoverTitle = "Read text file"; var fn = "nieuw.txt"; var docsDirectory = Android.App.Application.Context.GetExternalFilesDir(null); var file = Path.Combine($"{docsDirectory.AbsoluteFile.Path}", fn); await Launcher.Default.OpenAsync(new OpenFileRequest(popoverTitle, new ReadOnlyFile(file)));
可行解决方法
一、正确配置FileProvider(核心解决权限与空文件问题)
添加FileProvider到AndroidManifest.xml
在<application>标签内插入以下配置:<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>创建文件路径配置文件
在Android项目的Resources目录下新建xml文件夹,创建file_paths.xml文件,内容如下:<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-files-path name="external_files" path="." /> </paths>该配置将应用的外部文件目录暴露给其他合法应用,避免直接使用文件路径导致的权限拦截。
修改Intent代码生成合法Content URI
替换原Uri生成逻辑,改用FileProvider生成Content URI:var fn = "nieuw.txt"; var docsDirectory = Android.App.Application.Context.GetExternalFilesDir(null); var file = new Java.IO.File(docsDirectory, fn); // 生成符合权限要求的Content URI var myUri = FileProvider.GetUriForFile(Android.App.Application.Context, $"{Android.App.Application.Context.PackageName}.fileprovider", file); var viewDoc = new Android.Content.Intent(Android.Content.Intent.ActionView); viewDoc.SetDataAndType(myUri, "text/plain"); // 设置正确的权限Flag viewDoc.SetFlags(Android.Content.ActivityFlags.NewTask | Android.Content.ActivityFlags.GrantReadUriPermission | Android.Content.ActivityFlags.GrantWriteUriPermission); // 给所有匹配的应用授予权限 var packageManager = Android.App.Application.Context.PackageManager; var resInfoList = packageManager.QueryIntentActivities(viewDoc, Android.Content.PM.PackageInfoFlags.MatchDefaultOnly); foreach (var resolveInfo in resInfoList) { var packageName = resolveInfo.ActivityInfo.PackageName; Android.App.Application.Context.GrantUriPermission(packageName, myUri, Android.Content.ActivityFlags.GrantReadUriPermission | Android.Content.ActivityFlags.GrantWriteUriPermission); } Android.App.Application.Context.StartActivity(viewDoc);
二、修复Launcher.Default.OpenAsync的写入权限
原代码使用ReadOnlyFile仅提供只读权限,需改用WriteableFile并确保权限配置正确:
string popoverTitle = "Edit text file"; var fn = "nieuw.txt"; var docsDirectory = Android.App.Application.Context.GetExternalFilesDir(null); var file = Path.Combine($"{docsDirectory.AbsoluteFile.Path}", fn); // 使用WriteableFile允许外部应用写入 await Launcher.Default.OpenAsync(new OpenFileRequest(popoverTitle, new WriteableFile(file)));
同时在AndroidManifest.xml中添加对应权限:
<!-- Android 12及以下 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- Android 13+ 无需WRITE权限,改用媒体读取权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
三、修复Share.RequestAsync的空文件问题
分享时同样需使用Content URI,而非直接文件路径:
var fn = "nieuw.txt"; var docsDirectory = Android.App.Application.Context.GetExternalFilesDir(null); var file = new Java.IO.File(docsDirectory, fn); var shareUri = FileProvider.GetUriForFile(Android.App.Application.Context, $"{Android.App.Application.Context.PackageName}.fileprovider", file); var shareRequest = new ShareFileRequest { Title = "Share text file", File = new ShareFile(shareUri.ToString(), "text/plain") }; await Share.RequestAsync(shareRequest);
四、验证文件保存回原位置的权限
应用的GetExternalFilesDir目录属于应用私有外部存储,应用本身默认拥有读写权限。若仍出现权限问题,检查:
- 文件路径是否确实在
GetExternalFilesDir返回的目录内 - 应用是否处于后台(部分安卓版本会限制后台应用的文件操作权限)
内容的提问来源于stack exchange,提问作者MvdK
相关产品推荐
相关产品推荐

