简体   繁体   English

API 29 媒体商店访问

[英]API 29 Mediastore Access

My app creates playlists in the android mediastore.我的应用程序在 android 媒体商店中创建播放列表。 All is well for api's including 28 however, api 29 seems to require additional permissions.对于包括 28 在内的 api,一切都很好,但是 api 29 似乎需要额外的权限。 Inserting a new playlist name and id works without issue.插入新的播放列表名称和 ID 没有问题。 When it comes to inserting track id and play order, an access permission exception is thrown.插入曲目id和播放顺序时,抛出访问权限异常。 In verifying the Uri, i found that when resolver.insert for API 29 the exception error is:在验证Uri时,发现resolver.insert for API 29时异常错误为:

java.lang.SecurityException: myapp_name has no access to content://media/external_primary/audio/media/146

The code:代码:

Uri exturi = MediaStore.Audio.Playlists.Members.getContentUri("external", playlist_id);
// exturi : content://media/external/audio/playlists/227/members

// values : audio_id=146 play_order=0
values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, play_order);
values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, audio_id);

try {
    resolver.insert(exturi, values);
} catch (Exception e) {
    e.printStackTrace();
}

Strange thing is that although inserting a new playlist into Mediastore works but adding tracks (track_id, play order) gives an access permission error奇怪的是,虽然在 Mediastore 中插入一个新的播放列表是有效的,但是添加曲目 (track_id, play order) 会出现访问权限错误

How to resolve this exception error for API 29?如何解决 API 29 的这个异常错误?

Update Feb 2021: a small step forward, I am pretty sure I need to get Documenturi for the original uri but still gives me the access error. 2021 年 2 月更新:向前迈出了一小步,我很确定我需要为原始 uri 获取 Documenturi,但仍然给我访问错误。 So the issue does not lie with accessing the tracks but with the uri itself.所以问题不在于访问轨道,而在于 uri 本身。

doc_uri = MediaStore.getDocumentUri(context,playlist_members_uri);
java.lang.SecurityException: com.flyingdutchman.newplaylistmanager has no access to content://media/external/audio/playlists/130/members

I think this is an Android 10 bug, so I've filed a report here: https://issuetracker.google.com/issues/147619577 (includes instructions for an emulator test case to reproduce it if that interests you).我认为这是一个 Android 10 错误,所以我在此处提交了一份报告: https : //issuetracker.google.com/issues/147619577 (包括模拟器测试用例的说明,如果您感兴趣,可以重现它)。 Please consider starring it to let the Android team know that it affects you.请考虑给它加星标,让 Android 团队知道它会影响您。

From what I can tell, it only affects files on 'external' storage, like sdcards mounted on /storage/XXXX-XXXX据我所知,它只影响“外部”存储上的文件,例如安装在/storage/XXXX-XXXX上的 sdcards

In the meantime, the only fix that some of my users were able to successfully apply is to move their music files to the internal storage (reboot and wait for the media scan to finish to be sure that MediaStore is up-to-date).与此同时,我的一些用户能够成功应用的唯一修复是将他们的音乐文件移动到内部存储(重新启动并等待媒体扫描完成以确保 MediaStore 是最新的)。

in my further research for the answer, I came across this;在我对答案的进一步研究中,我遇到了这个问题;

All about the media database (Mediastore) with android 11 关于 android 11 的媒体数据库 (Mediastore)

Update for android 11. Worth noting that the media database has moved from android 11 更新。值得注意的是,媒体数据库已从

/data/data/com.android.providers.media

to

/data/data/com.google.android.providers.media.module

also the structures have changes significantly结构也发生了显着变化

安卓 10/11 之前 and安卓 11

  1. Create playlist with uri "MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI", and the date row in external.db for the playlist is:使用uri“MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI”创建播放列表,播放列表external.db中的日期行是:
_id _ID _display_name _显示名称 volume_name卷名
308 308 New playlist.m3u新播放列表.m3u external_primary external_primary

The playlist's volume name is "external_primary".播放列表的卷名是“external_primary”。

2. 2.

  • Music file is under flash card音乐文件在闪存卡下
  • Music file's id in external.db is 278 external.db 中音乐文件的 id 是 278
  • The volume name of flash card is "1EDD-DDE0"闪存卡的卷名是“1EDD-DDE0”

When add this music file to playlist, got below exception:将此音乐文件添加到播放列表时,出现以下异常:
Exception message: java.lang.SecurityException: has no access to content://media/external_primary/audio/media/278异常消息:java.lang.SecurityException:无权访问 content://media/external_primary/audio/media/278

If I create playlist with uri MediaStore.Audio.Playlists.getContentUri("1edd-dde0") , then music can be successfully added to the playlist.如果我使用 uri MediaStore.Audio.Playlists.getContentUri("1edd-dde0")创建播放列表,则音乐可以成功添加到播放列表中。

