标签: scoped-storage

如何在不使用文件或文件路径的情况下获取文件系统(不仅仅是已安装的文件)中APK文件的信息?

背景

我的应用程序(在此处)可以在整个文件系统(不仅是已安装的应用程序)中搜索APK文件,显示有关每个文件的信息,允许删除,共享,安装...

作为Android Q范围内存储功能的一部分,Google宣布SAF(存储访问框架)将取代常规存储权限。这意味着,即使您尝试使用存储权限,也只会授予访问特定类型的文件的权限,以使File和file-path可以使用或完全沙箱化(在此处撰写)。

这意味着许多框架将需要依赖SAF而不是File和file-path。

问题

其中之一是packageManager.getPackageArchiveInfo,它给出了文件路径,返回 PackageInfo,我可以得到有关以下内容的各种信息:

  1. 名称(在当前配置上),使用,也称为“标签” packageInfo.applicationInfo.loadLabel(packageManager)。这基于设备的当前配置(语言环境等)。
  2. 包名称,使用 packageInfo.packageName
  3. 版本代码,使用packageInfo.versionCodepackageInfo.longVersionCode
  4. 版本号,使用 packageInfo.versionName
  5. 应用图标,根据当前配置(密度等...)以各种方式使用:

一种。 BitmapFactory.decodeResource(packageManager.getResourcesForApplication(applicationInfo),packageInfo.applicationInfo.icon, bitmapOptions)

b。如果已安装,AppCompatResources.getDrawable(createPackageContext(packageInfo.packageName, 0), packageInfo.applicationInfo.icon )

C。 ResourcesCompat.getDrawable(packageManager.getResourcesForApplication(applicationInfo), packageInfo.applicationInfo.icon, null)

它还有很多其他功能,它们可以返回您,还有很多可选功能,但我认为这些是有关APK文件的基本详细信息。

我希望Google可以为此提供一个很好的替代方法(在此此处要求),因为目前我找不到任何好的解决方案。

我尝试过的

使用从SAF获得的Uri并从中获得InputStream很容易:

