音乐播放器要求写入外部存储权限?

Posted

技术标签:

【中文标题】音乐播放器要求写入外部存储权限?【英文标题】:Music Player asking for Write External Storage Permission? 【发布时间】:2016-08-01 10:45:14 【问题描述】:

我正在 android 中创建一个音乐播放器应用程序。它工作正常,但每当我滚动歌曲列表时,它就会开始崩溃并给出这个异常

Process: com.example.lenovo.musicplayer, PID: 31100
java.lang.SecurityException: External path: /storage/emulated/0/Android/data/com.android.providers.media/albumthumbs/1460104607336: Neither user 10294 nor current process has android.permission.WRITE_EXTERNAL_STORAGE.      
at android.os.Parcel.readException(Parcel.java:1555)      
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:190)
at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:153)
at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:691)
at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1170)
at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:994)
at android.content.ContentResolver.openInputStream(ContentResolver.java:719)
at android.provider.MediaStore$Images$Media.getBitmap(MediaStore.java:1110)
at com.example.lenovo.musicplayer.Adapter.getView(Adapter.java:119)
at android.widget.AbsListView.obtainView(AbsListView.java:2571)
at android.widget.ListView.makeAndAddView(ListView.java:1894)
at android.widget.ListView.fillDown(ListView.java:710)
at android.widget.ListView.fillGap(ListView.java:674)
at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5900)
at android.widget.AbsListView$FlingRunnable.run(AbsListView.java:5378)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:825)
at android.view.Choreographer.doCallbacks(Choreographer.java:619)
at android.view.Choreographer.doFrame(Choreographer.java:578)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:811)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:6102)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)

当我在清单文件中授予写入权限时,这个问题就消失了,但我不明白的是为什么当我没有向任何类型的贮存。 据我了解,音乐播放器不需要写入外部存储权限。

这是歌曲列表活动的代码

   public class ActivitySongsList extends AppCompatActivity 
public static ArrayList<MusicBean>songsList;
    ListView listView;
    Toolbar toolbar;
    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_songs_list);
        toolbar= (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        listView= (ListView) findViewById(R.id.lv_songs);
        songsList=getAudioList();
        Adapter adapter=new Adapter(this,songsList);
        listView.setAdapter(adapter);
        getSupportActionBar().setTitle("Songs");
        toolbar.setTitleTextColor(Color.parseColor("#ffffff"));
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() 
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) 
                Intent intent=new Intent(ActivitySongsList.this,ActivityMusicDetails.class);
                intent.putExtra("song",songsList.get(position));
                intent.putExtra("position",String.valueOf(position));
                startActivity(intent);
            
        );
    
    private ArrayList<MusicBean> getAudioList() 
        ArrayList<MusicBean> musicBeanArrayList=new ArrayList<>();
        try 
            final Cursor mCursor = getContentResolver().query(
                    MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                    new String[]MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.ALBUM_ID,MediaStore.Audio.Media.ARTIST,MediaStore.Audio.Media.TITLE, null, null,
                    "LOWER(" + MediaStore.Audio.Media.TITLE + ") ASC");

        int count = mCursor.getCount();

        int i = 0;
        if (mCursor.moveToFirst()) 
            do 
                String song=mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
                String path=mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
                long album_id=mCursor.getLong(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID));
                String artist=mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
                Uri sArtworkUri = Uri
                        .parse("content://media/external/audio/albumart");
                Uri albumArtUri = ContentUris.withAppendedId(sArtworkUri, album_id);
                musicBeanArrayList.add(new MusicBean(song,path,albumArtUri.toString(),String.valueOf(album_id),artist));
                /*songs[i] = mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME));
                mAudioPath[i] = mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));*/
                i++;
             while (mCursor.moveToNext());
        

        mCursor.close();
        catch (Exception e)
        
            e.printStackTrace();
        
        return musicBeanArrayList;
    

它会在这一行出现异常而崩溃

bitmap = MediaStore.Images.Media.getBitmap(ctx.getContentResolver(), uri);

在这段代码中,我得到了相应 mp3 文件的专辑封面。 但是这段代码也只是从外部存储中读取,因此这也不应该要求写入权限,因为我只是读取位图而不是写入它。

【问题讨论】:

【参考方案1】:

来自处理“/media/external/audio/albumart”的the MediaProvider code

内部openFile(Uri uri, String mode)

try 
    pfd = openFileAndEnforcePathPermissionsHelper(newUri, mode);
 catch (FileNotFoundException ex) 
    // That didn't work, now try to get it from the specific file
    pfd = getThumb(database, db, audiopath, albumid, null);

所以如果找不到文件,它会调用getThumb

getThumb 呼叫makeThumbInternal

然后在某些条件下,它调用

writeAlbumArt(need_to_recompress, out, compressed, bm);

在最新版本中,writeAlbumArt 调用

final long identity = Binder.clearCallingIdentity();

写之前,应该是解决问题的。但修复是在 2015 年 8 月 27 日提交的,所以只有 Marshmallow 有机会获得修复。

【讨论】:

我可以为此调试吗??【参考方案2】:

需要它是因为 MediaStore 需要它,没有 READ-ONLY; MediaStore 正在根据您的行为访问外部文件,因此是您在阅读。

【讨论】:

【参考方案3】:

您可以使用以下链接https://github.com/android/platform_packages_providers_mediaprovider/blob/master/src/com/android/providers/media/MediaProvider.java 为您提供帮助..

【讨论】:

【参考方案4】:

在清单文件中声明权限如下:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />


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

【讨论】:

是的,我正确阅读了这个问题,您必须至少提供 android.permission.READ_EXTERNAL_STORAGE 我已经给出了这就是我得到歌曲列表的原因

以上是关于音乐播放器要求写入外部存储权限?的主要内容,如果未能解决你的问题,请参考以下文章

IOS iPhone使用MPMusicPlayerController播放外部音乐文件,显示iPod界面

在没有获得任何权限的情况下在网站上自动播放音乐。

android 使用MediaPlayer播放音乐要添加的权限是啥?

android 使用MediaPlayer播放音乐要添加的权限是啥?

如何使用外部附件设备在设备上播放音乐?

C语言实现音乐播放器-MCI mcisendString