一、前言

从Android Q(即 Android 10)开始,应用访问外部存储的私有目录(即Context.getExternalFilesDir())不需要申请READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE权限。同时,正常情况下,就算应用有申请READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE权限,也只能访问外部存储的私有目录,若是访问了除了私有目录之外的其他外部储存,会抛出FileNotFoundException异常

二、异常现象

1、若是你的应用设置 targetSdkVersion = 29,在android Q的手机访问非私有目录的外部储存时,即使是有读写外存的权限,依然会抛出了类似下面的FileNotFoundException异常:

java.io.FileNotFoundException: /storage/emulated/0/min77/51850812e89ff8ead2002c15ebf417ac: open failed: EACCES (Permission denied)    at libcore.io.IoBridge.open(IoBridge.java:496)    at java.io.FileInputStream.<init>(FileInputStream.java:159)    at com.sswl.sdk.utils.Logger.readFileStream(Logger.java:107)    at com.sswl.sdk.utils.Logger.readProterties(Logger.java:82)    at com.sswl.sdk.utils.Logger.loadLogConfig(Logger.java:26)    at com.sswl.sdk.utils.Logger.w(Logger.java:67)    at com.sswl.sdk.network.http.NetworkRequest.doPostRequest(NetworkRequest.java:68)    at com.sswl.sdk.network.http.NetworkRequest.doPostRequest(NetworkRequest.java:47)    at com.sswl.sdk.network.http.NetworkRequest.doRequest(NetworkRequest.java:35)    at com.sswl.sdk.network.http.NetworkRequest.doRequest(NetworkRequest.java:28)    at com.sswl.sdk.network.http.HttpRequestAsyncTask.doInBackground(HttpRequestAsyncTask.java:65)    at com.sswl.sdk.network.http.HttpRequestAsyncTask.doInBackground(HttpRequestAsyncTask.java:21)    at android.os.AsyncTask$3.call(AsyncTask.java:378)    at java.util.concurrent.FutureTask.run(FutureTask.java:266)    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)    at java.lang.Thread.run(Thread.java:919)Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)    at libcore.io.Linux.open(Native Method)    at libcore.io.ForwardingOs.open(ForwardingOs.java:167)    at libcore.io.BlockGuardOs.open(BlockGuardOs.java:252)    at libcore.io.ForwardingOs.open(ForwardingOs.java:167)    at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7419)    at libcore.io.IoBridge.open(IoBridge.java:482)... 16 more

三、异常分析

1、Android Q只允许应用读取自己外部储存的私有目录,这个不需要读写外存权限;
2、当应用被授予读写外存的权限之后,也只能读取以下目录的文件:存储在MediaStore.Images的图片存储在MediaStore.Video的视频文件存储在MediaStore.Audio的音频文件

3、要是想要读取上述之外的外部存储文件,就会抛出FileNotFoundException异常

四、解决方案

1、方案一:把应用的 targetSdkVersion设置为29以下即可
2、方案二:在AndroidManifest.xml的Application节点设置android:requestLegacyExternalStorage=“true”

 <!-- This attribute is "false" by default on apps targeting       Android 10 or higher. -->  <application android:requestLegacyExternalStorage="true" ... >    ...  </application>

五、延伸问题

1、要是使用方案二来解决上述问题,正常出包是没问题的,但是要是使用apktool 反编译回编译,就会出现找不到android:requestLegacyExternalStorage属性异常,目前apktool最新版本是2.4.0,估计后续的版本会兼容Android Q
2、解决方案:
1)先在Android Studio中新建一个API 29的模拟器

2)运行创建好的模拟器

3)使用命令adb pull 从模拟器的system/framework 提取出framework-res.apk到电脑本地

adb pull system/framework/framework-res.apk C:\Users\Administrator.USER-20190314HO\Desktop\1

4)将从模拟器中拉取出来的framework-res.apk改名为1.apk,然后拷贝到:C:\Users\当前用户名\AppData\Local\apktool\framework目录下,然后重新用apktool回编译即可
【备注】:若是有androidQ的手机,也可以直接从手机上拉取

更多相关文章

  1. Android(安卓)CTS 测试研究之二
  2. Android(安卓)studio assets error:前言中不允许有内容
  3. 安装 Android(安卓)1.6 SDK
  4. Android(安卓)读取U盘或SD卡中的所有.txt文件
  5. android 获取路径目录方法以及判断目录是否存在,创建目录
  6. Android(安卓)高级控件ExpandabledListView详解
  7. android开发环境配置
  8. Android(安卓)build system note
  9. android ndk 使用第三方静态库

随机推荐

  1. android构建自定义的视图组件onMeasure
  2. Android中资源文件(非代码部分)的使用概
  3. Android(安卓)播放网络视频,视频流的处理
  4. Android学习笔记(36):Android的两种事件
  5. 云时代下,设备的移动性到底对企业有什么影
  6. 【Android】Android(安卓)手机杀进程并不
  7. Android粘性菊花—-粘性LoadingView你所
  8. mars Android视频第14讲中代码出现的错误
  9. Android(安卓)错误:at java.lang.reflect.
  10. 为什么说模仿是最好的学习方法?