当前位置: 首页 > 编程笔记 >

AndroidQ沙盒机制之分区存储适配

李良策
2023-03-14
本文向大家介绍AndroidQ沙盒机制之分区存储适配,包括了AndroidQ沙盒机制之分区存储适配的使用技巧和注意事项,需要的朋友参考一下

为了让用户更好地控制自己的文件,Android Q更改了应用访问设备外部存储空间中文件的方式。Android Q用更精细的媒体特定权限来替换READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限,并且无需特定权限,应用即可访问自己在外部存储设备的文件。

1、针对应用私有文件的隔离存储沙盒

对于每个应用,Android Q 都会创建一个“隔离存储沙盒”,以限制其他应用访问本应用在外部存储设备的文件。常见的外部存储设备是/sdcard。此定义具有两个优点:

①、需要的权限更少。 应用沙盒中的文件是您应用的私有文件。因此,您不再需要任何权限即可在外部存储设备中访问和保存自己的文件;

②、相对于设备上的其他应用,隐私性更强。 任何其他应用都无法直接访问您应用的隔离存储沙盒中的文件。借助此访问权限限制,您的应用可以更轻松地维护沙盒文件的隐私性;

在外部存储设备存储文件的最佳位置是Context.getExternalFilesDir()返回文件所在的位置,因此此位置的行为方式在所有Android版本中都保持一致。使用此方法时,需要在媒体环境中传递我们要创建或打开的文件类型对应的文件。例如,要保存或访问应用私有图片,请调用Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)。

2、媒体文件的共享集合

如果我们的应用创建了属于相应用户的文件,并希望卸载该应用时保留此用户,则将这些文件保存在某个通用媒体集合(共享集合)中。共享集合包括:照片、音频、视频和下载内容。

3、查看其它应用的文件所需权限

我们的应用无需请求任何权限,即可在这些共享集合中创建和修改自己的文件。但是,我们的应用要创建或修改其他应用已创建的文件,则必须先请求相应权限:

①、访问照片和视频共享集合中其他应用的文件时,需要 READ_MEDIA_IMAGES 或 READ_MEDIA_VIDEO 权限(具体取决于您的应用需要访问的文件类型);

②、访问音乐共享集合中其他应用的文件时,需要 READ_MEDIA_AUDIO 权限;

4、访问共享集合

在请求必要的权限后,我们的应用可以使用MediaStore API访问这些集合:

①、对于照片和视频共享集合,请使用 MediaStore.Images 或 MediaStore.Video;

②、对于音乐共享集合,请使用 MediaStore.Audio;

③、对于下载内容共享集合,请使用 MediaStore.Downloads;

要在原生代码中访问媒体文件,请使用基于Java或kotlin代码的MediaStore来检索相应文件,然后对相应文件描述符传递到原生代码。详情请参考从原生代码访问媒体文件部分。

5、保留应用在共享集合的文件

默认情况下,在用户卸载应用时,Android Q会清理保存在沙盒的文件。要在卸载应用时保留这些文件,请使用存储访问框架存储访问框架,或将文件保存在共享集合中。要保留共享集合的文件,请在相关的MediaStore集合中新插一行,并使用以下方法:

①、至少应为 DISPLAY_NAME 和 MIME_TYPE 列提供值;

②、(可选)您可以使用 PRIMARY_DIRECTORY 和 SECONDARY_DIRECTORY 列来影响文件在磁盘上的存储位置;

③、保留 DATA 列不定义。这样一来,平台便可以灵活地将文件保留在沙盒之外;

插入此行后,我们可以使用ContentResolver.openFileDescriptor() 这个API向文件读取或写入数据。

6、访问照片的位置信息

一些照片在Exif元数据中包含位置信息,以便用户查看照片的拍摄地点。由于此位置信息非常敏感,因此默认情况下,Android Q会对此位置信息进行隐藏。如果我们的应用需要访问照片的位置信息,需要调用以下方法:

