我的应用程序需要备份 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/