It seems that the reason is the mismatch of volume name between playlist and the music file to be added.原因似乎是播放列表和要添加的音乐文件之间的卷名不匹配。 Only when playlist's volume name is same to music file's, inserting operation can be complete.只有当播放列表的卷名与音乐文件的卷名相同时,才能完成插入操作。

AND FINALLY I FIND THIS MediaStore.Audio.Playlists This class was deprecated in API level 31. Android playlists are now deprecated.最后我找到了这个 MediaStore.Audio.Playlists 这个 class 在 API 级别 31 中被弃用了。Android 播放列表现在被弃用了。 We (Google) will keep the current functionality for compatibility resons, but we will no longer take feature request.我们 (Google) 将保留当前的兼容性原因功能,但我们将不再接受功能请求。 We do not advise adding new usages of Android Playlists.我们不建议添加 Android 播放列表的新用法。 M3U files can be used as an alternative. M3U 文件可以用作替代。

In conclusion, no longer a relevant post总之,不再是相关帖子

I have concluded that the issue lies with the google avd emulator image. 我已经得出结论,问题出在google avd仿真器映像。 There is no issues on either samsung or huawei emulated devices. 在三星或华为仿真设备上都没有问题。

I have implemented the SAF so do not use scopedStorage and have access once the user accepts.我已经实现了 SAF,所以不要使用 scopedStorage 并且一旦用户接受就可以访问。 The fact that I can insert new playlist entries clearly shows access to MediaStore, I can also delete these.我可以插入新的播放列表条目这一事实清楚地显示了对 MediaStore 的访问权限,我也可以删除这些条目。 However trying to add tracks to these playlists does not work for api29.但是,尝试向这些播放列表添加曲目不适用于 api29。 Inserting/deleting a new playlist does not involve any files located on internal or external sdcards as it is simply adding values.插入/删除新播放列表不涉及位于内部或外部 SD 卡上的任何文件,因为它只是添加值。

the permissions for both internal and external sdcard:内部和外部 sdcard 的权限:

2020-07-12 14:39:04.435 11858-11858/com.flyingdutchman.newplaylistmanager E/onCreate:: uriPermission: UriPermission {uri=content://com.android.externalstorage.documents/tree/17F5-240A%3A, modeFlags=3, persistedTime=1594551961263}
2020-07-12 14:39:04.435 11858-11858/com.flyingdutchman.newplaylistmanager E/onCreate:: uriPermission: UriPermission {uri=content://com.android.externalstorage.documents/tree/primary%3A, modeFlags=3, persistedTime=1594551926876}

The question now becomes现在的问题变成

How do I ensure saf permissions are recognised by the resolver.insert method when inserting/modify tracks into the Media database在向媒体数据库中插入/修改曲目时,如何确保 resolver.insert 方法识别 saf 权限

My app creates playlists in the android mediastore.我的应用程序在android mediastore中创建播放列表。 All is well for api's including 28 however, api 29 seems to require additional permissions.包括28在内的api一切都很好,但是api 29似乎需要其他权限。 Inserting a new playlist name and id works without issue.插入新的播放列表名称和ID不会出现问题。 When it comes to inserting track id and play order, an access permission exception is thrown.当涉及插入曲目ID和播放顺序时,将引发访问权限异常。 In verifying the Uri, i found that when resolver.insert for API 29 the exception error is:在验证Uri时,我发现当API 29的resolver.insert出现时,异常错误是:

java.lang.SecurityException: myapp_name has no access to content://media/external_primary/audio/media/146

The code:编码:

Uri exturi = MediaStore.Audio.Playlists.Members.getContentUri("external", playlist_id);
// exturi : content://media/external/audio/playlists/227/members

// values : audio_id=146 play_order=0
values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, play_order);
values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, audio_id);

try {
    resolver.insert(exturi, values);
} catch (Exception e) {
    e.printStackTrace();
}

Strange thing is that although inserting a new playlist into Mediastore works but adding tracks (track_id, play order) gives an access permission error奇怪的是,尽管可以在Mediastore中插入新的播放列表,但是添加曲目(track_id,播放顺序)会导致访问权限错误

How to resolve this exception error for API 29?如何解决API 29的此异常错误?

Update Feb 2021: a small step forward, I am pretty sure I need to get Documenturi for the original uri but still gives me the access error. 2021年2月更新:向前迈出了一小步,我敢肯定我需要为原始uri获取Documenturi,但仍然会给我访问错误。 So the issue does not lie with accessing the tracks but with the uri itself.因此,问题不在于访问曲目,而在于uri本身。

doc_uri = MediaStore.getDocumentUri(context,playlist_members_uri);
java.lang.SecurityException: com.flyingdutchman.newplaylistmanager has no access to content://media/external/audio/playlists/130/members

