我现在可以通过使用以下代码打开Lollipop文件选择器来获取文件URI:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivity(intent);
Run Code Online (Sandbox Code Playgroud)
文件选择器在内部存储的根目录或我打开的最后一个目录中打开.如何让文件选择器显示特定目录的内容?例如,我可能希望文件选择器在启动后显示Download文件夹的内容,如下图所示.

android android-intent storage-access-framework android-5.0-lollipop
我正在使用Intent.ACTION_OPEN_DOCUMENT_TREE授予我的应用程序对外部存储的写访问权限(在Lollipop和Marshmallow上).
但我想在测试应用程序中写入外部存储.Intent.ACTION_OPEN_DOCUMENT_TREE使用系统对话框,因此我无法在测试期间授予权限.我也尝试在应用程序中允许它,然后在测试中使用它但不共享 - 应用程序项目和测试项目是不同的包.
有没有人知道一些可能的解决方法,例如为测试目的授予整个外部存储的许可?也许通过改变一些系统属性?
adb shell setprop SOMEPROPERTY 1
testing android android-external-storage storage-access-framework
我有DocumentFile以下两种定义:
DocumentFile documentFile;
Uri documentFileUri;
Run Code Online (Sandbox Code Playgroud)
我可以通过以下方法从SD卡中删除文档文件:
documentFile.delete();DocumentsContract.deleteDocument(contentResolver, documentFileUri);但以上方法均不能从中删除相应的条目MediaStore。
处理该问题的正确方法是什么?如果我使用ContentProvider删除本地文件,它将File从数据库(contentResolver.delete(localFileUri, null, null);)中删除AND行。我希望如果使用,也会发生相同的情况,DocumentsContract但不会发生...
我想要的是
我想了解一下更新MediaStore。通常我会打电话给我,contentResolver.delete(documentFileUri, null, null);但这会失败,但有一个例外,说uri不支持删除...
题
是否有比我的解决方法更有效的方法?
解决方法
目前,我在删除a后使用以下功能立即更新媒体存储DocumentFile:
public static boolean updateAfterChangeBlocking(String path, int timeToWaitToRecheckMediaScanner)
{
final AtomicBoolean changed = new AtomicBoolean(false);
MediaScannerConnection.scanFile(StorageManager.get().getContext(),
new String[]{path}, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
changed.set(true);
}
});
while (!changed.get()) {
try {
Thread.sleep(timeToWaitToRecheckMediaScanner);
} catch (InterruptedException e) …Run Code Online (Sandbox Code Playgroud) 我正在将文档访问框架与我的云存储访问应用程序集成.使用此文档,我可以访问该文件并检索它(我只是使用Gmail应用程序的附加功能来检查).
我现在正试图找到如何使用相同的方法保存文件(通过应用程序直接将文件保存到云存储),我做了以下更改:
对于getRoots调用,
row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE);
Run Code Online (Sandbox Code Playgroud)
我也覆盖了这个createDocument方法.
我没有看到有关如何执行此操作的示例代码或文档的方法.我也看到像"照片"应用程序这样的应用程序有"共享"按钮使用不同的方法(日志显示miniShareActivity),我的应用程序没有显示在那里(看起来它使用不同的文件共享机制)
我正在寻找有关的信息
如何使用SAF存储文件(任何样本文件都很棒或指向文档).我假设它将允许用户使用选择器界面导航到文件夹并存储文件.
如何让应用程序显示在"Minishare活动"应用程序列表中以将文件导入应用程序(看起来它不提供选择器界面但我仍然希望提供支持以便将文件保存到默认位置)
我使用Android Storage Access Framework访问SD卡上的一些文件.对我来说,保持此权限非常重要,能够在重启设备后编辑文件.
因此,根据Storage Access Framework文档,我使用Persist权限,即使设备已重新启动,也可以通过您的应用程序继续访问文件.
但是,经过一段时间后,我注意到对于某些用户,权限以某种方式被撤销.因为当我尝试使用SAF进行编写时,我得到android.system.ErrnoException: open failed: EACCES (Permission denied)
了该异常之后我会检查我使用了哪些权限,mContext.getContentResolver().getPersistedUriPermissions()但它返回空列表.我确信用户为我提供了正确的权限,并且权限是针对当前安装的Sd卡,因为我在数据库中跟踪此操作.
目前,在这种情况下,我正在显示文档选择器,因此用户可以再次为我提供新的权限,但要求用户执行相同的操作通常不是用户友好的.
什么可以导致撤销权限?我怎么能防止这种撤销?
我已经在我的所有设备上测试了多次手机重启,更换时间,删除插入SD卡,但无法丢失任何安全权限.
我有下一个获取权限的代码:
private void openDocumentTree() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(intent, REQUEST_CODE);
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE) {
Uri treeUri = data.getData();
final int takeFlags = data.getFlags() & (
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
mContext.getContentResolver().takePersistableUriPermission(treeUri,
takeFlags);
//this is my internal class …Run Code Online (Sandbox Code Playgroud) 我正在使用外部SD卡的PersistableUriPermission并将其存储以供进一步使用.现在我希望当用户向我提供文件路径时,从我的应用程序中的文件列表中,我想编辑文档并重命名它.
所以我有要编辑的文件的文件路径.
我的问题是如何从我的TreeUri获取该文件的Uri以及编辑文件.
我试图CATEGORY_OPENABLE从存储访问框架的URI中打开文件描述符.我首先尝试使用sdcard上的文件,我已经可以使用该_data列解析到文件路径并打开(我正在尝试远离这样做,而是使用文件描述符).
我得到了这样的native int fd:
int fd = getContentResolver().openFileDescriptor(data.getData(), "r").detachFd();
Run Code Online (Sandbox Code Playgroud)
然后在C++中,我试图像这样打开它,这个想法取自如何在Android中使用JNI将资产FileDescriptor正确传递给FFmpeg:
pFormatCtx = avformat_alloc_context();
pFormatCtx->iformat = av_find_input_format("mp3");
char path[50];
sprintf(path, "pipe:%d", fd);
int e;
if(e=(avformat_open_input(&pFormatCtx,path,NULL,NULL)!=0)){
av_strerror(e, path, 50);
return error;
}
Run Code Online (Sandbox Code Playgroud)
这会产生"未知错误" avformat_open_input.如果我使用jniGetFDFromFileDescriptor上面链接的jni方法FileDescriptor来获取int fd,则会发生同样的事情.如何在不使用文件路径的情况下正确打开带有FFMPEG的可打开URI?
SAF似乎不刷新文件列表.我在带有Android KitKat的三星Galaxy S4上进行了测试.
当我使用访问DownloadsSAF中的默认提供程序的应用程序时,我看到的文件已被删除.现在我有两个文件,我通过检查/sdcard/Download/adb和使用手机的My Files应用程序确认了这一点,但SAF显示了超过一百个文件的列表.结果是当我选择其中一个已经删除的文件时,应用程序告诉我该文件不存在(这当然是正确的).
还有其他人面临这个问题吗?刷新SAF显示的列表的任何解决方案?
更新:尝试使用Nexus 5和Android 5.1,同样的事情发生了.我相信我误解了Downloads提供者的目标.
该Downloads供应商,可通过SAF,显示下载文件(通常在下载文件夹结束)的历史.如果我们转到下载目录并删除文件,这些文件将不会从Downloads提供程序中删除,因为它显示的是下载文件的历史记录,而不是目录中存在的实际文件列表.
在nautilus中通过复制/粘贴添加文件时,在ubuntu中安装手机后,该文件不会显示在Downloads提供程序中.
那么我们如何摆脱这段历史呢?有一个应用程序,等待它,下载.打开应用程序并删除那里的文件或像我一样清除所有文件,文件就会消失.
(Google驱动程序SAF提供程序正确地反映了您在其外部执行的操作,因此使用它进行测试.)
我正在开发一个创建和打开特定文件类型的 android 应用程序。我正在使用存储访问框架来访问 Kitkat 或更高版本操作系统的文件。现在我需要打开.enc文件并过滤掉任何其他文件。使用存储访问框架我试过:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("file/enc");
Run Code Online (Sandbox Code Playgroud)
和
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType(".enc");
Run Code Online (Sandbox Code Playgroud)
但他们都没有工作。请帮帮我。
我正在制作一个函数来保存通过expo-file-system. 在此代码中,当您在 Android 上单击下载按钮时,会出现文件选择 UI,当您选择文件时,就会下载该文件。但是,我希望文件能够像普通应用程序一样自动下载到特定目录中,而无需用户选择。
使用时requestDirectoryPermissionAsync,是否可以不使用SelectionUI,直接下载文件到指定路径?如果StorageAccessFramework没有这样的方法,有没有办法解决这个问题expo-file-system?
代码
import * as FileSystem from "expo-file-system";
const { StorageAccessFramework } = FileSystem;
const saveAndroidFile = async (fileUri, fileName, contentType) => {
try {
const fileDir = StorageAccessFramework.getUriForDirectoryInRoot("Download");
// This function calls the UI in the image below
const permissions = await StorageAccessFramework.requestDirectoryPermissionsAsync(fileDir);
if (!permissions.granted) {
return;
}
try {
await StorageAccessFramework.createFileAsync(fileDir, fileName, contentType)
.then(async (uri) => {
await FileSystem.writeAsStringAsync(uri, fileString, { encoding: FileSystem.EncodingType.Base64 });
alert("Report …Run Code Online (Sandbox Code Playgroud) android storage-access-framework react-native expo expo-file-system