16

我的应用在 android mediastore 中创建播放列表。包括 28 在内的 api 一切都很好,但是 api 29 似乎需要额外的权限。插入新的播放列表名称和 ID 可以正常工作。插入track id和播放顺序时,会抛出访问权限异常。在验证 Uri 时,我发现当 resolver.insert for API 29 出现异常错误时:

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

编码:

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

奇怪的是,虽然将新的播放列表插入 Mediastore 有效,但添加曲目(track_id,播放顺序)会导致访问权限错误

如何解决 API 29 的这个异常错误?

2021 年 2 月更新:向前迈出了一小步,我很确定我需要为原始 uri 获取 Documenturi,但仍然给我访问错误。所以问题不在于访问轨道,而在于 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
4

7 回答 7

7

我认为这是一个 Android 10 错误,所以我在这里提交了一份报告:https ://issuetracker.google.com/issues/147619577 (如果您感兴趣,包括仿真器测试用例重现它的说明)。请考虑给它加星标,让 Android 团队知道它会影响您。

据我所知,它只影响“外部”存储上的文件,比如安装在/storage/XXXX-XXXX

与此同时,我的一些用户能够成功应用的唯一修复是将他们的音乐文件移动到内部存储(重新启动并等待媒体扫描完成以确保 MediaStore 是最新的)。

于 2020-01-14T15:14:03.993 回答
1

android 11 的更新。值得注意的是,媒体数据库已从

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

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

结构也发生了重大变化

安卓 10/11 之前安卓 11

于 2021-03-23T14:28:42.617 回答
1
  1. 使用 uri "MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI" 创建播放列表,播放列表在 external.db 中的日期行是:
_ID _显示名称 卷名
308 新播放列表.m3u external_primary

播放列表的卷名是“external_primary”。

2.

  • 音乐文件在闪存卡下
  • external.db 中音乐文件的 id 为 278
  • 闪存卡的卷名是“1EDD-DDE0”

将此音乐文件添加到播放列表时,出现以下异常:
异常消息:java.lang.SecurityException: has no access to content://media/external_primary/audio/media/278

如果我使用 uri 创建播放列表MediaStore.Audio.Playlists.getContentUri("1edd-dde0"),则音乐可以成功添加到播放列表。

似乎原因是播放列表和要添加的音乐文件之间的卷名不匹配。只有当播放列表的卷名与音乐文件的卷名相同时,才能完成插入操作。

于 2021-04-08T10:49:28.017 回答
1

我遇到了同样的问题。随着 MediaProvider 更改为 Google 的 MediaProvider,Scoped Storage 功能被激活。当您尝试修改播放列表文件,但它不是由您的应用程序创建的(或者它确实是由您的应用程序创建的,但是在 OTA 到新的 Android 版本后,它会更改为使用 Google 的 MediaProvider,它会扫描您的播放列表文件并记录到它的数据库,但让owner_package_name列为空,它是一个新列,旧的 MediaProvider 数据库没有owner_package_name列,所以没有人知道这个播放列表文件是由你创建的),你会得到一个 SecurityException 说你无权访问这个文件.

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
    }
}

如果此播放列表文件的所有者包名称为空或其他应用程序的包名称,则由于范围存储功能限制,您可能无权写入此播放列表文件。

根据这个文档,我们可以考虑使用 MediaStore.createWriteRequest() 方法来提示用户为我们自己的应用程序授予对播放列表文件的写入权限,但是这个请求只适用于某些类型的文件,比如图像、音频、视频等,但是不适用于其他类型,例如以 .m3u 后缀结尾的播放列表文件。

另外,据此当您尝试在公共存储中操作一些不是您的应用程序创建的图像或音频文件时,您会得到一个RecoverableSecurityException,您可以使用此异常提示用户征得用户同意才能修改文件,但对于播放列表类型的文件,你只会得到SecurityException而不是RecoverableSecurityException.

所以结果是,您可能永远无法再次访问该播放列表文件,您无法修改它,也无法删除它。我的解决方案只是创建一个新的播放列表文件,所以它归我的应用所有,现在我终于可以完全访问它了。您可能需要将旧的播放列表数据迁移到新的。

于 2021-10-22T10:04:39.970 回答
1

在我对答案的进一步研究中,我遇到了这个;

所有关于带有 android 11 的媒体数据库 (Mediastore)

于 2021-03-16T17:02:40.580 回答
0

2020 年 5 月更新

使用调试 F7 单步执行解析器代码

场景 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();

获取提供者(mContext,身份验证);= 媒体

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

mPackageName=com.flyingdutchman.newplaylistmanager

mAttributionTag=null

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

额外=空

数据库实用程序.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 无权访问内容://media/external_primary/audio/playlists/206

场景 2 导致没有权限错误但没有轨道添加到 audio_playlists_map 表。

 playlist_uri = MediaStore.Audio.Playlists.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
url=content://media/external_primary/audio/playlists/206/members
于 2021-05-12T14:39:45.833 回答
0

我已经实现了 SAF,所以不要使用 scopedStorage,一旦用户接受就可以访问。我可以插入新的播放列表条目这一事实清楚地表明可以访问 MediaStore,我也可以删除这些条目。但是,尝试将曲目添加到这些播放列表不适用于 api29。插入/删除新播放列表不涉及位于内部或外部 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}

现在的问题变成了

在将曲目插入/修改到媒体数据库时,如何确保 resolver.insert 方法能够识别 saf 权限

于 2020-02-18T12:14:48.953 回答