有一个 PermissionUtils 动态权限工具类,但它只是一个通用权限请求框架,没有针对 Android 13~16 的存储权限变化做专门处理,补充一个,针对 Android 13~16 的存储权限变化做专门处理。Android 13(API 33) 开始,存储权限被拆分成了媒体类型权限(READ_MEDIA_IMAGESREAD_MEDIA_VIDEOREAD_MEDIA_AUDIO),Android 14/15/16 又进一步收紧了非媒体文件的访问。

适配 Android 16 的 StoragePermissionUtils

package com.nyw.mvvmmode.utils;

import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.os.Environment;
import android.provider.Settings;

/**
 * 存储权限工具类(适配 Android 6 ~ Android 16+)
 * 功能:
 * - 自动判断系统版本,使用对应权限策略
 * - Android 13+ 使用新的媒体权限
 * - Android 11+ 使用 MANAGE_EXTERNAL_STORAGE
 * - Android 6-10 使用传统读写权限
 */
public class StoragePermissionUtils {

    // 请求码
    public static final int REQUEST_STORAGE_PERMISSION = 200;

    /**
     * 检查存储权限
     */
    public static boolean checkStoragePermission(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            // Android 11+:检查是否有管理所有文件权限
            return Environment.isExternalStorageManager();
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            // Android 13-16:检查媒体权限
            return PermissionUtils.checkMultiplePermissions(activity, new String[]{
                    android.Manifest.permission.READ_MEDIA_IMAGES,
                    android.Manifest.permission.READ_MEDIA_VIDEO,
                    android.Manifest.permission.READ_MEDIA_AUDIO
            });
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // Android 6-10:检查读写权限
            return PermissionUtils.checkMultiplePermissions(activity, new String[]{
                    android.Manifest.permission.READ_EXTERNAL_STORAGE,
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE
            });
        }
        // Android 5.1 及以下默认有权限
        return true;
    }

    /**
     * 请求存储权限
     */
    public static void requestStoragePermission(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            // Android 11+:跳转到管理所有文件权限页面
            Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
            activity.startActivityForResult(intent, REQUEST_STORAGE_PERMISSION);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            // Android 13-16:请求媒体权限
            PermissionUtils.requestMultiplePermissions(activity, new String[]{
                    android.Manifest.permission.READ_MEDIA_IMAGES,
                    android.Manifest.permission.READ_MEDIA_VIDEO,
                    android.Manifest.permission.READ_MEDIA_AUDIO
            });
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // Android 6-10:请求传统读写权限
            PermissionUtils.requestMultiplePermissions(activity, new String[]{
                    android.Manifest.permission.READ_EXTERNAL_STORAGE,
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE
            });
        }
    }

    /**
     * 处理权限请求结果
     * 在 Activity 的 onRequestPermissionsResult 中调用
     */
    public static void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == PermissionUtils.REQUEST_CODE_PERMISSION) {
            PermissionUtils.onRequestPermissionsResult(null, requestCode, permissions, grantResults);
        }
    }

    /**
     * 处理从设置页返回的结果
     * 在 Activity 的 onActivityResult 中调用
     */
    public static boolean onActivityResult(Activity activity, int requestCode) {
        if (requestCode == REQUEST_STORAGE_PERMISSION) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                return Environment.isExternalStorageManager();
            }
        }
        return false;
    }
}

PermissionUtils 代码

package com.nyw.mvvmmode.utils;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

/**
 * Android 6.0+ 动态权限工具类
 * 支持:单个/多个权限请求、权限检查、引导用户去设置页开启权限
 */
public class PermissionUtils {
    // 权限请求码(自定义,确保唯一)
    public static final int REQUEST_CODE_PERMISSION = 100;
    // 跳转到应用设置页的请求码
    public static final int REQUEST_CODE_SETTINGS = 101;

    // 新增:使用弱引用持有Activity,避免内存泄漏
    private static WeakReference<Activity> sActivityWeakRef;

