android - 是否可以使用 MediaStore.VOLUME_EXTERNAL 获取 WhatsApp 媒体文件

标签 android mediastore android-external-storage

我的应用程序需要备份 WhatsApp 状态、语音笔记和图像的功能。如您所知,在 Android Q 之后,谷歌强制使用 MediaStore API 访问外部媒体文件。

WhatsApp 也将他们的文件移动到 /Android/media/com.whatsapp/WhatsApp。我尝试使用 MANAGE_EXTERNAL_STORAGE 权限它工作正常,但备份这些文件不是应用程序的核心功能,所以我认为谷歌不会让我使用此权限。

我想知道是否有任何方法可以使用 MediaStore.VOLUME_EXTERNAL 读取这些文件?

我试过这样的事情。我不确定这是否可能。

val collection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)

val selection= (MediaStore.Files.FileColumns.MEDIA_TYPE + "="
        + MediaStore.Files.FileColumns.MEDIA_TYPE_NONE)
val selectionArgs= arrayOf("%/WhatsApp/Media/.Statuses%")
val cursor = applicationContext.contentResolver.query(
    collection, null, selection, selectionArgs, null)
debug(cursor?.columnCount)
cursor?.close()

它抛出一个异常。

Caused by: android.database.sqlite.SQLiteException: no such column: media_type

最佳答案

试试这个...

要读取 whatsapp 状态,您不需要做更多的事情,只需更改它的路径。

此外,您不需要使用 MANAGE_EXTERNAL_STORAGE 权限。这也适用于较早的许可。

下面是 SDK 29 的答案

我是这样做的

String path=Environment.getExternalStorageDirectory().getAbsolutePath()+"/Android/media/"+"com.whatsapp" + "/WhatsApp/Media/.Statuses/"

File directory = new File(wa_path);
    if (!directory.exists()) {
        directory.mkdirs();
    }
    File[] files = directory.listFiles();
    if (files != null) {
        Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
        for (int i = 0; i < files.length; i++) {
            if (!files[i].getName().equals(".nomedia")) {
                your_list.add(files[i]);
            }
        }
    }

这也适用于 android 11。我只像以前一样请求“READ_EXTERNAL_STORAGE”和“WRITE_EXTERNAL_STORAGE”。

所以现在你需要检查“WhatsApp”文件夹在根存储中是否可用(之前它在哪里),如果不可用则需要检查我上面提到的路径。

适用于 SDK 30 及以上版本

首先请求应用特定的文件夹权限

    try {
        Intent createOpenDocumentTreeIntent = ((StorageManager) getSystemService("storage")).getPrimaryStorageVolume().createOpenDocumentTreeIntent();
        String replace = ((Uri) createOpenDocumentTreeIntent.getParcelableExtra("android.provider.extra.INITIAL_URI")).toString().replace("/root/", "/document/");
        createOpenDocumentTreeIntent.putExtra("android.provider.extra.INITIAL_URI", Uri.parse(replace + "%3A" + "Android%2Fmedia"));
        startActivityForResult(createOpenDocumentTreeIntent, 500);
    } catch (Exception unused) {
        Toast.makeText(MainActivity.this, "can't find an app to select media, please active your 'Files' app and/or update your phone Google play services", 1).show();
    }

现在在 OnActivityResult 中

    @Override
        protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (requestCode == 500) {
                if (data != null) {
     Uri wa_status_uri = Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fmedia/document/primary%3AAndroid%2Fmedia%2Fcom.whatsapp%2FWhatsApp%2FMedia%2F.Statuses");
 getContentResolver().takePersistableUriPermission(data.getData(), Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
    
                    //save shared preference to check whether app specific folder permission granted or not              FastSave.getInstance().saveBoolean(Utils.KEY_IS_APP_SPECTIFIC_PERMISSION_GRANTED, true);
    
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            getDataForAndroid11OnlyStatus(wa_status_uri);
                        }
                    }, 100);
                }
    
            }
        }


//now get status from whatsApp folder

    ArrayList<Object> statusObjectsList = new ArrayList<>();
    
    
    private void getDataForAndroid11OnlyStatus(Uri uriMain) {
        //check for app specific folder permission granted or not
        if (!FastSave.getInstance().getBoolean(Utils.KEY_IS_APP_SPECTIFIC_PERMISSION_GRANTED, false)) {
            //ask for folder permission
        }
    
        Log.d("====", "uriMain ::: " + uriMain);
        ContentResolver contentResolver = getContentResolver();
        Uri uri = uriMain;
        Uri buildChildDocumentsUriUsingTree = DocumentsContract.buildChildDocumentsUriUsingTree(uri, DocumentsContract.getDocumentId(uri));
    
        ArrayList arrayList = new ArrayList();
        Cursor cursor = null;
        try {
            cursor = contentResolver.query(buildChildDocumentsUriUsingTree, new String[]{"document_id"}, (String) null, (String[]) null, (String) null);
            while (cursor.moveToNext()) {
                arrayList.add(DocumentsContract.buildDocumentUriUsingTree(uriMain, cursor.getString(0)));
                if (!DocumentsContract.buildDocumentUriUsingTree(uriMain, cursor.getString(0)).toString().endsWith(".nomedia")) {
    
                    FileHelper fileHelper = new FileHelper(MainActivity.this);
                    String filePath = fileHelper.getRealPathFromUri(DocumentsContract.buildDocumentUriUsingTree(uriMain, cursor.getString(0)));
    
                    statusObjectsList.add(DocumentsContract.buildDocumentUriUsingTree(uriMain, cursor.getString(0)));
    
                }
            }
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    //here set your adapter in list and set data from statusObjectsList
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        } catch (Throwable th) {
            throw th;
        }
    }

如果您不理解或不起作用,请告诉我。

这正在 Android 11 模拟器、OnePlus Nord、Redmi Note 10 Pro 和 Poco 中进行测试。在所有这些 Android 11 设备中,都会显示 WhatsApp 状态。

补充说: 那么你的目标 api 是什么我认为你的目标是 api 29 如果你的目标是 api 30 将无法工作证明你的答案

谢谢

关于android - 是否可以使用 MediaStore.VOLUME_EXTERNAL 获取 WhatsApp 媒体文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68289072/

相关文章:

javascript - 使用 API 将外部数据加载到 PhoneGap 应用程序中

Android: picasso 加载图片失败。如何显示错误信息

android - 获取特定文件夹的 MediaStore 路径

android - 测试应用中的存储访问框架

android - 无法在 Android/data 中创建文件夹

java - 调用需要权限,在尝试获取位置时可能会被用户拒绝

android - 如何让球保持移动

android - 我们可以使用 MediaStore API 删除图像文件吗?如果是,那么如何

Android:外部存储上的 mkdirs()/mkdir() 返回 false

java - 如何构建android UIAutomator 项目?