①、将新的 ACCESS_MEDIA_LOCATION 权限添加到您应用的清单中;

②、在 MediaStore 对象中,调用 setRequireOriginal() 并传入照片的 URI;

Java示例代码如下:

Uri photoUri = Uri.withAppendedPath(
      MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
      cursor.getString(idColumnIndex));
 
  final double[] latLong;
  if (BuildCompat.isAtLeastQ()) {
    // When running Android Q, get location data from `ExifInterface`.
    photoUri = MediaStore.setRequireOriginal(photoUri);
    InputStream stream = getContentResolver().openInputStream(photoUri);
    if (stream != null) {
      ExifInterface exifInterface = new ExifInterface(stream);
      double[] returnedLatLong = exifInterface.getLatLong();
 
      // If lat/long is null, fall back to the coordinates (0, 0).
      latLong = returnedLatLong != null ? returnedLatLong : new double[2];
 
      // Don't reuse the stream associated with {@code ExifInterface}.
      stream.close();
    } else {
      // Failed to load the stream, so return the coordinates (0, 0).
      latLong = new double[2];
    }
  } else {
    // On devices running Android 9 (API level 28) and lower, use the
    // media store columns.
    latLong = new double[]{
        cursor.getFloat(latitudeColumnIndex),
        cursor.getFloat(longitudeColumnIndex)
    };
  }

kotlin示例代码如下:

val latLong = if (BuildCompat.isAtLeastQ()) {
    // When running Android Q, get location data from `ExifInterface`.
    photoUri = MediaStore.setRequireOriginal(photoUri)
    contentResolver.openInputStream(photoUri).use { stream ->
      ExifInterface(stream).run {
        // If lat/long is null, fall back to the coordinates (0, 0).
        latLong ?: doubleArrayOf(0.0, 0.0)
      }
    }
  } else {
    // On devices running Android 9 (API level 28) and lower, use the
    // media store columns.
    doubleArrayOf(
      cursor.getFloat(latitudeColumnIndex).toDouble(),
      cursor.getFloat(longitudeColumnIndex).toDouble()
    )
  }

7、访问其他应用创建的文件

要访问其他应用已保存在外部存储设备的媒体文件,需要以下步骤:

①、根据包含您要访问的文件的共享集合请求必要的权限;

②、使用 ContentResolver 对象查找并打开该文件;

8、向其他应用创建的文件写入数据

通过将文件保存在共享集合,我们的应用成为该文件的所有者。通常情况下,只有是共享集合的某个文件所有者时,我们的应用才可以向文件写入数据。不过,如果我们的应用是用户默认的应用,我们可以向其他应用的文件写入数据:

①、如果您的应用是用户的默认照片管理器应用,则可以修改其他应用保存到照片和视频共享集合中的图片文件;

②、如果您的应用是用户的默认音乐应用,则可以修改其他应用保存到音乐共享集合中的音频文件;

要修改其他应用保存在存储设备的媒体文件,需要使用ContentResolver找到相应文件来修改。

9、标识特定的外部存储设备

在Android 9及以下版本,所有存储设备上的所有文件都会显示单个"external"卷名称。而Android Q为每个外部存储设备提供唯一的卷名称。此命名系统可以帮助我们高效整理内容并且加入索引,还可以控制存储内容的位置。要唯一标识外部存储设备的特定文件,我们需要使用卷名称和ID。例如,主存储设备的文件是content://media/external/images/media/12,而命名为FA23-3E92辅助存储设备对应文件是content://media/FA23-3E92/images/media/12。

10、获取外部存储列表

要获取所有当前可用卷的名称列表,请调用 MediaStore.getAllVolumeNames(),如以下代码段所示:

Set<String> volumeNames = MediaStore.getAllVolumeNames(context);

