Android 之工作记录 访问app 无权限的文件(复杂到app内部)

81 阅读4分钟
val path = GetFilePathFromUri.getFileAbsolutePath(Utils.getApp(), uri)  
if (path == null) {  
    AppToast.showShort("没有访问权限")  
}
package com.lib.base.utils;  
  
import static android.os.Environment.MEDIA_MOUNTED;  
  
import android.annotation.SuppressLint;  
import android.content.ContentResolver;  
import android.content.ContentUris;  
import android.content.Context;  
import android.database.Cursor;  
import android.net.Uri;  
import android.os.Build;  
import android.os.Environment;  
import android.os.FileUtils;  
import android.provider.DocumentsContract;  
import android.provider.MediaStore;  
import android.provider.OpenableColumns;  
import android.text.TextUtils;  
  
import androidx.annotation.NonNull;  
import androidx.annotation.Nullable;  
import androidx.annotation.RequiresApi;  
  
  
import com.lib.base.common.AppToast;  
  
import java.io.BufferedInputStream;  
import java.io.BufferedOutputStream;  
import java.io.File;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.InputStream;  
import java.io.OutputStream;  
import java.util.regex.Matcher;  
import java.util.regex.Pattern;  
  
public class GetFilePathFromUri {  
  
/**  
* 文件路径名称  
*/  
public static String dirPathName = "appFiles";  
  
/**  
* 判断手机的外部存储是否有,如果没有就用内部存储  
*  
* @param context  
* @param dir  
* @return  
*/  
public static String getFileDirPath(Context context, String dir) {  
    String directoryPath = "";  
    if (MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {//判断外部存储是否可用  
        directoryPath = context.getExternalFilesDir(dir).getAbsolutePath();  
    } else {//没外部存储就使用内部存储  
        directoryPath = context.getFilesDir() + File.separator + dir;  
    }  
    File file = new File(directoryPath);  
        if (!file.exists()) {//判断文件目录是否存在  
        file.mkdirs();  
    }  
    return directoryPath;  
}  
  
/**  
* 根据Uri获取文件绝对路径,解决Android4.4以上版本Uri转换 兼容Android 10  
*  
* @param context  
* @param imageUri  
*/  
public static String getFileAbsolutePath(Context context, Uri imageUri) {  
    if (context == null || imageUri == null) {  
    return null;  
}  
  
//4.4以下的版本  
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {  
    return getRealFilePath(context, imageUri);  
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT  
&& Build.VERSION.SDK_INT < Build.VERSION_CODES.Q  
&& DocumentsContract.isDocumentUri(context, imageUri)) {//大于4.4,小于10  
    if (isExternalStorageDocument(imageUri)) {  
    String docId = DocumentsContract.getDocumentId(imageUri);  
    String[] split = docId.split(":");  
    String type = split[0];  
    if ("primary".equalsIgnoreCase(type)) {  
    return Environment.getExternalStorageDirectory() + "/" + split[1];  
}  
} else if (isDownloadsDocument(imageUri)) {  
    String id = DocumentsContract.getDocumentId(imageUri);  
if (!TextUtils.isEmpty(id)) {  
//已经返回真实路径  
if (id.startsWith("raw:")) {  
    return id.replaceFirst("raw:", "");  
}  
}  
String[] contentUriPrefixesToTry = new String[]{  
    "content://downloads/public_downloads",  
    "content://downloads/all_downloads",  
    "content://downloads/my_downloads",  
};  
//Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));  
for (String contentUriPrefix : contentUriPrefixesToTry) {  
    Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));  
try {  
    String path = getDataColumn(context, contentUri, null, null);  
if (path != null) {  
    return path;  
}  
} catch (Exception e) {  
    e.printStackTrace();  
}  
}  
return getDocumentFilePath(context, imageUri);  
// return getDataColumn(context, contentUri, null, null);  
} else if (isMediaDocument(imageUri)) {  
String docId = DocumentsContract.getDocumentId(imageUri);  
String[] split = docId.split(":");  
String type = split[0];  
Uri contentUri = null;  
if ("image".equals(type)) {  
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;  
} else if ("video".equals(type)) {  
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;  
} else if ("audio".equals(type)) {  
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;  
}  
String selection = MediaStore.Images.Media._ID + "=?";  
String[] selectionArgs = new String[]{split[1]};  
return getDataColumn(context, contentUri, selection, selectionArgs);  
}  
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {// MediaStore (and general) 大于等于10  
return uriToFileApiQ(context, imageUri);  
} else if ("content".equalsIgnoreCase(imageUri.getScheme())) {  
// Return the remote address  
if (isGooglePhotosUri(imageUri)) {  
return imageUri.getLastPathSegment();  
}  
if (Build.VERSION.SDK_INT >= 24) {  
return getFilePathFromUri(context, imageUri); //content 类型  
} else {  
return getDataColumn(context, imageUri, null, null);  
}  
}  
// File  
else if ("file".equalsIgnoreCase(imageUri.getScheme())) {  
return imageUri.getPath();  
}  
return null;  
}  
  
private static String getRealFilePath(final Context context, final Uri uri) {  
if (null == uri) {  
return null;  
}  
final String scheme = uri.getScheme();  
String data = null;  
if (scheme == null) {  
data = uri.getPath();  
} else if (ContentResolver.SCHEME_FILE.equals(scheme)) {  
data = uri.getPath();  
} else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {  
String[] projection = {MediaStore.Images.ImageColumns.DATA};  
Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);  
if (null != cursor) {  
if (cursor.moveToFirst()) {  
int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);  
if (index > -1) {  
data = cursor.getString(index);  
}  
}  
cursor.close();  
}  
}  
return data;  
}  
  
  
/**  
* @param uri The Uri to check.  
* @return Whether the Uri authority is ExternalStorageProvider.  
*/  
private static boolean isExternalStorageDocument(Uri uri) {  
return "com.android.externalstorage.documents".equals(uri.getAuthority());  
}  
  
