Android Q & Android 11存储适配(一) 基础知识点梳理

【Vue】在vue3中实现pptx、word、excel预览 /设置excel网络地址,可以是相对地址。//引入VueOfficeExcel组件。//引入VueOfficeDocx组件。//设置ppt网络地址,可以是相对地址。具体方法你怎么写都能,只要你能获取到。//设置文档网络地址,可以是相对地址。 阅读详情

下一篇 👉 Android Q & Android 11存储适配(二) FileOperator文件管理框架

分区存储(Scoped Storage)

  • 沙盒存储(App-specific directory) 本应用专有的目录(通过 Context.getExternalFilesDir() 访问)
  • 公共目录(Public Directory) MediaStore/SAF(Storage Access Framework) with ContentResolver
  • var code = “08c6adcc-183e-47f3-9443-4e271bc3328c”

分区存储如何影响文件访问:

文件位置所需权限访问方法 (*)卸载应用时是否移除文件?
特定于应用的目录无 getExternalFilesDir()是
媒体集合
(照片、视频、音频)
READ_EXTERNAL_STORAGE
(仅当访问其他应用的文件时)
MediaStore否
下载内容
(文档和
电子书籍)
无SAF存储访问框架
(加载系统的文件选择器)
否

对应于MediaStore 类中仅包含五种文件类型 Image/Video/Audio以及Files和Download , 其中 Image/Video/Audio 直接使用MediaStore+ContentResolver API即可访问 , 而Files和Download则是使用 SAF存储访问框架访问。

⭐ 注意:使用分区存储的应用对于 /sdcard/DCIM/IMG1024.JPG 这类路径不具有直接内核访问权限。要访问此类文件,应用必须使用 MediaStore,并调用 ContentResolver.openFile() 等方法。

App Specific 沙盒目录

  • 如果配置了 FileProvider 并且配置了external-files-path和external-cache-path,应用会在启动时自动创建 cache和files目录:
 <!--context.getExternalFilesDirs()-->
 <external-files-path
     name="ando_file_external_files"
     path="." />
 <!-- getExternalCacheDirs() 此标签需要 support 25.0.0以上才可以使用-->
 <external-cache-path
     name="ando_file_external_cache"
     path="." />

FileProvider :

<provider
    android:name=".common.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" />
</provider>

MediaStore

  • 媒体数据限制

分区存储会施加以下媒体数据限制:

若您的应用未获得 ACCESS_MEDIA_LOCATION 权限,照片文件中的 Exif 元数据会被修改。要了解详情,请参阅介绍如何访问照片中的位置信息的部分。

MediaStore.Files 表格本身会经过过滤,仅显示照片、视频和音频文件。例如,表格中不显示 PDF 文件。
必须使用 MediaStore 在 Java 或 Kotlin 代码中访问媒体文件。请参阅有关如何从原生代码访问媒体文件的指南。
该指南介绍了如何处理媒体文件,并提供了有关访问 MediaStore 内的单个文档和文档树的最佳做法。如果您的应用使用分区存储,则需要使用这些方法来访问媒体。

  • 如何从原生代码访问媒体文件

系统会自动扫描外部存储,并将媒体文件添加到以下定义好的集合中:

  • Images, including photographs and screenshots, which are stored in the DCIM/ and Pictures/ directories. The system adds these files to the MediaStore.Images table.
  • Videos, which are stored in the DCIM/, Movies/, and Pictures/ directories. The system adds these files to the MediaStore.Video table.
  • Audio files, which are stored in the Alarms/, Audiobooks/, Music/, Notifications/, Podcasts/, and Ringtones/ directories, as well as audio playlists that are in the Music/ or Movies/ directories. The system adds these files to the MediaStore.Audio table.
  • Downloaded files, which are stored in the Download/ directory. On devices that run Android 10 (API level 29) and higher, these files are stored in the MediaStore.Downloads table. This table isn't available on Android 9 (API level 28) and lower.
  • 权限管理

如果您的应用使用范围存储,则它仅应针对运行Android 9(API级别28)或更低版本的设备请求与存储相关的权限。 您可以通过在应用清单文件中的权限声明中添加android:maxSdkVersion属性来应用此条件:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
                 android:maxSdkVersion="28" />

不要为运行Android 10或更高版本的设备不必要地请求与存储相关的权限。 您的应用程序可以参与定义明确的媒体集合,包括MediaStore.Downloads集合,而无需请求任何与存储相关的权限。 例如,如果您正在开发相机应用程序,则无需请求与存储相关的权限,因为您的应用程序拥有您要写入媒体存储区的图像。

  • MediaStore API 提供访问以下类型的媒体文件的接口:
照片:存储在 MediaStore.Images 中。
视频:存储在 MediaStore.Video 中。
音频文件:存储在 MediaStore.Audio 中。
MediaStore 还包含一个名为 MediaStore.Files 的集合,该集合提供访问所有类型的媒体文件的接口。其他文件,例如 PDF 文件,无法访问到。

注意:如果您的应用使用分区存储,MediaStore.Files 集合将仅显示照片、视频和音频文件。

  • 若要加载媒体文件,请从 ContentResolver 调用以下方法之一:

    • 对于单个媒体文件,请使用 openFileDescriptor()。
    • 对于单个媒体文件的缩略图,请使用 loadThumbnail(),并传入要加载的缩略图的大小。
    • 对于媒体文件的集合,请使用 ContentResolver.query()。
  • 🌰查询一个媒体文件集合

// Need the READ_EXTERNAL_STORAGE permission if accessing video files that your
// app didnt create.

// Container for information about each video.
data class Video(val uri: Uri,
    val name: String,
    val duration: Int,
    val size: Int
)
val videoList = mutableListOf<Video>()

val projection = arrayOf(
    MediaStore.Video.Media._ID,
    MediaStore.Video.Media.DISPLAY_NAME,
    MediaStore.Video.Media.DURATION,
    MediaStore.Video.Media.SIZE
)

// Show only videos that are at least 5 minutes in duration.
val selection = "${MediaStore.Video.Media.DURATION} >= ?"
val selectionArgs = arrayOf(
    TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString()
)

// Display videos in alphabetical order based on their display name.
val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC"

val query = ContentResolver.query(
    MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
    projection,
    selection,
    selectionArgs,
    sortOrder
)
query?.use { cursor ->
    // Cache column indices.
    val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)
    val nameColumn =
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME)
    val durationColumn =
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION)
    val sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE)

    while (cursor.moveToNext()) {
        // Get values of columns for a given video.
        val id = cursor.getLong(idColumn)
        val name = cursor.getString(nameColumn)
        val duration = cursor.getInt(durationColumn)
        val size = cursor.getInt(sizeColumn)

        val contentUri: Uri = ContentUris.withAppendedId(
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
            id
        )

        // Stores column values and the contentUri in a local object
        // that represents the media file.
        videoList += Video(contentUri, name, duration, size)
    }
}
  • 媒体文件的挂起状态

如果您的应用程序执行一些可能非常耗时的操作,比如写入媒体文件,那么在文件被处理时对其进行独占访问是非常有用的。在运行Android 10或更高版本的设备上,您的应用程序可以通过将IS_PENDING标志的值设置为1来获得这种独占访问。只有您的应用程序可以查看该文件,直到您的应用程序将IS_PENDING的值更改回0。

为正在存储的媒体文件提供待处理状态
在搭载 Android 10(API 级别 29)及更高版本的设备上,您的应用可以通过使用 IS_PENDING 标记在媒体文件写入磁盘时获得对文件的独占访问权限。

以下代码段展示了在将图片存储到 MediaStore.Images 集合所对应的目录时如何使用 IS_PENDING 标记:

    val values = ContentValues().apply {
        put(MediaStore.Images.Media.DISPLAY_NAME, "IMG1024.JPG")
        put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
        put(MediaStore.Images.Media.IS_PENDING, 1)
    }

    val resolver = context.getContentResolver()
    val collection = MediaStore.Images.Media
            .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
    val item = resolver.insert(collection, values)

    resolver.openFileDescriptor(item, "w", null).use { pfd ->
        // Write data into the pending image.
    }

    // Now that we're finished, release the "pending" status, and allow other apps
    // to view the image.
    values.clear()
    values.put(MediaStore.Images.Media.IS_PENDING, 0)
    resolver.update(item, values, null, null)
    

Android Q 上,MediaStore 中添加了一个 IS_PENDING Flag,用于标记当前文件是 Pending 状态。