My app creates playlists in the android mediastore.我的应用程序在android mediastore中创建播放列表。 All is well for api's including 28 however, api 29 seems to require additional permissions.包括28在内的api一切都很好,但是api 29似乎需要其他权限。 Inserting a new playlist name and id works without issue.插入新的播放列表名称和ID不会出现问题。 When it comes to inserting track id and play order, an access permission exception is thrown.当涉及插入曲目ID和播放顺序时,将引发访问权限异常。 In verifying the Uri, i found that when resolver.insert for API 29 the exception error is:在验证Uri时,我发现当API 29的resolver.insert出现时,异常错误是:

java.lang.SecurityException: myapp_name has no access to content://media/external_primary/audio/media/146

The code:编码:

Uri exturi = MediaStore.Audio.Playlists.Members.getContentUri("external", playlist_id);
// exturi : content://media/external/audio/playlists/227/members

// values : audio_id=146 play_order=0
values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, play_order);
values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, audio_id);

try {
    resolver.insert(exturi, values);
} catch (Exception e) {
    e.printStackTrace();
}

Strange thing is that although inserting a new playlist into Mediastore works but adding tracks (track_id, play order) gives an access permission error奇怪的是,尽管可以在Mediastore中插入新的播放列表,但是添加曲目(track_id,播放顺序)会导致访问权限错误

How to resolve this exception error for API 29?如何解决API 29的此异常错误?

Update Feb 2021: a small step forward, I am pretty sure I need to get Documenturi for the original uri but still gives me the access error. 2021年2月更新:向前迈出了一小步,我敢肯定我需要为原始uri获取Documenturi,但仍然会给我访问错误。 So the issue does not lie with accessing the tracks but with the uri itself.因此,问题不在于访问曲目,而在于uri本身。

doc_uri = MediaStore.getDocumentUri(context,playlist_members_uri);
java.lang.SecurityException: com.flyingdutchman.newplaylistmanager has no access to content://media/external/audio/playlists/130/members

Update May 2020 2020 年 5 月更新

Stepping through the resolver code with debug F7使用调试 F7 单步执行解析器代码

Scenario 1 results in permission error (incorrect MediaStore.VOLUME_EXTERNAL).场景 1 导致权限错误(不正确的 MediaStore.VOLUME_EXTERNAL)。

 playlist_uri = MediaStore.Audio.Playlists.getContentUri(MediaStore.VOLUME_EXTERNAL);
 playlist_members_uri  = MediaStore.Audio.Playlists.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
                    .buildUpon()
                    .appendEncodedPath(Long.toString(playlist_id))
                    .appendEncodedPath("members")
                    .build();

acquireProvider(mContext, auth);获取提供者(mContext,auth); = media = 媒体

Uri createdRow = provider.insert(mPackageName, mAttributionTag, url, values, extras); Uri createdRow = provider.insert(mPackageName, mAttributionTag, url, values, extras); = null = 空

mPackageName=com.flyingdutchman.newplaylistmanager mPackageName=com.flyingdutchman.newplaylistmanager

mAttributionTag=null mAttributionTag=null

values[0] = 206 values[1]=69 values[2]=1值[0] = 206 个值[1]=69 个值[2]=1

extras=null额外=空

DatabaseUtils.java数据库实用程序

   public static final void readExceptionFromParcel(Parcel reply) {
        int code = reply.readExceptionCode();
        if (code == 0) return;
        String msg = reply.readString();
        DatabaseUtils.readExceptionFromParcel(reply, msg, code);
    }

msg = com.flyingdutchman.newplaylistmanager has no access to content://media/external_primary/audio/playlists/206 msg = com.flyingdutchman.newplaylistmanager 无权访问 content://media/external_primary/audio/playlists/206

Scenario 2 results in NO permission error BUT no tracks added to audio_playlists_map table.场景 2 导致没有权限错误但没有曲目添加到 audio_playlists_map 表。

 playlist_uri = MediaStore.Audio.Playlists.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
url=content://media/external_primary/audio/playlists/206/members

I came across the same issue.我遇到了同样的问题。 As the MediaProvider changes to Google's MediaProvider, the Scoped Storage feature is activated.当 MediaProvider 更改为 Google 的 MediaProvider 时,会激活 Scoped Storage 功能。 When you try to modify a playlist file, but it's not created by your app (or it did be created by your app, but after OTA to new Android version, which changes to use Google's MediaProvider, it scans your playlist file and put a record to its database, but leaves the owner_package_name colume empty, it's a new colume, the old MediaProvider database has no owner_package_name colume, so no one could tell this playlist file was created by you), you will get a SecurityException says you have no access to this file.当您尝试修改播放列表文件,但它不是由您的应用程序创建的(或者它确实由您的应用程序创建,但在 OTA 到新的 Android 版本后,更改为使用 Google 的 MediaProvider,它会扫描您的播放列表文件并记录到它的数据库,但owner_package_name空,这是一个新的列,旧的 MediaProvider 数据库没有owner_package_name ,所以没有人可以告诉这个播放列表文件是由你创建的),你会得到一个 SecurityException 说你无权访问这个文件。