/**  
* @param uri The Uri to check.  
* @return Whether the Uri authority is DownloadsProvider.  
*/  
private static boolean isDownloadsDocument(Uri uri) {  
return "com.android.providers.downloads.documents".equals(uri.getAuthority());  
}  
  
private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {  
Cursor cursor = null;  
String column = MediaStore.Images.Media.DATA;  
String[] projection = {column};  
try {  
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);  
if (cursor != null && cursor.moveToFirst()) {  
int index = cursor.getColumnIndexOrThrow(column);  
return cursor.getString(index);  
}  
} catch (Exception e){  
e.printStackTrace();  
}finally {  
if (cursor != null) {  
cursor.close();  
}  
}  
return null;  
}  
  
/**  
* @param uri The Uri to check.  
* @return Whether the Uri authority is MediaProvider.  
*/  
private static boolean isMediaDocument(Uri uri) {  
return "com.android.providers.media.documents".equals(uri.getAuthority());  
}  
  
/**  
* @param uri The Uri to check.  
* @return Whether the Uri authority is Google Photos.  
*/  
private static boolean isGooglePhotosUri(Uri uri) {  
return "com.google.android.apps.photos.content".equals(uri.getAuthority());  
}  
  
  
/**  
* Android 10 以上适配 另一种写法  
*  
* @param context  
* @param uri  
* @return  
*/  
@SuppressLint("Range")  
private static String getFileFromContentUri(Context context, Uri uri) {  
if (uri == null) {  
return null;  
}  
String filePath;  
String[] filePathColumn = {MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.DISPLAY_NAME};  
ContentResolver contentResolver = context.getContentResolver();  
Cursor cursor = contentResolver.query(uri, filePathColumn, null,  
null, null);  
if (cursor != null) {  
cursor.moveToFirst();  
try {  
filePath = cursor.getString(cursor.getColumnIndex(filePathColumn[0]));  
return filePath;  
} catch (Exception e) {  
} finally {  
cursor.close();  
}  
}  
return "";  
}  
  