到此这篇关于AndroidQ沙盒机制之分区存储适配的文章就介绍到这了,更多相关AndroidQ 分区存储适配内容请搜索小牛知识库以前的文章或继续浏览下面的相关文章希望大家以后多多支持小牛知识库!

 类似资料:
  • MIP 以浏览体验与加载速度为优先考量点,因此在组件开发的时候,MIP 只开放了部分原生 JS 供组件开发者使用,以尽量避免组件开发出有悖 MIP 站点体验的组件。这个实现部分开放原生 JS API 的机制就是 MIP 的加载机制。 部分开放的 JS API MIP 鼓励使用 JS 进行计算,进行逻辑实现等等。因此这类工具型 API、数据结构对象等等具有完全的功能,比如 Math.*、Array、

  • 问题内容: Java应该没有内存泄漏,但是仍然可能。当我的程序出现内存泄漏时,我可以修复它(我希望)。但是,当某些第三方程序包具备该功能时,我该怎么办?几乎什么都没有,除非不使用此软件包。 还有其他解决方案吗?我喜欢沙盒的想法。您被允许在某个区域内做任何您想做的事情,而您的“身体上的”没有能力打扰其他人。有没有办法为Java中的内存使用创建此类沙箱?想象一下=创建用于内存使用的沙箱,允许某些程序包

  • 创建一个渲染器可运行于 Chromium OS 沙盒中的浏览器窗口. 启用此选项后,渲染器必须通过IPC与主进程进行通信才能访问Node API。同时,为了使Chromium OS沙盒可运行,electron 必须使用 --enable-sandbox命令行参数运行。 Chromium主要的安全功能之一是所有Blink渲染或JavaScript都运行在沙盒中,该沙盒使用了特定于操作系统的功能以确保

  • 一、前言 前几章节我们介绍了Memcached的网络模型,命令行的解析,消息回应,HashTable,Memcached的增删改查操作以及LRU算法模块。 这一章我们重点讲解Memcached的存储机制Slabs。Memcached存储Item的代码都是在slabs.c中来实现的。 在解读这一章前,我们必须先了解几个概念。 Item 缓存数据存储的基本单元 Item是Memcached存储的最小单

  • Chromium的一个关键安全特性是,进程可以在沙盒中执行。 沙盒通过限制对大多数系统资源的访问来减少恶意代码可能造成的伤害 — 沙盒化的进程只能自由使用CPU周期和内存。 为了执行需要额外权限的操作,沙盒处的进程通过专用通信渠道将任务下放给更大权限的进程。 在Chromium中,沙盒化应用于主进程以外的大多数进程。 其中包括渲染器进程,以及功能性进程,如音频服务、GPU 服务和网络服务。 查阅C

  • Web Storage 最早是在Web 超文本应用技术工作组(WHAT-WG)的Web 应用1.0 规范中描述的。 这个规范的最初的工作最终成为了HTML5 的一部分。Web Storage 的目的是克服由cookie 带来的一些限制,当数据需要被严格控制在客户端上时,无须持续地将数据发回服务器。Web Storage 的两个主要目标是: 提供一种在cookie 之外存储会话数据的途径; 提供一种

  • 是否有一种方法来设置缓存控制元数据,同时将文件放入谷歌云存储使用谷歌云存储适配器Flysystem? 我的所有文件都公开在bucket中,但有时我需要更新一些文件,之后我仍然会看到旧文件。一般来说,我认为这是可能的,但我没有看到一种通过Flysystem实现这一点的方法,我们在任何地方都使用它。

  • 我试图理解数据在DataBricks环境中是如何存储和管理的。我对引擎盖下发生的事情有一个相当不错的理解,但在网上看到了一些相互矛盾的信息,因此希望得到一个详细的解释来巩固我的理解。为了提出我的问题,我想总结一下我在Apache Spark开发人员课程中所做的部分练习。 作为练习的一部分,我在Databricks平台上遵循了以下步骤: 启动我的群集 将拼花文件读取为DataFrame 将DataF