我正在使用Android 4.4的存储访问框架并打开文件选择器.
一切正常,除非从Google云端硬盘中选择文件,我只能弄清楚如何将其作为输入流打开,但我想获得一个java File对象.
返回的内容uri看起来像这样:content://com.google.android.apps.docs.storage/document/acc%3D4%3Bdoc%3D2279
其他类似的问题,但没有一个工作解决方案,允许我获取文件名,文件大小和内容:
我还研究了Paul Burke的FileChooser(https://github.com/iPaulPro/aFileChooser),这是该问题列表中最常见的问题.
如何从该内容获取文件?
我目前的解决方法是从输入流写出一个临时文件.
谢谢!
关于如何在SD卡(android 5及以上版本)中编写(和重命名)文件的大量调查结果后,我认为android提供的新SAF需要获得用户写入SD卡文件的许可.
我在这个文件管理器应用程序ES文件资源管理器中看到,最初它采用以下方式读取和写入权限,如图片所示.
选择SD卡后,授予写入权限.
因此我尝试使用SAF的方式相同,但重命名文件失败了.我的代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rename = (Button) findViewById(R.id.rename);
startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), 42);
}
@Override
public void onActivityResult(int requestCode,int resultCode,Intent resultData) {
if (resultCode != RESULT_OK)
return;
Uri treeUri = resultData.getData();
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
grantUriPermission(getPackageName(), treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
public void renameclick(View v) {
File ff = new File("/storage/sdcard1/try1.jpg");
try {
ff.createNewFile();
} catch (Exception e) {
Log.d("error", "creating");
e.printStackTrace();
}
} …Run Code Online (Sandbox Code Playgroud) android android-sdcard storage-access-framework android-5.0-lollipop documentfile
我正在尝试Android 4.4的存储访问框架
我开发了一个虚拟应用程序,它启动了活动开始的意图.
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, READ_REQUEST_CODE);
Run Code Online (Sandbox Code Playgroud)
我还开发了另一个虚拟应用程序作为文件提供程序.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.saf"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="19"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.saf.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="com.example.saf.MyFileProvider"
android:authorities="com.example.saf.documents"
android:exported="@bool/is_kitkat"
android:enabled="@bool/is_kitkat"
android:grantUriPermissions="@bool/is_kitkat"
android:permission="android.permission.MANAGE_DOCUMENTS">
<intent-filter>
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
</intent-filter>
</provider>
</application>
Run Code Online (Sandbox Code Playgroud)
我已经实现了MyFileProvider类.
但是当我启动用户应用程序(触发意图的那个)时,我收到以下错误
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.OPEN_DOCUMENT cat=[android.intent.category.OPENABLE] }
Run Code Online (Sandbox Code Playgroud)
我只是关注android的开发者文档.我有什么想法可能做错了吗?
编辑:这是我最新的Manifest.我还需要MyFileProvider"扩展DocumentsProvider"的"正确"实现吗?我现在可以在函数中返回null吗?
android android-intent android-activity android-4.4-kitkat storage-access-framework
Google不幸地计划破坏存储权限,以使应用程序无法使用标准File API(和文件路径)访问文件系统。许多人反对它,因为它改变了应用程序访问存储的方式,并且在许多方面都是受限制的有限API。
因此,如果我们想处理各种问题,我们将需要在将来的某些Android版本上完全使用SAF(存储访问框架)(在Android Q上,我们至少可以暂时使用一个标志来使用常规存储权限)。存储卷并到达那里的所有文件。
因此,例如,假设您要制作一个文件管理器并显示设备的所有存储卷,并为每个文件显示有多少总字节和可用字节。这样的事情看起来非常合法,但是由于我找不到找到这种方法的方法。
从API 24(此处)开始,我们终于可以列出所有存储卷,如下所示:
val storageManager = getSystemService(Context.STORAGE_SERVICE) as StorageManager
val storageVolumes = storageManager.storageVolumes
Run Code Online (Sandbox Code Playgroud)
事实是,此列表上的每个项目都没有功能来获取其大小和可用空间。
但是,以某种方式,Google的“ Google提供的文件”应用程序设法获得了该信息,而没有获得任何形式的许可:
并在装有Android 8的Galaxy Note 8上进行了测试。甚至没有最新版本的Android。
因此,这意味着即使在Android 8上,也应该有一种无需任何许可即可获取此信息的方法。
有一些类似于获得自由空间的东西,但是我不确定是否确实如此。虽然如此。这是它的代码:
val storageManager = getSystemService(Context.STORAGE_SERVICE) as StorageManager
val storageVolumes = storageManager.storageVolumes
AsyncTask.execute {
for (storageVolume in storageVolumes) {
val uuid: UUID = storageVolume.uuid?.let { UUID.fromString(it) } ?: StorageManager.UUID_DEFAULT
val allocatableBytes = storageManager.getAllocatableBytes(uuid)
Log.d("AppLog", "allocatableBytes:${android.text.format.Formatter.formatShortFileSize(this,allocatableBytes)}")
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我找不到类似的东西来获取每个StorageVolume实例的总空间。假设我对此是正确的,我已经在这里提出了要求。
您可以在我对此问题写的答案中找到更多我所找到的内容,但是目前,这是所有变通办法的结合,这些工作不是变通办法,而是在某些情况下有效。 …
在我的应用程序中,我将图像路径存储在我的SQlite数据库中以供进一步使用.我得到的路径是
content://com.android.providers.media.documents/document/image%3A71964
Run Code Online (Sandbox Code Playgroud)
当我从数据库中检索此路径并尝试从该路径中检索图像时,机器人抛出
java.lang.SecurityException: Permission Denial: opening provider
com.android.providers.media.MediaDocumentsProvider
from ProcessRecord{42c84ec8 23911:com.gots.gb/u0a248} (pid=23911, uid=10248)
requires android.permission.MANAGE_DOCUMENTS or android.permission.MANAGE_DOCUMENTS
Run Code Online (Sandbox Code Playgroud)
根据https://developer.android.com/guide/topics/providers/document-provider.html#permissions我需要通过添加以下代码来保留权限
final int takeFlags = intent.getFlags()
& (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// Check for the freshest data.
getContentResolver().takePersistableUriPermission(uri, takeFlags);
Run Code Online (Sandbox Code Playgroud)
当我将此代码添加到我的ImageAdapter类时,它扩展了BaseAdapter android抛出
08-21 02:14:38.530: W/System.err(24452): java.lang.SecurityException:
No permission grant found for UID 10248 and Uri
content://com.android.providers.media.documents/document/image:71964
Run Code Online (Sandbox Code Playgroud)
这是我的ImageAdapter代码的相关部分
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView ;
if (convertView == null){
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(185, 185));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, …Run Code Online (Sandbox Code Playgroud) java sqlite android android-4.4-kitkat storage-access-framework
一开始,用户可以使用新的存储访问框架选择文件(假设应用程序是API> 19):
https://developer.android.com/guide/topics/providers/document-provider.html
然后通过保存URI来保存对所选文件的引用,如下所示:
content://com.android.providers.downloads.documments/document/745
Run Code Online (Sandbox Code Playgroud)
(在这种情况下,文件来自默认下载dir`).
稍后,我想让用户打开这些文件(例如,他们的名字显示在UI列表中,用户选择一个).
我想用Android着名的意图选择器功能做到这一点,我所拥有的只是上面的URI对象......
谢谢,
android android-intent android-file storage-access-framework android-afilechooser
Android 10 和 11有各种存储限制,其中还包括访问所有文件的新权限 ( MANAGE_EXTERNAL_STORAGE )(但它不允许访问真正的所有文件),而之前的存储权限已减少以仅授予对媒体的访问权限文件:
我注意到一个名为“ X-plore ”的应用程序以某种方式克服了这个限制(此处):一旦您进入“Android/data”文件夹,它会要求您授予对它的访问权限(直接使用 SAF,不知何故),并且当您授予它,您可以访问“Android”文件夹的所有文件夹中的所有内容。
这意味着可能仍然有一种方法可以达到它,但问题是由于某种原因,我无法制作具有相同效果的样本。
该应用程序似乎针对 API 29 (Android 10),并且它尚未使用新权限,并且它具有标志requestLegacyExternalStorage。我不知道他们在针对 API 30 时使用的相同技巧是否有效,但我可以说,在我的情况下,在 Pixel 4 和 Android 11 上运行,它工作正常。
所以我尝试做同样的事情:
我制作了一个针对 Android API 29 的示例 POC,已授予(各种)存储权限,包括遗留标志。
我试图请求直接访问“Android”文件夹(基于此处),但遗憾的是由于某种原因无法正常工作(一直转到 DCIM 文件夹,不知道为什么):
val androidFolderDocumentFile = DocumentFile.fromFile(File(primaryVolume.directory!!, "Android"))
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
.putExtra(DocumentsContract.EXTRA_INITIAL_URI, androidFolderDocumentFile.uri)
startActivityForResult(intent, 1)
Run Code Online (Sandbox Code Playgroud)
我尝试了各种标志组合。
启动应用程序时,当我自己手动到达“Android”文件夹时,因为这不能正常工作,我授予了对该文件夹的访问权限,就像在其他应用程序上一样。
获取结果时,我尝试获取路径中的文件和文件夹,但无法获取它们:
override fun onActivityResult(requestCode: Int, resultCode: Int, …Run Code Online (Sandbox Code Playgroud) Google不幸地计划破坏存储权限,以使应用程序无法使用标准File API(和文件路径)访问文件系统。许多人反对它,因为它改变了应用程序访问存储的方式,并且在许多方面都是受限制的有限API。
因此,如果我们想处理各种问题,我们将需要在将来的某些Android版本上完全使用SAF(存储访问框架)(在Android Q上,我们至少可以暂时使用一个标志来使用常规存储权限)。存储卷并到达那里的所有文件。
因此,例如,假设您要创建一个文件管理器并显示设备的所有存储卷,以显示用户可以授予访问权限的内容,并且如果您已经可以访问每个文件,则只需输入该文件即可。这样的事情看起来很合理,但是由于我找不到解决方法。
从API 24(此处)开始,我们终于可以列出所有存储卷,如下所示:
val storageManager = getSystemService(Context.STORAGE_SERVICE) as StorageManager
val storageVolumes = storageManager.storageVolumes
Run Code Online (Sandbox Code Playgroud)
而且,这是有史以来第一次,我们可以有一个Intent请求访问storageVolume(在此)。因此,例如,如果我们要请求用户授予对主数据库的访问权限(实际上是从那里开始,实际上并没有真正询问任何内容),则可以使用以下方法:
startActivityForResult(storageManager.primaryStorageVolume.createOpenDocumentTreeIntent(), REQUEST_CODE__DIRECTORTY_PERMISSION)
Run Code Online (Sandbox Code Playgroud)
代替startActivityForResult(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), REQUEST_CODE__DIRECTORTY_PERMISSION),希望用户在那里选择正确的东西。
为了最终获得用户选择的内容,我们需要执行以下操作:
@TargetApi(Build.VERSION_CODES.KITKAT)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE__DIRECTORTY_PERMISSION && resultCode == Activity.RESULT_OK && data != null) {
val treeUri = data.data ?: return
contentResolver.takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
val pickedDir = DocumentFile.fromTreeUri(this, treeUri)
...
Run Code Online (Sandbox Code Playgroud)
到目前为止,我们可以请求对各种存储卷的许可... …
在Android 4.4中,来自Play商店的应用程序只能写入其应用程序特定目录(例如:/storage/extSdCar/Android/data/com.example.myapp/),并且不允许应用程序在micro SD卡中写入此目录以外的内容.所以我正在探索新的SAF API来检查我是否可以使用SAF写入除应用程序特定目录之外的micro SD卡.
我已经通过创建示例提供程序和客户端应用程序来实现SAF.在我的提供商中,我尝试通过在queryRoots中实现以下代码来显示SD卡的全部内容:
row.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(new File("/storage/extSdCard")));
row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_RECENTS | Root.FLAG_SUPPORTS_SEARCH);
Run Code Online (Sandbox Code Playgroud)
我在我的客户端创建了以下意图,我可以通过我的提供商从SAF的系统UI浏览SD卡的全部内容.
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
intent.putExtra(Intent.EXTRA_TITLE, "test.txt");
startActivityForResult(intent, WRITE_REQUEST_CODE);
Run Code Online (Sandbox Code Playgroud)
当我单击保存按钮时,我收到Toast错误"无法保存文档".但是当我导航到我的提供者的App特定目录(/storage/extSdCar/Android/data/com.example.myprovider/)时系统UI,我能够保存文档.也没有意图,如Intent.CATEGORY_WRITABLE,所以我只能获得可以编辑的文档.请帮我解决以下几点:
似乎即使我们使用SAF,仍然对micro SD卡的WRITE限制保持不变.它是否正确?
2.有什么方法可以创建或删除或修改micro SD卡中我的App特定目录之外的已有文件?
3.谁为普通用户文件决定FLAG_SUPPORTS_WRITE标志,如照片,视频,音乐,文档等?
java android android-sdcard android-4.4-kitkat storage-access-framework
我正在为Dropbox编写DocumentsProvider.我正在尝试遵循Google指南创建自定义提供程序,以及Ian Lake 在Medium上发布的相同内容.
我试图在存储访问框架中包含该功能,其中一个表明有更多数据要加载.
queryChildDocuments()方法的相关部分如下所示:
@Override
public Cursor queryChildDocuments(final String parentDocumentId,
final String[] projection,
final String sortOrder) {
if (selfPermissionsFailed(getContext())) {
// Permissions have changed, abort!
return null;
}
// Create a cursor with either the requested fields, or the default projection if "projection" is null.
final MatrixCursor cursor = new MatrixCursor(projection != null ? projection : getDefaultDocumentProjection()){
// Indicate we will be batch loading
@Override
public Bundle getExtras() {
Bundle bundle = new Bundle(); …Run Code Online (Sandbox Code Playgroud) storage android frameworks storage-access-framework dropbox-sdk-js
android ×10
java ×2
android-11 ×1
android-file ×1
documentfile ×1
frameworks ×1
sqlite ×1
storage ×1