@TargetApi(Build.VERSION_CODES.O)
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    setSupportActionBar(toolbar)
    packageInstaller = packageManager.packageInstaller

    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
    intent.addCategory(Intent.CATEGORY_OPENABLE)
    intent.type = "application/vnd.android.package-archive"
    startActivityForResult(intent, 1)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) { …
Run Code Online (Sandbox Code Playgroud)

android inputstream apk android-package-managers scoped-storage

51
推荐指数
2
解决办法
1519
查看次数

Android Q (10) 请求获得访问所有存储的权限。范围存储

在 Android 10 中,需要访问存储的应用程序需要请求访问具体路径的权限。但是像文件浏览器这样的应用程序可以请求访问根存储的权限并获得对所有存储的读/写权限。这就是我正在努力做的。

根据Android,我们必须ACTION_OPEN_DOCUMENT_TREE为此使用。我遇到的问题是一切似乎都正确,但未向应用授予权限。

  private void askAndroid10Perm()
    {
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
        intent.addFlags(
                Intent.FLAG_GRANT_READ_URI_PERMISSION
                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                        | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
                        | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
        startActivityForResult(intent, REQUEST_CODE_OPEN_DOCUMENT_TREE);
    }
Run Code Online (Sandbox Code Playgroud)

在这里,用户可以看到 Android 文件树,并选择主存储,单击以授予权限。“它将允许 - 应用程序名称 - 可以完全访问当前存储在此位置下的所有文件,以及存储在此处的任何未来内容”-> 允许

然后:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {
        case REQUEST_CODE_OPEN_DOCUMENT_TREE:
            if (resultCode == Activity.RESULT_OK) {
                Uri treeUri = data.getData();
                int takeFlags = data.getFlags();
                takeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION |
                        Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

                    Log.i("TAG", "takePersistableUriPermission: " …
Run Code Online (Sandbox Code Playgroud)

android android-10.0 scoped-storage

23
推荐指数
3
解决办法
2万
查看次数

Google Play 应用程序拒绝 - 不是核心功能 - 使用所有文件访问权限

我在 Play 商店中有一个应用程序,该应用程序targetSdkVersion已更新为30from 29,更新后该应用程序一次又一次被 Google Play 拒绝。

MANAGE_EXTERNAL_STORAGE此前, SDK Manifest 中有一项权限。

从我的应用程序中完全删除MANAGE_EXTERNAL_STORAGE 权限和存储权限 (WRITE_EXTERNAL_STORAGE ) 后,将应用程序上传到商店,应用程序更新再次被拒绝。

这是从 Google Play 收到的拒绝原因电子邮件。

注意:我将所有媒体文件保存在应用程序特定的内部存储中。

另外,我在我的 SDK 中获得了许可READ_EXTERNAL_STORAGE,因为我们的应用程序中有聊天功能,可以获取设备的图像和视频来发送。

根据许可没有影响。Use of All files access (MANAGE_EXTERNAL_STORAGE) permission READ_EXTERNAL_STORAGE

附参考。

更新

我也删除了READ_EXTERNAL_STORAGE该应用程序的权限,但仍然遭到 Google Play 出于相同原因的拒绝。

是存储策略的问题还是其他问题?

mediastore google-play google-play-console scoped-storage android-11

12
推荐指数
2
解决办法
1万
查看次数

Android Q,如何用正确的文件名保存MediaStore的录音?

我想将使用我的应用程序录制的 mp3 文件存储到带有 MediaStore 的 Music 文件夹中,用于 Android 10 的新“范围存储”。
此方法效果很好,但文件以时间戳命名(例如 1576253519449),没有.mp3扩展名。
如果我使用文件管理器手动添加扩展名,则文件会被正确记录。
我如何fileName + ".mp3"用来命名文件?

String fileName; //Obtained by intent
MediaRecorder audioRecorder;
Uri audiouri;
ParcelFileDescriptor file;

private void startRecording() throws IOException {
    ContentValues values = new ContentValues(4);
    values.put(MediaStore.Audio.Media.TITLE, fileName);
    values.put(MediaStore.Audio.Media.DATE_ADDED, (int) (System.currentTimeMillis() / 1000));
    values.put(MediaStore.Audio.Media.MIME_TYPE, "audio/mp3");
    values.put(MediaStore.Audio.Media.RELATIVE_PATH, "Music/Recordings/");

    audiouri = getContentResolver().insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values);
    file = getContentResolver().openFileDescriptor(audiouri, "w");

    if (file != null) {
        audioRecorder = new MediaRecorder();
        audioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        audioRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        audioRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        audioRecorder.setOutputFile(file.getFileDescriptor());
        audioRecorder.setAudioChannels(1);
        audioRecorder.prepare();
        audioRecorder.start();
    }
}
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

另一个问题: …

android file audio-recording mediastore scoped-storage

9
推荐指数
1
解决办法
3437
查看次数

Android 10:如何以编程方式删除文件系统上的 MediaStore 项目及其关联数据?

我正在更新我的应用以使用 Android 10 中引入的 Scoped Storage 功能。

我的应用程序与 MediaStore 一起使用并显示图像、视频和音频文件,并为用户提供删除项目的能力。

我之前删除文件的操作:

  1. 得到了路径 MediaStore.MediaColumns.DATA
  2. 用于new File(path).delete()删除该文件
  3. 手动更新 MediaStore

现在 MediaStore.MediaColumns.DATA 不可用,我迁移到使用ContentResolver.delete()从 MediaStore 删除项目

例如,我有项目的 uri:(content://media/external/images/media/502它的有效 uri,我在网格中显示它的缩略图)。我是否在 MediaStore 或其他一些应用程序中插入了这个项目都没有关系。

我用context.getContentResolver().delete(uri, null, null). 它要么成功删除(返回 1 行),要么捕获RecoverableSecurityException用于startIntentSenderForResult()访问当前 uri,然后使用相同的内容getContentResolver().delete()将其删除onActivityResult()然后成功删除。

无论哪种方式,该项目都会从 MediaStore 中删除,并且在我查询 MediaStore 以获取图像时也不会在结果中显示,也不会在其他应用程序中显示。

但是此文件存在于文件系统中(使用 SAF 和各种文件管理器(Google Files、Total Commander)进行检查)

有时(取决于 Android 版本和媒体类型)这些项目会在手机重启后(或打开 Google 相册后 - 它扫描文件系统)带回 MediaStore

例如:我的 Google Pixel 和 Google Pixel …

android mediastore scoped-storage

9
推荐指数
3
解决办法
5679
查看次数

如何获得 MANAGE_EXTERNAL_STORAGE 权限

我正在尝试在我的 Android 10 (API 29) 设备上获得MANAGE_EXTERNAL_STORAGE权限。

https://developer.android.com/training/data-storage/manage-all-files

显现:

<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
Run Code Online (Sandbox Code Playgroud)

主要活动:

Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
startActivity(intent);
Run Code Online (Sandbox Code Playgroud)

结果是:

No Activity found to handle Intent { act=android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION }
Run Code Online (Sandbox Code Playgroud)

好的,这种行为是可能的。医生说:

In some cases, a matching Activity may not exist, so ensure you safeguard against this.
Run Code Online (Sandbox Code Playgroud)

但是我怎样才能获得那个许可呢?

android android-permissions scoped-storage

9
推荐指数
1
解决办法
1万
查看次数

以编程方式测试是否在Android 10+中禁用了旧版外部存储访问

是否有一个简单的API调用可以告诉我在Android 10或更高版本上运行的应用程序是否必须使用范围存储访问权限,即是否禁用了常规文件访问(又称为“旧版外部存储”)?请注意,即使AndroidManifest.xml中的应用程序也声明了:

  android:requestLegacyExternalStorage="true"
Run Code Online (Sandbox Code Playgroud)

由于将来Google的政策更改,文件访问仍可能会被拒绝,因此测试该值是没有用的。我发现的唯一方法是测试外部存储根目录是否可读,为此,应用程序必须首先请求存储许可,如果禁用了旧存储,则该存储对其他任何东西都没有用。

public static boolean mustUseScopedStorage() {
    // Impractical must first ask for useless Storage permission...
    File exSD = Environment.getExternalStorageDirectory();
    return !exSD.canRead(); // this test works only if Storage permission was granted.
}
Run Code Online (Sandbox Code Playgroud)

我想我曾经看过一种新的API可以检测到这一点,但是现在找不到该文章了...

android scoped-storage legacy-external-storage

8
推荐指数
1
解决办法
281
查看次数

下载管理器不适用于 Android 10 (Q)

很长一段时间以来,我一直在努力解决这个问题……我正在更新一个应用程序,该应用程序使用 DownloadManger 来执行一个简单的任务,例如将文件下载到外部存储公共目录,即:

Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
Run Code Online (Sandbox Code Playgroud)

从 Android api 19-28 开始,这里一切正常。在 API 29 (Q/10) 上进行测试时,就会出现问题。Android实作用域存储等弃用getExternalStoragePublicDirectory ......因此,我需要找出一个兼容的解决方案,以支持的API 19- 29。我无法使用内部应用程序存储,因为 DownloadManager 会抛出 SecurityException。Androids 文档指出我可以使用 DownloadManager.RequestsetDestinationUri并且它甚至提到我可以使用的 Android Q Context.getExternalFilesDir(String)。但是,当我这样做时,路径仍然是模拟路径:

/storage/emulated/0/Android/data/com.my.package.name/files/Download/myFile.xml
Run Code Online (Sandbox Code Playgroud)

我从下载管理器收到一个回调,表明下载已完成(使用正确的 ID),但随后我无法从保存它的区域获取下载。我检查文件是否存在并返回false:

new File("/storage/emulated/0/Android/data/com.my.package.name/files/Download/myFile.xml").exists();
Run Code Online (Sandbox Code Playgroud)

任何帮助表示赞赏

添加上下文代码。所以设置下载管理器

    private void startDownload() {
        IntentFilter filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
        registerReceiver(downloadReceiver, filter);

        String remoteURL= getString(R.string.remote_url);

        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(remoteUrl));
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
        request.setTitle(getString(R.string.download_title));
        request.setDescription(getString(R.string.download_description));
        request.setDestinationUri(Uri.fromFile(new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "myFile.xml")));

        DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
        mainDownloadID= manager.enqueue(request);
    }
Run Code Online (Sandbox Code Playgroud)

检查文件是否存在:

new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "myFile.xml").exists(); //this returns false in the onReceive (and download …
Run Code Online (Sandbox Code Playgroud)

android download android-download-manager android-10.0 scoped-storage

8
推荐指数
1
解决办法
7339
查看次数

使用Android的MediaStore(ContentResolver/范围存储)创建图像文件后文件扩展名和文件名错误

我正在使用MediaStore 和 ContentResolver API 来保存图像文件 (jpg/png/gif) MediaStore.Images。它可以工作,但问题是所有文件都以 .jpg 扩展名保存,并且文件名始终为“millis.jpg 中的当前时间”

以下是我在 ContentValues 中放入的内容的示例:

date_added=1575480356 _display_name=2067623.gif date_modified=1575480356 mime_type=image/gif
Run Code Online (Sandbox Code Playgroud)

但将其插入 ContentResolver 并写入文件后,显示名称更改为2067623.jpg,文件名更改为1575480356.jpg.

如何让它保留文件名和扩展名

代码:

    ContentResolver resolver = activity.getContentResolver();
    Uri mediaCollection;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        mediaCollection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
    } else {
        mediaCollection = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
    }

    ContentValues mediaDetails = new ContentValues();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        final String relativeLocation = Environment.DIRECTORY_PICTURES + File.separator + "my_folder";
        mediaDetails.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
        mediaDetails.put(MediaStore.Images.Media.IS_PENDING, 1);
        mediaDetails.put(MediaStore.MediaColumns.RELATIVE_PATH, relativeLocation);
    }
    String mimeType …
