Android 10 申请动态权限以后仍然无法读写文件的解决方案

如果 targetSdkVersion = 29, 即便是在判断申请读写动态权限成功以后,也无法对外置卡路径(ExternalStorage)进行读写,可以使用以下代码进行测试

 String path = Environment.getExternalStorageDirectory().getPath() + "/Download";
 File file = new File(path);
 if (file.exists()) {
     if (file.canRead()) {
         Log.e("AAA", "onCreate: file.canRead true");
     } else {
         Log.e("AAA", "onCreate: file.canRead false");
     }
 }

针对这个问题,以下是几种妥协的解决方法:

  1. 如应用非必须以 29 为target, 可以将targetSdkVersion 置为 29 以下,如 targetSdkVersion = 28,这样走动态权限就正常了。

  2. 仍然以targetSdkVersion 为 29,但是可在AndroidManifest.xml中application标签添加 android:requestLegacyExternalStorage="true",这样也可以,但是注意compileVersion也必须同时为 29 :

    android {
        compileSdkVersion 29
        buildToolsVersion "29.0.3"
        
        defaultConfig {
            applicationId "com.android.test.lib"
            minSdkVersion 19
            targetSdkVersion 29
            versionCode 1
            versionName "1.0"
        }
        ...
    }
    

    这种方案暂时有效,但是官方在未来的版本中可能去掉这个设置。

  3. 如果你是存文件,并且只是应用内自己访问,可以将文件存在私有目录下,可以使用 getExternalFilesDirgetExternalCacheDir 等方法, 以下我列出了几种常用的私有目录文件访问方式获取到的对应路径:

    方法获取的路径
    getExternalFilesDir(null)根目录下的 Android / data / [your_packageName] / files
    getExternalCacheDir()根目录下的 Android / data / [your_packageName] / files / cache
    getExternalMediaDirs()根目录下的 Android / media / [your_packageName]
    getFilesDir()/ data / user / 0 / [your_packageName] / files
    getCacheDir()/ data / user / 0 / [your_packageName] / cache
    openFileOutput(“aaa.txt”, Context.MODE_PRIVATE)data / data / [your_packageName] / files / aaa.txt

    其中,getExternalFilesDir可以传一个名字,获取对应类型的文件夹:

      // /storage/emulated/0/Android/data/[your_packageName]/files/Pictures
      File dir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); 
    
      // /storage/emulated/0/Android/data/[your_packageName]/files/Documents
      File dir = getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
      
      // /storage/emulated/0/Android/data/[your_packageName]/files/Movies
      File dir = getExternalFilesDir(Environment.DIRECTORY_MOVIES);
    

    但是这种方法只能访问应用自己的应用目录,不能访问除此之外的其他公共目录,这种被称为App-specific目录。访问公共目录或其他APP的App-specific目录,只能通过MediaStore、SAF、或者其他APP 提供的ContentProvider、FileProvider等访问。

  4. 使用 MediaStore,也就是通过 ContentResolver去访问系统的多媒体数据库,获取对应的Uri进行后续的读写操作,拿到Uri后,可以进一步转成输入流进行转储等。但是这种只针对多媒体类型的文件(图片、视频、音频),如果是其他普通的文件就不行了。

  5. 使用 SAF ,这种是Google官方提供的方法来访问存储卡上的其他文件的方法,看了一下,这个大概是一个文件选择器,启动之后让用户去选择特定的文件或文件夹,最终回调的结果也是Uri,拿到Uri后再进行读写删操作。

另外,需要注意的一点是,如果你的应用已经有线上版本,targetSdkVersion 升级一定慎重,因为targetSdkVersion 只能升级不能降级(降级会导致应用无法安装)。

更多关于Android 10 文件读写适配的指导可以参考:
Android 10 适配攻略小结
Android Q版本应用兼容性适配指导

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

川峰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值