其他 APP 通过 MediaStore 查询文件,如果没有设置 setIncludePending 接口,就查询不到设置为 Pending 状态的文件,这就能使 APP 专享此文件。

这个 flag 在一些应用场景下可以使用,例如在下载文件的时候:下载中,文件设置为 Pending 状态;下载完成,把文件 Pending 状态置为 0。

ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, "myImage.PNG");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
values.put(MediaStore.Images.Media.IS_PENDING, 1);

ContentResolver resolver = context.getContentResolver();
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
Uri item = resolver.insert(uri, values);

try {
    ParcelFileDescriptor pfd = resolver.openFileDescriptor(item, "w", null);
    // write data into the pending image.
} catch (IOException e) {
    LogUtil.log("write image fail");
}

// clear IS_PENDING flag after writing finished.
values.clear();
values.put(MediaStore.Images.Media.IS_PENDING, 0);
resolver.update(item, values, null, null);
  • 文件移动
Note: You can move files on disk during a call to update() by changing MediaColumns.RELATIVE_PATH or MediaColumns.DISPLAY_NAME.

注意:您可以在调用update 的过程中通过更改 MediaColumns.RELATIVE_PATH  或MediaColumns.DISPLAY_NAME 在磁盘上移动文件。

Storage Access Framework

相关视频 (Youtube):

Android 4.4(API 级别 19)引入了存储访问框架 (SAF)。借助 SAF,用户可轻松在其所有首选文档存储提供程序中浏览并打开文档、图像及其他文件。用户可通过易用的标准界面,以统一方式在所有应用和提供程序中浏览文件,以及访问最近使用的文件。

编辑文档

⭐ Note: The DocumentFile class’s canWrite() method doesn’t necessarily indicate that your app can edit a document. That’s because this method returns true if Document.COLUMN_FLAGS contains either FLAG_SUPPORTS_DELETE or FLAG_SUPPORTS_WRITE. To determine whether your app can edit a given document, query the value of FLAG_SUPPORTS_WRITE directly.

虚拟文件 👉 视频

Android 7.0 在存储访问框架中加入了虚拟文件的概念。即使虚拟文件没有二进制表示形式,客户端应用也可将其强制转换为其他文件类型,或使用 ACTION_VIEW Intent 查看这些文件,从而打开文件中的内容。

如要打开虚拟文件,您的客户端应用需包含可处理此类文件的特殊逻辑。若想获取文件的字节表示形式(例如为了预览文件),则需从文档提供程序请求另一种 MIME 类型。

为获得应用中虚拟文件的 URI,您首先需创建 Intent 来打开文件选择器界面(如先前搜索文档中的代码所示)。

⭐ 重要说明:由于应用不能使用 openInputStream() 方法直接打开虚拟文件,因此如果您在 ACTION_OPEN_DOCUMENT Intent 中加入 CATEGORY_OPENABLE 类别,则您的应用不会收到任何虚拟文件。

SAF 使用情形 👉 官方文档

通过上面的分析可以看出, MediaStore 仅可以处理公共目录中的 图片/视频/音频 文件, 当涉及到分组文件和其它类型文件的时候显得捉襟见肘。