Run Code Online (Sandbox Code Playgroud)

java android mediastore android-contentresolver scoped-storage

8
推荐指数
1
解决办法
1360
查看次数

将文件写入 Android Q 中可公开访问的文档文件夹 - Scoped Storage

背景

迁移到 Android 后 QI 无法再找到合适的方式来获得对文档文件夹的写入权限 ( /storage/emulated/0/Documents)

在任何人提到有关范围存储的许多其他问题之前,我已经阅读了其中的许多问题,并且根据我目前所见,所有解决方案都使用特定于应用程序的目录或仅访问媒体目录(而不是文档文件夹访问权限)。

根据我在 Android QI 中的理解,可以选择:

  • 使用只能由我的应用程序(或我授予权限的应用程序)访问的特定于应用程序的目录
  • 允许用户选择他们想要存储文件的位置(我认为这可以是一个公共位置) ACTION_OPEN_DOCUMENT_TREE

问题

我开发的应用程序用于对主题进行测试,来自测试的数据会自动存储在可公开访问的 Documents 文件夹中,有点像: /storage/emulated/0/Documents/myAppName/subjectName/testData-todaysDate.pdf

当用户想要访问测试数据时,他们将智能手机插入计算机并导航到文档文件夹,其余的就很明显了。出于这个原因,我必须使用可公开访问的存储。还想象他们想通过另一个应用程序打开手机上的测试数据,同样的交易!

我正在寻找的解决方案

所以我正在寻找的解决方案需要能够做到以下几点:

  • 不多次请求许可(一次就可以)
  • 无需用户提示即可自动保存测试数据(因为将进行数百次测试)
  • 保存到公共文档文件夹,例如 /storage/emulated/0/Documents/
  • 不涉及用户选择目录所以不 ACTION_OPEN_DOCUMENT_TREE
  • 理想情况下,数据是持久的,因此卸载应用程序不会导致数据丢失

我知道 Android Q 中的这些变化是为了让用户更多地“了解应用程序如何访问他们的数据”,但是一旦他们了解您的应用程序如何使用您的数据,就不会有问题。

android mediastore android-10.0 scoped-storage

8
推荐指数
1
解决办法
2466
查看次数