场景

从微信打开KML文件,选择自家开发的App打开,发现能够读取读取文件路径,但是在操作的时候显示错误

java.io.FileNotFoundException: /storage/emulated/0/Android/data/com.tencent.mm/MicroMsg/Download/xxx.kml: open failed: EACCES (Permission denied)

其中AS工程已经正确配置存储权限,并且application已经配置android:requestLegacyExternalStorage="true"

因项目在Android10上能够正确运行,但是在Android 11及以上有异常,猜想是因为Android 11做了一些限制。

因此采用另外一种方法:先把真实路径从获取到的Uri对象中解析出来,然后把文件拷贝一份到App目录下面,再对这个文件进行解析

/**
* 从Uri获取真实路径
* @param context
* @param uri
* @return
*/
public static String getFPUriToPath(Context context, Uri uri) {
try {
List<PackageInfo> packs = context.getPackageManager().getInstalledPackages(PackageManager.GET_PROVIDERS);
if (packs != null) {
String fileProviderClassName = FileProvider.class.getName();
for (PackageInfo pack : packs) {
ProviderInfo[] providers = pack.providers;
if (providers != null) {
for (ProviderInfo provider : providers) {
if (uri.getAuthority().equals(provider.authority)) {
// if (provider.name.equalsIgnoreCase(fileProviderClassName)) {
Class<FileProvider> fileProviderClass = FileProvider.class;
try {
Method getPathStrategy = fileProviderClass.getDeclaredMethod("getPathStrategy", Context.class, String.class);
getPathStrategy.setAccessible(true);
Object invoke = getPathStrategy.invoke(null, context, uri.getAuthority());
if (invoke != null) {
String PathStrategyStringClass = FileProvider.class.getName() + "$PathStrategy";
Class<?> PathStrategy = Class.forName(PathStrategyStringClass);
Method getFileForUri = PathStrategy.getDeclaredMethod("getFileForUri", Uri.class);
getFileForUri.setAccessible(true);
Object invoke1 = getFileForUri.invoke(invoke, uri);
if (invoke1 instanceof File) {
return ((File) invoke1).getAbsolutePath();
}
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
break;
// }
// break;
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}

/**
* 用流拷贝文件一份到自己APP目录下
*
* @param context
* @param uri
* @param fileName
* @return
*/
public static String getPathFromInputStreamUri(Context context, Uri uri, String fileName) {
InputStream inputStream = null;
String filePath = null;

if (uri.getAuthority() != null) {
try {
inputStream = context.getContentResolver().openInputStream(uri);
File file = createTemporalFileFrom(context, inputStream, fileName);
filePath = file.getPath();

} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

return filePath;
}

private static File createTemporalFileFrom(Context context, InputStream inputStream, String fileName)
throws IOException {
File targetFile = null;

if (inputStream != null) {
int read;
byte[] buffer = new byte[8 * 1024];
//自己定义拷贝文件路径
targetFile = new File(context.getCacheDir(), fileName);
if (targetFile.exists()) {
targetFile.delete();
}
OutputStream outputStream = new FileOutputStream(targetFile);

while ((read = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, read);
}
outputStream.flush();

try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}

return targetFile;
}