捕获的图像未存储在 android 11 中
Captured Image is not storing in android 11
我无法将捕获的图像存储在 (getExternalFilesDir(Environment.DIRECTORY_PICTURES)) Android 11 设备中。
我已经添加了
<uses-permissionandroid:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
在清单和所有文件访问中。但它不起作用。
if (Build.VERSION.SDK_INT >= 30) {
if (!Environment.isExternalStorageManager()) {
try {
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
intent.addCategory("android.intent.category.DEFAULT")
intent.data = Uri.parse(String.format("package:%s", applicationContext.packageName))
startActivityForResult(intent, 2296)
} catch (e: Exception) {
val intent = Intent()
intent.action = Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
startActivityForResult(intent, 2296)
}
}
}
此代码在 Android 11 设备下运行。但是 Android 11 文件没有创建 File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) .toString() + "/" + FolderName )
使用此代码保存捕获的图像
String mPath = Environment.getExternalStorageDirectory() + "/Print";
Bitmap tmp = BitmapFactory.decodeFile(mPath);
File imageFile = new File(mPath);
FileOutputStream outStream;
try
{
outStream = new FileOutputStream(imageFile);
try
{
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outStream);
outStream.flush();
outStream.close();
} catch (IOException e)
{
e.printStackTrace();
}
} catch (Exception e)
{
e.printStackTrace();
}
您的phone的摄像头没有写入指定位置的权限。因此,要解决此问题,您需要使用文件提供程序并为其授予适当的权限,以便相机可以将图像写入您的文件。
为此,
- 创建一个 FileProvider。在您的清单文件中,添加:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" /> // <-------- see this
</provider>
现在在您的 res/xml
文件夹中创建一个 files.xml
文件。在里面写一些代码:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<cache-path
name="camera"
path="Camera/" />
<cache-path
name="cache"
path="/" />
<files-path
name="files"
path="." />
<external-path
name="external"
path="." />
<external-files-path
name="my_images"
path="/"/>
// todo: add necessary folders according to your requirements...
// also, this is an old example. Consider googling for the latest style. I'm just copying from an old project I have, and it kinda works...
</paths>
所以在这里我们为 FileProvider 提供了可以与外部应用程序共享的文件夹。
2. 现在创建一个要存储照片的 uri。在你的 activity:
Context applicationContext = getApplicationContext();
File root = getCachedDir(); // consider using getExternalFilesDir(Environment.DIRECTORY_PICTURES); you need to check the file_paths.xml
File capturedPhoto = new File(root, "some_photo.jpeg");
if(!photoFile.exists()) {
photoFile.mkdirs();
}
Uri photoURI = FileProvider.getUriForFile(applicationContext, applicationContext.getPackageName() + ".fileprovider", capturedPhoto);
请注意,我的项目需要临时保存图片,所以我使用了cachedDir。如果永久保存照片,请使用 getExternalFilesDir(Environment.DIRECTORY_PICTURES);
并适当修改 file_paths.xml。
- 现在我们有了正确的uri,我们可以调用相机意图了:
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,photoURI);
startActivityForResult(takePictureIntent, REQUEST_CODE);
- 最后,在活动结果中,做一些事情:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
// todo: maybe show photo in an imageView
}
}
我希望这能奏效。
编辑
如果您在生产环境中使用此应用,依赖 android 的默认相机应用不是一个好主意。我们的应用程序以前使用过这种方式,它适用于三星的默认相机。但是我们的很多用户使用第三方应用程序,例如 PixArt
,它不会将照片保存到我们给定的位置。所以我们不得不使用 CameraX
实现一个内置相机。所以考虑使用 CameraX 或其他相机库。
首先是“android.permission.MANAGE_EXTERNAL_STORAGE”权限与保存图像无关。
在 Android 11 google 之后说你应该在你的 space 中开展业务。
这意味着您无法像以前那样获取或保存图像或任何文件 Android 11。
您只能保存在共享文件夹或应用程序存储中 data/App packagename/.....
如果你想访问其他应用程序文件,那么你需要“android.permission.MANAGE_EXTERNAL_STORAGE”,但 google 说这必须是应用程序优先功能,如文件管理器或病毒扫描程序,如应用程序。
就您的应用而言,您尚未提供保存代码。
在 Android 11 我建议使用媒体 Api
ContentResolver resolver = mContext.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, s);
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + File.separator + getResources().getString(R.string.app_name) + File.separator + "imgfolder");
contentValues.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
contentValues.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 1);
Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
fos = resolver.openOutputStream(Objects.requireNonNull(imageUri));
try {
mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
contentValues.clear();
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
resolver.update(imageUri, contentValues, null, null);
}
这是图片文件
我无法将捕获的图像存储在 (getExternalFilesDir(Environment.DIRECTORY_PICTURES)) Android 11 设备中。
我已经添加了
<uses-permissionandroid:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
在清单和所有文件访问中。但它不起作用。
if (Build.VERSION.SDK_INT >= 30) {
if (!Environment.isExternalStorageManager()) {
try {
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
intent.addCategory("android.intent.category.DEFAULT")
intent.data = Uri.parse(String.format("package:%s", applicationContext.packageName))
startActivityForResult(intent, 2296)
} catch (e: Exception) {
val intent = Intent()
intent.action = Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
startActivityForResult(intent, 2296)
}
}
}
此代码在 Android 11 设备下运行。但是 Android 11 文件没有创建 File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) .toString() + "/" + FolderName )
使用此代码保存捕获的图像
String mPath = Environment.getExternalStorageDirectory() + "/Print";
Bitmap tmp = BitmapFactory.decodeFile(mPath);
File imageFile = new File(mPath);
FileOutputStream outStream;
try
{
outStream = new FileOutputStream(imageFile);
try
{
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outStream);
outStream.flush();
outStream.close();
} catch (IOException e)
{
e.printStackTrace();
}
} catch (Exception e)
{
e.printStackTrace();
}
您的phone的摄像头没有写入指定位置的权限。因此,要解决此问题,您需要使用文件提供程序并为其授予适当的权限,以便相机可以将图像写入您的文件。
为此,
- 创建一个 FileProvider。在您的清单文件中,添加:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" /> // <-------- see this
</provider>
现在在您的 res/xml
文件夹中创建一个 files.xml
文件。在里面写一些代码:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<cache-path
name="camera"
path="Camera/" />
<cache-path
name="cache"
path="/" />
<files-path
name="files"
path="." />
<external-path
name="external"
path="." />
<external-files-path
name="my_images"
path="/"/>
// todo: add necessary folders according to your requirements...
// also, this is an old example. Consider googling for the latest style. I'm just copying from an old project I have, and it kinda works...
</paths>
所以在这里我们为 FileProvider 提供了可以与外部应用程序共享的文件夹。 2. 现在创建一个要存储照片的 uri。在你的 activity:
Context applicationContext = getApplicationContext();
File root = getCachedDir(); // consider using getExternalFilesDir(Environment.DIRECTORY_PICTURES); you need to check the file_paths.xml
File capturedPhoto = new File(root, "some_photo.jpeg");
if(!photoFile.exists()) {
photoFile.mkdirs();
}
Uri photoURI = FileProvider.getUriForFile(applicationContext, applicationContext.getPackageName() + ".fileprovider", capturedPhoto);
请注意,我的项目需要临时保存图片,所以我使用了cachedDir。如果永久保存照片,请使用 getExternalFilesDir(Environment.DIRECTORY_PICTURES);
并适当修改 file_paths.xml。
- 现在我们有了正确的uri,我们可以调用相机意图了:
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,photoURI);
startActivityForResult(takePictureIntent, REQUEST_CODE);
- 最后,在活动结果中,做一些事情:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
// todo: maybe show photo in an imageView
}
}
我希望这能奏效。
编辑
如果您在生产环境中使用此应用,依赖 android 的默认相机应用不是一个好主意。我们的应用程序以前使用过这种方式,它适用于三星的默认相机。但是我们的很多用户使用第三方应用程序,例如 PixArt
,它不会将照片保存到我们给定的位置。所以我们不得不使用 CameraX
实现一个内置相机。所以考虑使用 CameraX 或其他相机库。
首先是“android.permission.MANAGE_EXTERNAL_STORAGE”权限与保存图像无关。 在 Android 11 google 之后说你应该在你的 space 中开展业务。 这意味着您无法像以前那样获取或保存图像或任何文件 Android 11。 您只能保存在共享文件夹或应用程序存储中 data/App packagename/.....
如果你想访问其他应用程序文件,那么你需要“android.permission.MANAGE_EXTERNAL_STORAGE”,但 google 说这必须是应用程序优先功能,如文件管理器或病毒扫描程序,如应用程序。
就您的应用而言,您尚未提供保存代码。 在 Android 11 我建议使用媒体 Api
ContentResolver resolver = mContext.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, s);
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + File.separator + getResources().getString(R.string.app_name) + File.separator + "imgfolder");
contentValues.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
contentValues.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 1);
Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
fos = resolver.openOutputStream(Objects.requireNonNull(imageUri));
try {
mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
contentValues.clear();
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
resolver.update(imageUri, contentValues, null, null);
}
这是图片文件