Xamarin.Android升级API27后Intent.CreateChooser失效求助
解决Xamarin.Android API27下Intent.CreateChooser失效的问题
我之前也碰到过一模一样的问题!API27之后Android对跨应用文件访问的限制更严格了,原来直接用Uri.FromFile()的写法已经行不通,必须换成FileProvider来生成安全的content://格式Uri才行,给你一步步拆解解决方案:
核心原因
从Android 7.0(API24)开始,系统就禁止应用间传递file://类型的Uri,API27更是严格执行了这个规则——之前API25可能因为兼容机制没触发问题,但升级后必须改用FileProvider来做跨应用文件共享。
步骤1:在AndroidManifest.xml中配置FileProvider
打开项目的AndroidManifest.xml,在<application>标签内添加以下配置,记得把com.yourpackage.name替换成你自己的应用包名:
<provider android:name="androidx.core.content.FileProvider" android:authorities="com.yourpackage.name.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
步骤2:创建file_paths.xml配置文件
在项目的Resources/xml目录下(没有xml文件夹就新建一个)创建file_paths.xml,内容如下(这里以共享外部存储根目录为例,你可以根据自己的文件存储位置调整):
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 共享外部存储根目录,如需指定子目录,把path的值改成对应路径即可 --> <external-path name="external_files" path="." /> <!-- 如果文件存在应用私有外部存储,用这个节点: <external-files-path name="app_private_files" path="." /> --> </paths>
步骤3:修改你的OpenFileServiceAndroid代码
把原来生成Uri的逻辑替换成FileProvider.GetUriForFile(),同时给Intent添加临时读取权限,完整代码示例如下:
public class OpenFileServiceAndroid : IOpenFileService { public async Task OpenFileService(string fileName) { string root = null; if (Android.OS.Environment.IsExternalStorageEmulated) { root = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath; } // 拼接完整文件路径 var targetFile = new Java.IO.File(root, fileName); if (!targetFile.Exists()) { // 可在此处处理文件不存在的异常情况 return; } // 使用FileProvider生成安全的content:// Uri var fileUri = FileProvider.GetUriForFile( Android.App.Application.Context, "com.yourpackage.name.fileprovider", // 必须和Manifest里的authorities完全一致 targetFile); // 创建打开文件的Intent var openIntent = new Intent(Intent.ActionView); openIntent.SetDataAndType(fileUri, GetFileMimeType(targetFile.AbsolutePath)); // 授予目标应用临时读取权限 openIntent.AddFlags(ActivityFlags.GrantReadUriPermission); // 创建选择器并启动 var chooser = Intent.CreateChooser(openIntent, "选择打开方式"); chooser.AddFlags(ActivityFlags.NewTask); // 确保非Activity环境下也能启动 Android.App.Application.Context.StartActivity(chooser); } // 辅助方法:根据文件路径获取MIME类型 private string GetFileMimeType(string filePath) { var defaultMimeType = "application/octet-stream"; var fileExtension = MimeTypeMap.GetFileExtensionFromUrl(Uri.FromFile(new Java.IO.File(filePath)).ToString()); if (!string.IsNullOrEmpty(fileExtension)) { defaultMimeType = MimeTypeMap.Singleton.GetMimeTypeFromExtension(fileExtension.ToLower()) ?? defaultMimeType; } return defaultMimeType; } }
关键注意点
- 务必保证
FileProvider.GetUriForFile()中的authorities和Manifest配置的完全一致,否则会抛出权限异常。 - 根据你的实际文件存储位置调整
file_paths.xml的节点,比如文件在应用内部存储就用<files-path>,具体可参考Android官方的FileProvider路径规则。 - 如果你需要写入权限,记得动态申请(你提到已授予存储权限,这部分应该没问题)。
内容的提问来源于stack exchange,提问作者C.C
相关产品推荐
相关产品推荐

