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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:31:08