    /**
     * 检查单个权限是否已授予
     */
    public static boolean checkSinglePermission(Context context, @NonNull String permission) {
        // Android 6.0 以下默认授予所有权限
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            return true;
        }
        return ContextCompat.checkSelfPermission(context, permission)
                == PackageManager.PERMISSION_GRANTED;
    }

    /**
     * 检查多个权限是否已全部授予
     */
    public static boolean checkMultiplePermissions(Context context, @NonNull String[] permissions) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || permissions == null || permissions.length == 0) {
            return true;
        }
        for (String permission : permissions) {
            if (!checkSinglePermission(context, permission)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 筛选出未授予的权限
     */
    public static List<String> getDeniedPermissions(Context context, @NonNull String[] permissions) {
        List<String> deniedPermissions = new ArrayList<>();
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || permissions == null || permissions.length == 0) {
            return deniedPermissions;
        }
        for (String permission : permissions) {
            if (!checkSinglePermission(context, permission)) {
                deniedPermissions.add(permission);
            }
        }
        return deniedPermissions;
    }

    /**
     * 请求单个权限
     */
    public static void requestSinglePermission(Activity activity, @NonNull String permission) {
        requestMultiplePermissions(activity, new String[]{permission});
    }

    /**
     * 请求多个权限
     */
    public static void requestMultiplePermissions(Activity activity, @NonNull String[] permissions) {
        if (activity == null || permissions == null || permissions.length == 0) {
            return;
        }
        // 弱引用持有Activity
        sActivityWeakRef = new WeakReference<>(activity);
        // 筛选未授予的权限
        List<String> deniedPermissions = getDeniedPermissions(activity, permissions);
        if (deniedPermissions.isEmpty()) {
            // 所有权限已授予,直接回调成功
            if (sPermissionCallback != null) {
                sPermissionCallback.onPermissionGranted(permissions);
            }
            return;
        }
        // 发起权限请求
        ActivityCompat.requestPermissions(
                activity,
                deniedPermissions.toArray(new String[0]),
                REQUEST_CODE_PERMISSION
        );
    }

    /**
     * 检查是否需要显示权限说明(用户之前拒绝过权限)
     */
    public static boolean shouldShowPermissionRationale(Activity activity, @NonNull String permission) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || activity == null) {
            return false;
        }
        return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission);
    }

    /**
     * 跳转到应用设置页(用户永久拒绝权限时调用)
     */
    public static void goToAppSettings(Activity activity) {
        if (activity == null) {
            return;
        }
        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
        intent.setData(uri);
        activity.startActivityForResult(intent, REQUEST_CODE_SETTINGS);
    }

    // ====================== 权限请求回调 ======================
    private static PermissionCallback sPermissionCallback;

    public interface PermissionCallback {
        /**
         * 所有请求的权限都已授予
         */
        void onPermissionGranted(String[] grantedPermissions);

        /**
         * 部分/全部权限被拒绝
         */
        void onPermissionDenied(String[] deniedPermissions, boolean isPermanentlyDenied);
    }

    /**
     * 设置权限请求回调(需在请求权限前设置)
     */
    public static void setPermissionCallback(PermissionCallback callback) {
        sPermissionCallback = callback;
    }

    /**
     * 清除权限回调(避免内存泄漏)
     */
    public static void clearPermissionCallback() {
        sPermissionCallback = null;
        sActivityWeakRef = null; // 清除弱引用
    }

    /**
     * 在 Activity 的 onRequestPermissionsResult 中调用,处理权限请求结果
     */
    public static void onRequestPermissionsResult(Activity activity, int requestCode,
                                                  @NonNull String[] permissions, @NonNull int[] grantResults) {
        // 检查Activity是否存活
        if (activity == null || activity.isFinishing() || activity.isDestroyed()) {
            clearPermissionCallback();
            return;
        }
        // 检查弱引用是否有效
        if (sActivityWeakRef != null && sActivityWeakRef.get() != activity) {
            clearPermissionCallback();
            return;
        }
        if (requestCode != REQUEST_CODE_PERMISSION || sPermissionCallback == null) {
            return;
        }

        List<String> grantedPermissions = new ArrayList<>();
        List<String> deniedPermissions = new ArrayList<>();
        boolean isPermanentlyDenied = false;

        for (int i = 0; i < permissions.length; i++) {
            if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                grantedPermissions.add(permissions[i]);
            } else {
                deniedPermissions.add(permissions[i]);
                // 检查是否永久拒绝(用户勾选了“不再询问”)
                if (!shouldShowPermissionRationale(activity, permissions[i])) {
                    isPermanentlyDenied = true;
                }
            }
        }

        if (deniedPermissions.isEmpty()) {
            // 所有权限都授予
            sPermissionCallback.onPermissionGranted(grantedPermissions.toArray(new String[0]));
        } else {
            // 部分/全部权限被拒绝
            sPermissionCallback.onPermissionDenied(deniedPermissions.toArray(new String[0]), isPermanentlyDenied);
        }
    }
}

这样做的好处

  1. 不重复造轮子:存储权限的具体规则在 StoragePermissionUtils 中处理,底层调用你已有的 PermissionUtils
  2. 适配到 Android 16
    • Android 13-16 使用新的媒体权限
    • Android 11-12 使用 MANAGE_EXTERNAL_STORAGE
    • Android 6-10 使用旧的读写权限
  3. 完整的结果处理
    • 动态权限结果 → onRequestPermissionsResult
    • 从系统设置页返回 → onActivityResult

在 Activity 中调用:

// 检查并请求存储权限
if (!StoragePermissionUtils.checkStoragePermission(this)) {
    StoragePermissionUtils.requestStoragePermission(this);
}

在 Activity 中处理权限回调::

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    StoragePermissionUtils.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (StoragePermissionUtils.onActivityResult(this, requestCode)) {
        // 用户从设置页返回并开启了权限
        Toast.makeText(this, "存储权限已开启", Toast.LENGTH_SHORT).show();
        // 继续执行需要权限的操作
    }
}

这样就不需要重新写一个全新的权限工具类,只需要更新 StoragePermissionUtils,就能在 Android 16 上正常使用。

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