是否可以在 android 11 及更高版本中仅获得READ_EXTERNAL_STORAGE许可即可播放音乐?

Is is possible to play music just with READ_EXTERNAL_STORAGE permission in android 11 and above?

提问人:Amirhussein 提问时间:9/2/2023 最后编辑:Amirhussein 更新时间:9/3/2023 访问量:51

问:

我想制作一个音乐播放器应用程序。该应用程序将所有音乐加载到外部存储中并播放它们。根据谷歌文档,我刚刚问过用户。该应用程序加载所有音乐并播放它们,并且在装有 android 11 和 12 的模拟器中运行良好。READ_EXTERNAL_STORAGE

但是当我想在自己的手机中使用 android 10 版本尝试时,该应用程序会加载所有音乐,但是当我播放它时,我收到错误“权限被拒绝”,这让我非常困惑。

我想问一下我需要什么权限才能从手机加载所有音乐并播放它们。

我必须获得许可吗?这是唯一的办法吗?MANAGE_EXTERNAL_STORAGE

这是我加载音乐的方式:

fun loadAllMusics() {
        val allSongs = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
        val selection = MediaStore.Audio.Media.IS_MUSIC + "!=0"

        val cursor = contentResolver.query(allSongs, null, selection, null, null)
        if (cursor != null) {
            if (cursor.moveToFirst() == true) {
                do {
                    val songURL =
                        cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA))
                    val songAuthor =
                        cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST))
                    val songName =
                        cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE))
                    val songDuration =
                        cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION))
                    val albumID =
                        cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID))

                    songItemsList.add(
                        SongItem(
                            songDuration.toLong(),
                            songName,
                            songAuthor,
                            songURL,
                            getSongCover(albumID)
                        )

                    )

                } while (cursor.moveToNext() == true)
            }
        }

    }

这就是我加载歌曲封面的方式:

private fun getSongCover(albumID: String): Uri? {
        try {
            val sArtworkUri = Uri.parse("content://media/external/audio/albumart")
            val uri = ContentUris.withAppendedId(sArtworkUri, albumID.toLong())
            return uri
        } catch (e: Exception) {
            return null
        }
    }

清单:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@drawable/amir_tataloo__man_bahat_ghahram"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="false"
        android:theme="@style/Theme.MusicPlayer"
        tools:targetApi="31">
        
        <activity
            android:name=".PlayListActivity"
            android:exported="false" />
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

我的设备日志猫:

FATAL EXCEPTION: main
Process: com.example.musicplayer, PID: 25265
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:503)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075)
Caused by: java.lang.reflect.InvocationTargetException
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075) 
Caused by: java.io.FileNotFoundException: /storage/emulated/0/Download/Sasy - Gentleman.mp3: open failed: EACCES (Permission denied)
    at libcore.io.IoBridge.open(IoBridge.java:496)
    at java.io.FileInputStream.<init>(FileInputStream.java:159)
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1237)
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1208)
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1173)
    at com.example.musicplayer.PlayListActivity$handleRecyclerView$1.onItemClick(PlayListActivity.kt:82)
    at com.example.musicplayer.MySongAdapter.onBindViewHolder$lambda$0(MySongAdapter.kt:36)
    at com.example.musicplayer.MySongAdapter.$r8$lambda$a8Hmn1z3bXNdzC3RJ1fPrlvimpM(Unknown Source:0)
    at com.example.musicplayer.MySongAdapter$$ExternalSyntheticLambda0.onClick(Unknown Source:4)
    at android.view.View.performClick(View.java:7870)
    at android.view.View.performClickInternal(View.java:7839)
    at android.view.View.access$3600(View.java:886)
    at android.view.View$PerformClick.run(View.java:29363)
    at android.os.Handler.handleCallback(Handler.java:883)
    at android.os.Handler.dispatchMessage(Handler.java:100)
    at android.os.Looper.loop(Looper.java:237)
    at android.app.ActivityThread.main(ActivityThread.java:7948)
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075) 
Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
    at libcore.io.Linux.open(Native Method)
    at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
    at libcore.io.BlockGuardOs.open(BlockGuardOs.java:252)
    at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
    at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7825)
    at libcore.io.IoBridge.open(IoBridge.java:482)
    at java.io.FileInputStream.<init>(FileInputStream.java:159) 
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1237) 
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1208) 
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1173) 
    at com.example.musicplayer.PlayListActivity$handleRecyclerView$1.onItemClick(PlayListActivity.kt:82) 
    at com.example.musicplayer.MySongAdapter.onBindViewHolder$lambda$0(MySongAdapter.kt:36) 
    at com.example.musicplayer.MySongAdapter.$r8$lambda$a8Hmn1z3bXNdzC3RJ1fPrlvimpM(Unknown Source:0) 
    at com.example.musicplayer.MySongAdapter$$ExternalSyntheticLambda0.onClick(Unknown Source:4) 
    at android.view.View.performClick(View.java:7870) 
    at android.view.View.performClickInternal(View.java:7839) 
    at android.view.View.access$3600(View.java:886) 
    at android.view.View$PerformClick.run(View.java:29363) 
    at android.os.Handler.handleCallback(Handler.java:883) 
    at android.os.Handler.dispatchMessage(Handler.java:100) 
    at android.os.Looper.loop(Looper.java:237) 
    at android.app.ActivityThread.main(ActivityThread.java:7948) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075) 

为什么我只在 android 10 中收到此错误,而它在 android 11 和 12 中运行良好?

Android Kotlin 权限被拒绝

评论

0赞 CommonsWare 9/2/2023
“应用程序加载外部存储中的所有音乐” -- 使用 .有很多很多开源音乐播放器。您可以考虑检查其中的一些,看看它们的作用。MediaStore
0赞 Amirhussein 9/2/2023
是的,我使用了“MediaStore”
0赞 CommonsWare 9/2/2023
您可能希望扩展您的最小可重现示例,以显示您如何查询以及如何获得您正在使用的,MediaStoreUri
0赞 Robert 9/3/2023
如果要使用 MediaStore 和分区存储,则不需要READ_EXTERNAL_STORAGE。
0赞 Amirhussein 9/3/2023
如何使用分区存储?我以为它已经默认在 API 29 及更高版本中使用了。是否有任何代码可以启用它?

答: 暂无答案