You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 13应用首次启动未弹出存储权限请求的问题

Android 13 存储权限请求弹窗不显示的解决方案

问题根源

Android 13(API 33)重构了媒体存储权限体系,原READ_EXTERNAL_STORAGE权限在该版本下不再适用于音频、图片等媒体文件,必须使用对应细分权限(比如READ_MEDIA_AUDIO)。你的代码和Manifest仍在使用旧权限,导致系统无法触发权限请求弹窗。

修复方案

1. 更新AndroidManifest.xml权限配置

添加Android 13专属的音频读取权限,同时保留旧权限兼容低版本:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
    android:maxSdkVersion="32"/>
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"
    android:minSdkVersion="33"/>

2. 适配不同版本的权限检查与请求逻辑

修改checkPermission和requestPermission方法,根据系统版本切换目标权限:

// 需添加导入:import android.os.Build;

boolean checkPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        // Android 13+ 检查音频媒体权限
        return ContextCompat.checkSelfPermission(MainApp.this, Manifest.permission.READ_MEDIA_AUDIO) == PackageManager.PERMISSION_GRANTED;
    } else {
        // 低版本检查旧存储权限
        return ContextCompat.checkSelfPermission(MainApp.this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
    }
}

void requestPermission() {
    String[] permissions;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        permissions = new String[]{Manifest.permission.READ_MEDIA_AUDIO};
    } else {
        permissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE};
    }

    if (ActivityCompat.shouldShowRequestPermissionRationale(MainApp.this, permissions[0])) {
        Toast.makeText(MainApp.this, "需要读取音频权限才能加载本地音乐,请在设置中开启", Toast.LENGTH_LONG).show();
    }
    ActivityCompat.requestPermissions(MainApp.this, permissions, 123);
}

3. 处理权限授权后的逻辑

原代码请求权限后直接return,用户授权后不会重新加载音乐列表,需重写权限回调并抽离音乐加载逻辑:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == 123) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // 授权成功,重新加载音乐列表
            loadMusicList();
        } else {
            Toast.makeText(this, "未授予权限,无法加载本地音乐", Toast.LENGTH_SHORT).show();
            textView.setVisibility(TextView.VISIBLE);
        }
    }
}

// 抽离音乐加载逻辑为独立方法
private void loadMusicList() {
    songsList.clear();
    String[] projection = {MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.DURATION};
    String selection = MediaStore.Audio.Media.IS_MUSIC + "!=0";

    Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, null, null);

    if (cursor != null) {
        while (cursor.moveToNext()) {
            AudioModel songData = new AudioModel(cursor.getString(1), cursor.getString(0), cursor.getString(2));
            if (new File(songData.getPath()).exists()) {
                songsList.add(songData);
            }
        }
        cursor.close(); // 关闭Cursor避免内存泄漏
    }

    if (songsList.size() == 0) {
        textView.setVisibility(TextView.VISIBLE);
        recyclerView.setVisibility(View.GONE);
    } else {
        textView.setVisibility(View.GONE);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(new MusicListAdapter(songsList, getApplicationContext()));
    }
}

最后修改onCreate方法,调用抽离后的加载逻辑:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main_app);
    recyclerView = findViewById(R.id.recylerView);
    textView = findViewById(R.id.warning);
    
    if (checkPermission()) {
        loadMusicList();
    } else {
        requestPermission();
    }
}

内容的提问来源于stack exchange,提问作者NAUFAL_ ARZ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 20:02:22