You can check if the playlist file was owned by your app before doing the ' insert ' operation:您可以在执行“ insert ”操作之前检查播放列表文件是否归您的应用所有:

Uri uri = MediaStore.Audio.Playlists.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
String[] projection = new String[] {
        MediaStore.Audio.Playlists._ID,
        MediaStore.Audio.Playlists.NAME,
        MediaStore.Audio.Playlists.OWNER_PACKAGE_NAME,
};
String where = MediaStore.Audio.Playlists._ID + "=?";
String[] args = new String[] {playlistFileId};
Cursor cursor = resolver.query(uri, projection, where, args, null);
if (cursor != null) {
    cursor.moveToFirst();
    if (!cursor.isAfterLast()) {
        String ownerPkg = cursor.getString(
                cursor.getColumnIndex(MediaStore.Audio.Playlists.OWNER_PACKAGE_NAME));
        // print ownerPkg here
    }
}

If the owner package name of this playlist file is empty or other app's package name, that you probably have no access to write this playlist file due to the scoped storage feature limit.如果此播放列表文件的所有者包名称为空或其他应用程序的包名称,则您可能由于范围存储功能限制而无权写入此播放列表文件。

According to this document , we can consider using MediaStore.createWriteRequest() method to prompt user to grant write permission to playlist file for our own app, but this request only available to certain kind of files, like images, audios, videos etc, but not for some other kinds like playlist files which ends in .m3u suffix.根据这个文档,我们可以考虑使用 MediaStore.createWriteRequest() 方法来提示用户为我们自己的应用程序授予对播放列表文件的写入权限,但此请求仅适用于某些类型的文件,如图像、音频、视频等,但是不适用于其他类型,例如以 .m3u 后缀结尾的播放列表文件。

Also, according to this , when you try to operate some image or audio files that's not created by your app in public storage, you will get a RecoverableSecurityException and you can use this exception to prompt user to get user consent to modify the file, but for playlist kind files, you will just get SecurityException instead of RecoverableSecurityException .此外,根据this ,当您尝试在公共存储中操作某些不是您的应用程序创建的图像或音频文件时,您将收到一个RecoverableSecurityException并且您可以使用此异常提示用户获得用户同意来修改该文件,但是对于播放列表类型的文件,您只会得到SecurityException而不是RecoverableSecurityException

So the result is, you may never be able to access to that playlist file again, you can not modify it, and you can not delete it too.所以结果是,您可能永远无法再次访问该播放列表文件,您无法修改它,也无法删除它。 My solution is just create a new playlist file, so it's owned by my app, now I finally have full access to it.我的解决方案只是创建一个新的播放列表文件,因此它归我的应用所有,现在我终于可以完全访问它了。 You may need to migrate your old playlist data to the new one.您可能需要将旧的播放列表数据迁移到新的播放列表数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在 Android 上获取所有带有 mediastore 的图像 API ≤28 和 API ≥29 - Getting all images with mediastore on Android API ≤28 and API ≥29 MediaStore - BUCKET_DISPLAY_NAME 仅存在于 API 29+ 上? - MediaStore - BUCKET_DISPLAY_NAME only present on API 29+? 更新 MediaStore 上的条目不适用于 Android Q/API29 - Updating an entry on MediaStore does not work on Android Q / API29 api 29+ 已弃用 MediaStore.Audio.Media.EXTERNAL_CONTENT_URI? - MediaStore.Audio.Media.EXTERNAL_CONTENT_URI is deprecated for api 29+? MediaStore.MediaColumns#DATE_TAKEN 是否只能从 API 级别 29 使用? - Is MediaStore.MediaColumns#DATE_TAKEN only available from API level 29? 重命名由应用程序在 android 10 中创建的 Mediastore 文件。在 Android API 30 上工作,但在 API 29 中显示错误 - Rename file of the Mediastore which is created by app in android 10. Working on Android API 30 but shows error in API 29 如何使用 MediaStore API 访问 Android 11 的 Whatsapp 文件夹? - How to access Whatsapp folder of Android 11 by using MediaStore API? 不访问 API-29 中的外部存储 - Doesn't Access to external storage in API-29 我无法使用 Android 10 (API 29) 访问 GPS - I can't access GPS using Android 10 (API 29) Android Kotlin 访问下载目录中的文件 API > 29 - Android Kotlin Access to Files in Download Directory API > 29
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM