捕获的图像未存储在Android 11中

6

我无法将捕获的图像存储在(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)


没有代码可以获取或保存图片文件。而且你不需要访问该目录的所有文件。 - blackapps
你添加了什么到清单中? - blackapps
我已经编辑了问题。 - Pritham Bnr
@blackapps 那为什么图片不能保存在安卓文件夹中呢?它在 Android 11 之前的设备上是可以工作的。 - Pritham Bnr
@blackapps 我使用相机拍摄了照片,但是照片没有保存在存储(Android/data)文件夹中。 - Pritham Bnr
显示剩余5条评论
3个回答

4

您的手机相机没有在指定位置写入权限。因此,要解决此问题,您需要使用文件提供程序并授予适当的权限,以便相机可以将图像写入您的文件。

要做到这一点,

  1. 创建一个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,用于存储照片:

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文件。
3.现在我们有了正确的URI,就可以调用相机意图:
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,photoURI);
        startActivityForResult(takePictureIntent, REQUEST_CODE);
  1. 最后,在活动结果中,进行一些操作:
    @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 或其他相机库。


出现错误 - Caused by: java.io.IOException: 没有这样的文件或目录。 - Pritham Bnr
尝试这个:File capturedPhoto = new File(root, "some_photo.jpeg"); if(!capturedPhoto.exists()) { capturedPhoto.mkdirs(); } Uri photoURI = FileProvider.getUriForFile(applicationContext, applicationContext.getPackageName() + ".fileprovider", capturedPhoto); - Qazi Fahim Farhan
1
由于作用域存储问题,您的手机相机没有权限在指定位置写入。这与作用域存储无关。在Android Q以下,任何应用程序都可以写入该位置。但自Android N/7以来,您不能在意图中使用文件URI/路径启动相机应用程序。Android N/7及以上版本强制您使用文件提供程序。 - blackapps

1

首先,“android.permission.MANAGE_EXTERNAL_STORAGE” 权限与保存图像无关。 在 Android 11 之后,谷歌建议您在自己的空间内进行业务。 这意味着您不能像在 Android 11 之前那样获取或保存图像或任何文件。 您只能保存在共享文件夹中或在应用程序存储数据/应用程序包名称/... 中。

如果要访问其他应用程序文件,则需要“android.permission.MANAGE_EXTERNAL_STORAGE”,但是谷歌说必须是类似文件管理器或病毒扫描器的应用程序的先前功能。

就您的应用程序而言,您尚未提供保存代码。 在 Android 11 中,我建议使用 Media 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);
                }

这是关于图片文件的内容


0

使用此代码保存捕获的图像

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();
    }

1
getExternalStorageDirectory已被弃用。 - Pritham Bnr
它可以工作。但将来他们会移除。 - Pritham Bnr
1
没错。你可以替换 getExternalFilesDir(null).getAbsolutePath(); - Pouria Hemi
如果我添加那行代码,就会调用RESULT_CANCELED。 - Pritham Bnr
上次我做这个的时候,我发现输出图像的分辨率非常低。要拍摄高分辨率照片,应该使用带有意图的文件URI。 - Qazi Fahim Farhan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接