/**  
* Android 10 以上适配  
*  
* @param context  
* @param uri  
* @return  
*/  
@RequiresApi(api = Build.VERSION_CODES.Q)  
private static String uriToFileApiQ(Context context, Uri uri) {  
File file = null;  
//android10以上转换  
if (uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {  
file = new File(uri.getPath());  
} else if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {  
//把文件复制到沙盒目录  
ContentResolver contentResolver = context.getContentResolver();  
Cursor cursor = contentResolver.query(uri, null, null, null, null);  
if (cursor.moveToFirst()) {  
@SuppressLint("Range")  
String displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));  
try {  
InputStream is = contentResolver.openInputStream(uri);  
// File file1 = new File(context.getExternalCacheDir().getAbsolutePath()+"/"+System.currentTimeMillis());  
// if (!file1.exists()) {  
// file1.mkdir();  
// }  
String dirPath = getFileDirPath(context, dirPathName);  
File cache = new File(dirPath, displayName);  
FileOutputStream fos = new FileOutputStream(cache);  
FileUtils.copy(is, fos);  
file = cache;  
fos.close();  
is.close();  
} catch (IOException e) {  
e.printStackTrace();  
}  
}  
}  
return file.getAbsolutePath();  
}  
  
private static String getFilePathFromUri(Context context, Uri uri) {  
String realFilePath = getRealFilePath(context, uri); //防止获取不到真实的地址,因此这里需要进行判断  
if (!TextUtils.isEmpty(realFilePath)) {  
return realFilePath;  
}  
// File filesDir = context.getApplicationContext().getFilesDir();  
String filesDir = getFileDirPath(context,dirPathName);  
String fileName = getFileName(uri);  
if (!TextUtils.isEmpty(fileName)) {  
File copyFile1 = new File(filesDir + File.separator + fileName);  
copyFile(context, uri, copyFile1);  
return copyFile1.getAbsolutePath();  
}  
return null;  
}  
  
private static String getFileName(Uri uri) {  
if (uri == null) {  
return null;  
}  
String fileName = null;  
String path = uri.getPath();  
int cut = path.lastIndexOf('/');  
if (cut != -1) {  
fileName = path.substring(cut + 1);  
}  
return fileName;  
}  
  
public static String getFileName(@NonNull Context context, Uri uri) {  
String mimeType = context.getContentResolver().getType(uri);  
String filename = null;  
  
if (mimeType == null && context != null) {  
filename = getFileName(uri);  
} else {  
  
Cursor returnCursor = context.getContentResolver().query(uri, null,  
null, null, null);  
if (returnCursor != null) {  
// Available columns: [document_id, mime_type, _display_name, summary, last_modified, flags, _size]  
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);  
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);  
int dIdIndex = returnCursor.getColumnIndexOrThrow("document_id");  
int mimeTypeIndex = returnCursor.getColumnIndexOrThrow("mime_type");  
int summaryIndex = returnCursor.getColumnIndexOrThrow("summary");  
int lastModifiedIndex = returnCursor.getColumnIndexOrThrow("last_modified");  
int flagsIndex = returnCursor.getColumnIndexOrThrow("flags");  
returnCursor.moveToFirst();  
filename = returnCursor.getString(nameIndex);  
long size = returnCursor.getLong(sizeIndex);  
String document_id = returnCursor.getString(dIdIndex);  
String mimeTyped = returnCursor.getString(mimeTypeIndex);  
String summary = returnCursor.getString(summaryIndex);  
String lastModified = returnCursor.getString(lastModifiedIndex);  
String flags= returnCursor.getString(flagsIndex);  
returnCursor.close();  
}  
}  
  
return filename;  
}  
  
public static File getDocumentCacheDir(@NonNull Context context) {  
String directoryPath = "";  
if (MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {//判断外部存储是否可用  
directoryPath = context.getExternalFilesDir(dirPathName).getAbsolutePath();  
} else {//没外部存储就使用内部存储  
directoryPath = context.getFilesDir() + File.separator + dirPathName;  
}  
File file = new File(directoryPath);  
if (!file.exists()) {//判断文件目录是否存在  
file.mkdirs();  
}  
return file;  
}  
  
@Nullable  
public static File generateFileName(@Nullable String name, File directory) {  
if (name == null) {  
return null;  
}  
  
File file = new File(directory, name);  
  
if (file.exists()) {  
String fileName = name;  
String extension = "";  
int dotIndex = name.lastIndexOf('.');  
if (dotIndex > 0) {  
fileName = name.substring(0, dotIndex);  
extension = name.substring(dotIndex);  
}  
  
int index = 0;  
  
while (file.exists()) {  
index++;  
name = fileName + '(' + index + ')' + extension;  
file = new File(directory, name);  
}  
}  
try {  
if (!file.createNewFile()) {  
return null;  
}  
} catch (IOException e) {  
  
return null;  
}  
return file;  
}  
  
/**  
* 复制 没有权限的 文件到自己的文件系统下  
* @param context  
* @param uri  
* @return  
*/  
private static String getDocumentFilePath(@NonNull Context context, Uri uri){  
String fileName = getFileName(context, uri);  
File cacheDir = getDocumentCacheDir(context);  
File file = generateFileName(fileName, cacheDir);  
String destinationPath = null;  
if (file != null) {  
destinationPath = file.getAbsolutePath();  
saveFileFromUri(context, uri, destinationPath);  
}  
return destinationPath;  
}  
  
private static void saveFileFromUri(Context context, Uri uri, String destinationPath) {  
InputStream is = null;  
BufferedOutputStream bos = null;  
try {  
is = context.getContentResolver().openInputStream(uri);  
bos = new BufferedOutputStream(new FileOutputStream(destinationPath, false));  
byte[] buf = new byte[1024];  
is.read(buf);  
do {  
bos.write(buf);  
} while (is.read(buf) != -1);  
} catch (IOException e) {  
AppToast.INSTANCE.showLong("找到到的文件,文件可能已经被删除");  
e.printStackTrace();  
} finally {  
try {  
if (is != null) {  
is.close();  
}  
if (bos != null) {  
bos.close();  
}  
} catch (IOException e) {  
e.printStackTrace();  
}  
}  
}  
  
private static void copyFile(Context context, Uri srcUri, File dstFile) {  
try {  
InputStream inputStream = context.getContentResolver().openInputStream(srcUri);  
if (inputStream == null) {  
return;  
}  
OutputStream outputStream = new FileOutputStream(dstFile);  
copyStream(inputStream, outputStream);  
inputStream.close();  
outputStream.close();  
} catch (Exception e) {  
e.printStackTrace();  
}  
}  
  
  
private static int copyStream(InputStream input, OutputStream output) {  
final int BUFFER_SIZE = 1024 * 2;  
byte[] buffer = new byte[BUFFER_SIZE];  
BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE);  
BufferedOutputStream out = new BufferedOutputStream(output, BUFFER_SIZE);  
int count = 0, n = 0;  
try {  
while ((n = in.read(buffer, 0, BUFFER_SIZE)) != -1) {  
out.write(buffer, 0, n);  
count += n;  
}  
out.flush();  
} catch (Exception e) {  
} finally {  
try {  
out.close();  
in.close();  
} catch (Exception e) {  
}  
}  
return count;  
}  
  
/**  
* 获取字符串中的数值  
* @param str  
* @return  
*/  
public static String checkNum(String str) {  
StringBuilder builder=new StringBuilder();  
String regEx="(\\d+(\\.\\d+)?)";  
Pattern p = Pattern.compile(regEx);  
Matcher m = p.matcher(str);  
while (m.find()) {//当符合正则表达式定义的条件时  
builder.append(m.group());  
}  
return builder.toString();  
}  
  
  
}