- [操作一组文件](https://developer.android.google.cn/training/data-storage/shared/media#manage-groups-files)
- [操作文档和其他文件](https://developer.android.google.cn/training/data-storage/shared/media#other-file-types)
- [把数据分享给其它应用](https://developer.android.google.cn/training/data-storage/shared/media#companion-apps)
  • 查看剩余空间

如果您提前知道要存储多少数据,则可以通过调用getAllocatableBytes()找出设备可以为应用程序提供多少空间。 getAllocatableBytes()的返回值可能大于设备上当前的可用空间量。 这是因为系统已识别出可以从其他应用程序的缓存目录中删除的文件。

// App needs 10 MB within internal storage.
const val NUM_BYTES_NEEDED_FOR_MY_APP = 1024 * 1024 * 10L;

val storageManager = applicationContext.getSystemService<StorageManager>()!!
val appSpecificInternalDirUuid: UUID = storageManager.getUuidForPath(filesDir)
val availableBytes: Long =
        storageManager.getAllocatableBytes(appSpecificInternalDirUuid)
if (availableBytes >= NUM_BYTES_NEEDED_FOR_MY_APP) {
    storageManager.allocateBytes(
        appSpecificInternalDirUuid, NUM_BYTES_NEEDED_FOR_MY_APP)
} else {
    val storageIntent = Intent().apply {
        action = ACTION_MANAGE_STORAGE
    }
    // Display prompt to user, requesting that they choose files to remove.
}

⭐ 保存文件之前,不需要检查可用空间量。 相反,您可以尝试立即写入文件,然后在发生异常时捕获IOException。

卸载应用

AndroidManifest.xml中声明:android:hasFragileUserData=“true”,卸载应用会有提示是否保留 APP数据。默认应用卸载时App-specific目录下的数据被删除,但用户可以选择保留。

分享 App-specific 目录下文件👉 FileProvider

参考资料

文档

ContentProvider官方文档

DocumentsProvider官方文档

唯一标识符最佳做法

视频

Youtube 👉 https://www.youtube.com/watch?v=UnJ3amzJM94

Bilibili 👉 https://www.bilibili.com/video/BV1NE41117eR

前端vue3实现本地及在线文件预览(含pdf/txt/mp3/mp4/docx/xlsx/pptx) 本地或内网预览需要借助插件实现,pdf、mp3、mp4等主要靠原生标签或浏览器自带功能,尽量减少了插件的安装。 阅读详情

相关推荐

前端vue导出PPT,使用pptxgen.js

公司新需求需要导出ppt给业务用,查阅资料后发现也挺简单的,记录一下。如有不懂的可以留言!!! 1.安装包 npm install pptxgenjs --save 2.引入包 在需要使用的文件中引入 import Pptxgenfrom "pptxgenjs"

qq_45094682的博客 5476

C语言_获取文件大小

在操作文件时获取文件大小非常简单,我们只需要将文件定位到文件尾,然后在使用ftell获取fp指针到文件第一个字节的偏移量时多少就可以了!//获取文件长度 fseek(fp, 0, SEEK_END); //定位到文件末 int nFileLen = ftell(fp); //文件长度最后别忘记定位到文件头,不然读取的时候会默认从FP指针位置开始读取,也就是文件尾,这样是读取不出任何内容的!f...

17岁boy的博客 9092

Android存储权限终极梳理:从READ_EXTERNAL_STORAGE到MANAGE_EXTERNAL_STORAGE的演进之路

本文全面解析Android存储权限体系的演进历程,从基础权限到Android 10引入的分区存储(Scoped Storage)机制,再到Android 11的MANAGE_EXTERNAL_STORAGE特权。通过详细的技术分析和实战代码示例,帮助开发者高效适配新版存储模型,确保应用在隐私保护与功能完整性之间取得平衡。

yoga7的博客 768

Vue实现pptx在线预览

原文:https://blog.youkuaiyun.com/qq_43075191/article/details/125640149。版权声明:本文为作者原创文章,转载请附上博文链接!

Admans的专栏 5560

别再乱申请MANAGE_EXTERNAL_STORAGE了!Android 11到13存储权限适配的实战避坑指南

本文详细解析了Android 11到13存储权限适配的实战避坑指南,重点探讨了MANAGE_EXTERNAL_STORAGE权限的合规陷阱及其替代方案。通过MediaStore API、存储访问框架(SAF)等合规方法,开发者可以高效实现文件存储功能,同时确保100%的Google Play过审率。文章还提供了不同Android版本的权限矩阵和典型问题处理方案,助力开发者避开存储权限适配的常见误区。

weixin_30791095的博客 398

AndroidQStorage:Android Q存储实战(MediaStore和SAF)

AndroidQStorageSample 是什么? 本项目是,在当前Android Q即将大规模普及的情况下,适配Android Q对存储权限做出的调整,而进行的一个实战项目。 项目中对文件的操作全部基于Uri对象和AndroidX的DocumentFile库,为大家演示Android Q通过Storage Access Framework如何操作私有目录和公共目录。 主要功能包括, 对Android Q 存储权限的获取 校验一个Uri是否有效 如何保存、获取MediaStore内容 如何通过SAF获取文件/文件夹的Uri 如何通过SAF传入Uri对文件进行操作 为什么? 作为Android的开发者,大家应该对早年Android手机被人抱怨卡顿、手机存储空间被应用占用、文件被毒瘤应用监听篡改等诸多问题。很多Android开发者自己都不愿意使用Android手机(尊重个人爱好)。 现在生态

一文带你了解Android 11分区存储适配

分区存储概念 为了让用户更好地控制自己的文件并减少混乱,Android 10针对应用推出的一个新的存储范例,新的存储模型会让以 Android 10(API 级别 29)及更高版本为目标平台的应用在默认情况下被赋予了对外部存储设备的分区访问权限,即分区存储(scoped storage)。分区存储改变了应用在设备的外部存储设备中存储和访问文件的方式。 从另一个角度来说,分区存储的推出更好的保护用户的隐私。默认情况下,对于以 Android 10 及更高版本为目标平台的应用,其访问权限范围限定为外部存储,即分

“点点”专栏 8959

记录Nvidia AGX Orin的配置日常(二)设置上电自动开机和远程桌面

因为要拿AGX作为机器人的主控板,所以需要给他设置一下通电后无需按电源键就自动开机,然后再配置一下远程桌面。

AutomaticForever的博客 1361

Android Q & Android 11存储适配(二) FileOperator文件管理框架

FileOperator ????GitHub ????更简单的处理Android系统文件操作 ????适用于Android 4.4及以上系统, 兼容AndroidQ新的存储策略 ????图片压缩算法参考 Luban ????Kotlin Sample ???? app ????Java Sample ???? sample_java Gradle: Project build.gradle : repositories { maven { url 'https://dl.bintray.co

JavaKam的博客 3192

【完美解决】Anaconda3安装后缺失大量文件,没有scripts、Library等目录

Anaconda3是官网下载的:https://www.anaconda.com/distribution/#download-section 我选择的是64位python 3.7的版本。 问题出现及现象: 我自己选择了一个D盘的目录D:\Tools\Anaconda3进行安装,装完后发现conda list命令无法执行,首先都到的是配置环境变量,然后发现安装目录下缺失大量文件(如下图)...

android之行 3万+

FI 应计对象的创建和摊销

创建/修改:ACACTREE01/ACACTREE02 应计对象的过账:ACACPOSTING

nancyln9711的博客 903

Android Q 存储体系适配(一)

简介 由于Android10 Android系统开始引入沙盒系统,且Android11 进一步的对沙盒系统进行了限制,以此为契机,梳理一下Android 的存储体系。 内部存储和外部存储 内部存储的位置是挂载在Android系统中的/data目录下面的存储空间。外部存储时挂载在Android系统中的/sdcard目录下面的存储空间。 在Android4.4 以前,手机端的存储设备非常小,因此可以类比PC机,机身内部的存储设备就是内部存储。外置的SD卡就是外部存储。随着手机设备存储设备的越来越大,机身的存储设

cxmfzu的博客 588

il2cpp分析-gobal-metadata.dat解密

打开ida,把libil2cpp拖到ida中按快捷键Shift+F12等待字符串分析完后,搜索global-metadata.dat。ida中双击sub_57EE7C进入,VS code中也跳转到LoadMetadataFile函数。VSCode打开il2cpp源代码,全局搜索global-metadata.dat。工具:010Editor,IDA 7.5,Jadx,VS Code。判断加密逻辑为根据文件的长度循环读取字节码做亦或加密。双击搜索出来的结果,切记要选il2cpp目录下的。

Android_machong的博客 8024

Android版本差异适配方案(5.0-11.0)

Android版本差异适配方案(5.0-9.0) 一个好的APP最好支持90%设备,由于不同版本系统提供的API可能不同,所以了解不同版本间系统差异很重要,这样才能更好的适配更多的智能设备。你的应用足不足够健壮要看你的应用在主流版本运行是否流畅。这篇文章记录开发过程中遇到的相对重要以及常用的适配方案,希望对读者有所帮助。 Android 版本号及对应的版本名 版本号 版本名 中文名 ...

博由心生,福泽一生 6715

【Docker】如何让docker容器正常使用nvidia显卡

描述了如何在docker容器中使用英伟达显卡的过程和问题解决方法。

NameLoadingFailed的博客 8372

SOC估算方法之(OCV-SOC+安时积分法)

此方法主要参考。

m0_61973119的博客 935

别再乱申请MANAGE_EXTERNAL_STORAGE了!Android 11到13存储权限适配,这份避坑指南帮你搞定

本文详细解析了Android 11到13存储权限适配的关键问题,特别是MANAGE_EXTERNAL_STORAGE的滥用风险。通过分场景的权限选择策略、厂商差异处理和实战代码示例,帮助开发者构建合规的存储权限流程,确保应用顺利通过Google Play审核。

weixin_30443813的博客 468

Redhawk:什么是timing window?

STA timing file中timing window的作用和计算方式

m0_61544122的博客 1万+

Android存储权限演进与文件读写适配:从运行时权限到分区存储的完整解决方案

在Android应用开发中,文件存储与访问是基础且关键的技术环节。其核心原理涉及操作系统对应用数据隔离与用户隐私保护机制的演进,从早期的粗放式文件系统访问,逐步发展为基于权限沙盒的精细化管控。这一演进的技术价值在于平衡了应用功能需求与系统安全性,防止恶意应用随意访问用户敏感数据。在实际应用场景中,开发者常需处理用户日志保存、媒体文件导出等需求,但不同Android版本间的权限差异常导致兼容性问题。本文聚焦于Android存储权限的完整演进路径,特别是针对Scoped Storage(分区存储)和MANAGE

weixin_30730053的博客 303

6.3 节深度拆解:Hermes Agent 多 Agent 协同执行链路的 4 层设计逻辑

拆解 Hermes 多 Agent 协同的 4 层工程化设计(协议层、编排层、执行层、适配层),聚焦协议层的强约束消息 Schema 如何解决 Agent 间语义不一致问题,并提供 `soul.md` 配置、GLM-4.7Flash 结构化输出验证及 v0.13.0/v0.14.0 版本实操避坑指南

weixin_42520239的博客 122

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an &ldquo;advanced algorithms&rdquo; book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

突破Android版本壁垒:GmsCore从Android 10到15的无缝适配指南

你是否还在为GmsCore在不同Android版本上的兼容性问题头疼?从Android 10的分区存储到Android 15的权限强化,每个版本更新都可能让你的应用陷入崩溃。本文将系统梳理5代Android系统的适配要点,提供经过验证的配置方案和代码示例,让你的GmsCore集成之路不再坎坷。 ## 核心适配框架概览 GmsCore作为Google Play Services的开源替代方案,其...

gitblog_00777的博客 1104

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

别再乱申请MANAGE_EXTERNAL_STORAGE了!Android 11到13存储权限适配保姆级避坑指南

本文详细解析了Android 11到13存储权限适配的关键要点,特别强调避免滥用MANAGE_EXTERNAL_STORAGE权限。提供了从MediaStore API到存储访问框架(SAF)的合规替代方案,并分享多版本兼容策略和Google Play过审技巧,帮助开发者高效解决存储权限问题。

weixin_30681615的博客 207

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Android各个版本存储权限适配与文件写入

【代码】Android各个版本存储权限适配与文件写入。

sig321的专栏 433

从Android 1.0到Android 11:SDK版本演进史与开发适配全攻略

本文系统梳理了Android系统从1.0到11的SDK版本演进历程,重点解析了minSdkVersion、targetSdkVersion和compileSdkVersion三大关键配置的协同作用与适配策略。文章提供了针对分区存储、后台权限等新特性的实战适配方案,旨在帮助开发者构建兼顾兼容性与先进性的健壮应用架构。

weixin_29218963的博客 538

Android数据存储方案全解析:从基础到高级实践

数据存储是移动应用开发的核心技术之一,Android系统提供了多样化的存储机制以满足不同场景需求。从技术原理上看,Android存储体系基于Linux文件系统实现,通过沙箱机制保障应用数据安全。开发者常用的关键技术包括SharedPreferences键值存储、Room数据库以及文件系统API,这些方案在数据安全性、访问效率和存储容量上各有特点。随着Android 10引入分区存储(Scoped Storage)机制,存储访问模式发生了重大变革,开发者需要掌握MediaStore API和存储访问框架(SA

weixin_33979203的博客 310
上一篇: Android Q & Android 11存储适配(二) FileOperator文件管理框架
风之旅人、
博客等级 码龄11年 5粉丝 15原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值