我正在制作Xamarin.Forms应用程序,无法在Android的默认应用程序中打开文件。我在本地数据库中具有字节形式的文件数据,并且我希望能够在默认应用程序中查看其类型。我假设首先需要将文件写入文件系统,然后再打开它。据我所知打开文件很简单:
Intent intent = new Intent(Intent.ActionView);
intent.SetDataAndType(uri, mimeType);
intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask);
CrossCurrentActivity.Current.Activity.StartActivity(intent);
我可以轻松从扩展名中获取mime类型。但是,创建文件并获取它的uri很难。到目前为止,我所做的所有尝试都抛出异常,或者目标应用程序说它无法访问资源。以下代码不会引发异常,但会失败,因为目标应用无法访问该文件:
// create directory
var activity = CrossCurrentActivity.Current.Activity;
var previewFolder = new File(activity.GetExternalFilesDir(Environment.DirectoryDownloads), "previews");
previewFolder.Mkdirs();
// create file
var file = File.CreateTempFile(fileName, null, _previewFolder);
file.SetReadable(true);
var stream = new FileOutputStream(file);
await stream.WriteAsync(content, 0, content.Length);
stream.Close();
// get uri
var uri = FileProvider.GetUriForFile(activity, "my.app.id.fileprovider", file);
AndroidManifest.xml中的fileprovider部分如下所示:
<provider android:name="android.support.v4.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"></meta-data>
</provider>
和file_paths.xml看起来像(我真的不明白该如何配置):
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<root-path name="root" path="." />
<external-files-path name="my_images" path="Pictures" />
<external-files-path name="my_movies" path="Movies" />
</paths>
我想念什么或做错什么了?
编辑:
主要问题似乎是:
intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask);
需要为:
intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask | ActivityFlags.GrantReadUriPermission);
答案 0 :(得分:1)
按照docs:
FileProvider只能为其中的文件生成内容URI 您预先指定的目录。要指定目录, 使用以下元素的子元素指定XML的存储区域和路径 元素。例如,以下路径元素告诉 您打算请求图像的内容URI的FileProvider / 私有文件区域的子目录。
您的情况是:
<files-path name="my_images" path="Pictures" />
因此,您需要创建一个路径:Pictures
,第三方应用程序将通过其别名my_images
看到它。不要像以前那样使用临时文件
var file = File.CreateTempFile(fileName, null, _previewFolder);
请使用内部目录:
File root = Context.getFilesDir();
File imagesRoot = new File(root, "Pictures");
File imageFile = new File(imagesRoot, "myFile.png");
还可以通过执行以下步骤获得大权限:
授予对从返回的内容URI的访问权限 getUriForFile(),请执行以下操作之一:调用方法 的Context.grantUriPermission(package,Uri,mode_flags) content:// Uri,使用所需的模式标志。这授予临时 内容URI对指定包的访问权限, 根据mode_flags参数的值,您可以 设置为FLAG_GRANT_READ_URI_PERMISSION,FLAG_GRANT_WRITE_URI_PERMISSION 或两者。该权限一直有效,直到您通过以下方式撤消它为止 调用revokeUriPermission()或直到设备重启。放在 通过调用setData()获得Intent中的内容URI。接下来,调用方法 Intent.setFlags()与FLAG_GRANT_READ_URI_PERMISSION或 FLAG_GRANT_WRITE_URI_PERMISSION或两者兼有。最后,将Intent发送给 另一个应用。通常,您可以通过调用setResult()来执行此操作。 在Intent中授予的权限在堆栈中保持有效 接收活动处于活动状态。堆栈完成后, 权限会自动删除。授予一个的权限 客户端应用中的活动会自动扩展到其他 该应用程序的组件。