android - 有没有办法在 Android 11 上将图像保存到没有 SAF 的 USB 记忆棒?
问题描述
我想将使用相机拍摄的图像从我的应用程序直接保存到插入手机的 USB 记忆棒中。有没有办法在不要求用户从 SAF 中选择目录的情况下做到这一点?我想使用范围存储,因为我的目标是 Android 11 及更高版本。
没有连接到设备的 SD 卡。
我可以使用此代码将文件存储在 Android 10 上的 USB 记忆棒上,但不能在 Android 11 上
// I pass the image taken from the camera by parameter
private void legacyToUsb(File image){
File[] externalStorageVolumes = ContextCompat.getExternalFilesDirs(getApplicationContext(), null);
String path = null;
for (File externalDir : externalStorageVolumes) {
Log.d(TAG, "Found dir at : " + externalDir);
path = externalDir.getPath();
}
if (path == null) {
showToast("Failed to found mounted device");
return;
}
String fileName = mDateFormat.format(System.currentTimeMillis()) + ".jpg";
File destFile = new File(path, fileName);
showToast("Going to save data to " + destFile.getPath());
if (destFile == null)
showToast("Failed to open file");
FileOutputStream os;
String msg = "Successfully saved to " + destFile.getPath();
try{
byte[] imageData = getBytesFromFile(image);
os = new FileOutputStream(destFile);
os.write(imageData);
} catch (IOException e) {
e.printStackTrace();
msg = "Failed to save file : " + e.getMessage();
}
showToast(msg);
}
但是,在 Android 11 上不起作用(我无法在 USB 记忆棒内创建文件),因为getExternalFilesDirs()
没有给我 USB otg 的路径。
ContextCompat.getExternalFilesDirs(<context>)
返回:
安卓 10
Found dir at : /storage/emulated/10/Android/data/com.example.MyApp/files
Found dir at : /storage/4406-15E5/Android/data/com.example.MyApp/files //I'm using this one
安卓 11
Found dir at : /storage/emulated/0/Android/data/com.example.MyApp/files
据我了解,范围存储消除了通过这些功能访问可移动存储的可能性。所以我正在尝试另一种方式
private void scopedToUsb(File image){
ContentResolver resolver = getContentResolver();
String fileName = mDateFormat.format(System.currentTimeMillis());
ContentValues fileDetails = new ContentValues();
fileDetails.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
fileDetails.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
fileDetails.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
fileDetails.put(MediaStore.Images.Media.IS_PENDING, 1);
Set<String> volumeNames = MediaStore.getExternalVolumeNames(getApplicationContext());
String storageVolume = null;
// Get the first volume found here, it returns the hex with which the usb stick is identified
// in my case 4406-15e5
for (String volumeName : volumeNames){
storageVolume = volumeName;
Log.d(TAG, "Found volumeName : "+ volumeName);
break;
}
// I have tried here MediaStore.VOLUME_EXTERNAL and MediaStore.VOLUME_EXTERNAL_PRIMARY
// They both point to the same directory not in the usb stick
Uri collection = MediaStore.Images.Media.getContentUri(storageVolume);
Uri imageUri = resolver.insert(collection, fileDetails);
if(imageUri == null) {
showToast("Failed to insert image row to ContentResolver");
return;
}
Log.d(TAG, "Inserted, going to create ouput stream");
OutputStream out = null;
try {
out = resolver.openOutputStream(imageUri);
Bitmap bm = BitmapFactory.decodeFile(image.getAbsolutePath());
bm.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.close();
} catch (IOException e) {
e.printStackTrace();
showToast("Failed to sqve picture to Usb");
return;
}
showToast("Successfully saved to " + collection.getPath());
}
但我在这一行收到异常
Uri imageUri = resolver.insert(collection, fileDetails);
例外
java.lang.IllegalStateException: Failed to create directory: /mnt/media_rw/4406-15E5/Pictures/.pending-1621349186-2021-05-11-16-46-26-671.jpg
at android.os.Parcel.createExceptionOrNull(Parcel.java:2384)
at android.os.Parcel.createException(Parcel.java:2360)
at android.os.Parcel.readException(Parcel.java:2343)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:190)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:142)
at android.content.ContentProviderProxy.insert(ContentProviderNative.java:549)
at android.content.ContentResolver.insert(ContentResolver.java:2177)
at android.content.ContentResolver.insert(ContentResolver.java:2138)
at com.example.MyApp.MainActivity.scopedToUsb(MainActivity.java:368)
at com.example.MyApp.MainActivity.saveToUsb(MainActivity.java:294)
at com.example.MyApp.MainActivity.access$000(MainActivity.java:72)
at com.example.MyApp.MainActivity$1.onImageSaved(MainActivity.java:273)
at androidx.camera.core.ImageCapture$2.onImageSaved(ImageCapture.java:844)
at androidx.camera.core.ImageSaver.lambda$postSuccess$1$ImageSaver(ImageSaver.java:308)
at androidx.camera.core.-$$Lambda$ImageSaver$29vxg6qyjKwPRXgWrIwgYVInWKE.run(Unknown Source:4)
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:923)
可能吗 ?我是否缺少任何许可?我应该强制使用存储访问框架吗?谢谢
解决方案
推荐阅读
- python - 如何在特定文件夹中安装 Python 模块并在任何带有 Pycharm 或 Visual Studio 的项目中使用它们?
- r - 根据两行之和过滤数据
- kubernetes - 如何在 IBM 云区块链 2.0 资源上部署 .BNA 文件?
- php - 插件更新前的 Wordpress 运行功能
- php - libsodium:crypto_stream_xor 与 crypto_secretbox
- python - 我应该用 tf.one_hot 对背景类进行什么编码?
- javascript - 这种在迭代之前复制数组的模式是什么?
- vba - 如何通过 Visual Basic 设置 Windows 日期
- machine-learning - 图像的成对排名
- c++ - 如何限制计算的浮点值的小数位数?