96SEO 2026-08-08 11:31 0
在项目中经常看到日志里堆满了第三方 SDK 的文件权限警告。升级库又懒得动,甚至有的库已经停止维护。于是只能先把 Android 文件读写、分享的方案理清楚,等真的卡住再去源码层面自行修改。
| 目录 | 示例方法 | 权限需求 | 适用场景 | 是否推荐 |
|---|---|---|---|---|
| 内部私有目录 | /data/data/包名/files/ | 无需任何存储权限 | 配置、缓存、数据库、Token 等敏感数据 | 推荐看看 |
| 内部缓存目录 | /data/data/包名/cache/ | 无需权限 | 临时文件、网络缓存、图片压缩产物等可随时清理的数据 | 推荐 |
| 外部专属目录 | /storage/emulated/0/Android/data/包名/files/ | 无需传统存储权限 | 大文件、日志、导出临时文件等使用者不必直接看到的内容 | 推荐 |
| * 注意:Android 10起必须使用 Scoped Storage,targetSdkVersion ≥ 29 时不再支持直接操作公共方法。 | ||||
| 公共媒体目录 Pictures、Movies、Music 等标准公共文件夹 + MediaStore 接口。 | ||||
val filesDir = context.filesDir // /data/data/.../files/
val cacheDir = context.cacheDir // /data/data/.../cache/
val externalFiles = context.getExternalFilesDir // /Android/data/.../files/
val externalCache = context.externalCacheDir // /Android/data/.../cache/
这些方法在所有 Android 版本均可直接读写。老实说,

Android 13 及以上:
Android 12 以下:
官方说明的观点是。读取其他 App 创建的媒体文件必须声明对应媒体读取权限;而自己通过 MediaStore 写入的媒体文件则无需额外权限。
SFA 在 Android 4.4+ 可用。且在 Android 10+ 完全不需要传统存储权限,是解决「第三方 SDK 权限冲突」的优先考虑方案。
fun savePrivateFile {
val file = File
file.writeText
}
fun readPrivateFile: String =
File.takeIf { it.exists }?.readText,: ""
fun saveExternalLog: File?{
val dir = context.getExternalFilesDir?: return null
if ) dir.mkdirs
val file = File
file.writeText
return file
}
# 示例方法:
# /storage/emulated/0/Android/data/com.example.app/files/logs/app.log
fun saveImageToGallery(
context: Context。displayName: String,bitmapData: ByteArray
): Uri?{
val resolver = context.contentResolver
val values = ContentValues.apply {
put
put
if {
put
put
}
}
val uri = resolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,values
)?其实,的观点是,return null
resolver.openOutputStream?.use { it.write }
if {
values.clear
values.put
resolver.update
}
return uri
}
Kotlin – 推荐方式
fun saveFileToDownloads(
context: Context。fileName: String,mimeType: String,data: ByteArray
): Uri?{
if {
val resolver = context.contentResolver
val values = ContentValues.apply {
put
put
put(MediaStore.Downloads.RELATIVE_PATH。Environment.DIRECTORY_DOWNLOADS + "/MyApp")
put
}
val uri = resolver.insert(
MediaStore.Downloads.EXTERNAL_CONTENT_URI,values
)?这方面,return null
resolver.openOutputStream?.use { it.write }
values.clear
values.put
resolver.update
return uri
}
return null // 对低版本请走 legacy 方法或 SAF
}
@Suppress
fun saveFileToDownloadsLegacy: File {
val dir = Environment.getExternalStoragePublicDirectory
if ) dir.mkdirs
val file = File
file.writeBytes
return file
}
# 必须在 Manifest 中声明 WRITE_EXTERNAL_STORAGE 并在运行时申请该权限。
# 示例:
#
// 打开程序保存对话框,让使用者挑选位置
fun launchCreateDocument {
val intent = Intent.apply {
addCategory
type = "application/pdf"
putExtra
}
activity.startActivityForResult
}
// 将字符串写入使用者选中的 Uri
fun writeStringToUri {
uri?这方面,return
context.contentResolver.openOutputStream?.use { it.write) }
}
fun launchOpenDocument {
val intent = Intent.apply {
addCategory
type = "*/*"
}
activity.startActivityForResult
}
fun readBytesFromUri: ByteArray =
if ByteArray
else context.contentResolver.openInputStream?.use { it.readBytes }?: ByteArray
fun requestStoragePermission {
when {
Build.VERSION.SDK_INT>= Build.VERSION_CODES.TIRAMISU -> {
// Android 13+ 已经细分为 READ_MEDIA_*
ActivityCompat.requestPermissions(
activity,arrayOf(
Manifest.permission.READ_MEDIA_IMAGES,Manifest.permission.READ_MEDIA_VIDEO,Manifest.permission.READ_MEDIA_AUDIO
),REQUEST_CODE_STORAGE
)
}
Build.VERSION.SDK_INT>= Build.VERSION_CODES.M -> {
ActivityCompat.requestPermissions(
activity,arrayOf。REQUEST_CODE_STORAGE
)
}
else -> { /* 不需要运行时请求 */ }
}
}
"FileProvider 不负责把文件写进去,它只负责把已经存在的本地方法包装成安全的 content:// URI 并授予目标 App 临时访问权。" 以下场景必须使用它:
> h three= ""id= provider-config-xml"">res/xml/file_paths.xml:
pre code= ' language - xml '>& lt?xml version ="1.0" encoding ="utf-8"?>
<,其实,/ paths & gt; h # 十 、完整代码示例——分享位于 APP 专属目录下的 PDF 文件
pre code= ' language - kotlin '> // 假设 pdf 位于: getExternalFilesDir/test.pdf val pdfFile = File,"test.pdf") val pdfUri = FileProvider.getUriForFile( this,"${packageName}.fileprovider"。pdfFile )
val intent = Intent.apply { setDataAndType addFlags } startActivity
h two id= 'relation-with-media-store-saf' strong="">十一 、FileProvider 与 MediaStore / SAF 的关系表:
| '方案' |
|---|
整理完后你会发现大部分业务都可以避开繁琐的传统存储权限,只要合理选择「私有」「专属」「MediaStore」或「SAF」四种方案即可。如果真的碰到第三方 SDK 报错无法兼容,再回头去源码层面改成基于 {@link ContentResolver} 的方式或者自行实现一个轻量级 {@link FileProvider} 来解决冲突。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback