问题描述
当 targetSdkVersion 设置高于 29 后,分享拷贝失败
问题分析
android 10 以后采用分区存储权限说明
- 对权限申请做限制,否则在 android10 以下的设备会获取权限失败
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
设备 | 权限添加 maxSdkVersion=“28” | 未添加 maxSdkVersion=“28” |
---|---|---|
android 6 | yes | no |
android 10 | yes | yes |
android 11 | yes | yes |
- 对 android 10 以后不进行申请 WRITE_EXTERNAL_STORAGE,会一直返回失败
相对路径于 DCIM 会导致一些手机拷贝失败
已知问题设备:小米 8
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM)
解决方案
修改 compileSdkVersion 和 targetSdkVersion 为 29
权限声明
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
核心 java 代码
public static boolean saveVideoToAlbumIfNeed(final String path, final String pathToAlbum) {
File file = new File(path);
Uri uri = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && getTargetSdkVersion() >= Build.VERSION_CODES.Q) {
// 通过插入到相册的方案
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.TITLE, file.getName());
values.put(MediaStore.MediaColumns.DISPLAY_NAME, file.getName());
values.put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4");
// values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM);
ContentResolver contentResolver = currentActivity.getContentResolver();
uri = contentResolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
if(uri == null){
Log.d(TAG, "Insert file to resolver failed.");
return false;
}
// 拷贝到指定uri,如果没有这步操作,android11不会在相册显示
try {
OutputStream out = currentActivity.getContentResolver().openOutputStream(uri);
FileUtil.copyFile(path, out);
} catch (IOException e) {
e.printStackTrace();
}
} else {
String savePath = null;
savePath = getSDCardPath() + "/" + pathToAlbum;
// 文件已存在不重新拷贝
File saveFile = new File(savePath);
if (saveFile.exists()) {
return true;
}
// 如果目录不存在先创建
String saveRoot = savePath.substring(0, savePath.lastIndexOf("/"));
File fileRoot = new File(saveRoot);
if (!fileRoot.exists()) {
fileRoot.mkdir();
}
// 拷贝文件
if (! FileUtil.copyFile(path, savePath)) {
Log.d(TAG, "Copy file to sdcard fail.");
return false;
}
uri = Uri.fromFile(saveFile);
}
// 通知刷新相册
Intent scanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
scanIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
scanIntent.setData(uri);
currentActivity.sendBroadcast(scanIntent);
return true;
}
public static boolean copyFile(String oldPath, OutputStream out) {
Log.d(TAG, "oldPath = " + oldPath);
try {
int bytesum = 0;
int byteread = 0;
File oldfile = new File(oldPath);
if (oldfile.exists()) {
// 读入原文件
InputStream inStream = new FileInputStream(oldPath);
byte[] buffer = new byte[1444];
while ((byteread = inStream.read(buffer)) != -1) {
bytesum += byteread; //字节数 文件大小
System.out.println(bytesum);
out.write(buffer, 0, byteread);
}
inStream.close();
out.close();
return true;
}
else {
Log.w(TAG, String.format("文件(%s)不存在。", oldPath));
}
}
catch (Exception e) {
Log.e(TAG, "复制单个文件操作出错");
e.printStackTrace();
}
return false;
}