告别重复编码:3步封装通用Android权限请求工具类

告别重复编码:3步封装通用Android权限请求工具类

【免费下载链接】easypermissions Simplify Android M system permissions 【免费下载链接】easypermissions 项目地址: https://gitcode.com/gh_mirrors/ea/easypermissions

你是否还在为Android应用中的权限请求逻辑重复编写大量代码?每次新增权限都要复制粘贴相似的检查、请求和回调处理代码?本文将带你基于EasyPermissions库,通过3个简单步骤打造一个可复用的权限请求工具类,彻底解决权限逻辑代码冗余问题。

为什么需要封装权限请求工具类

Android 6.0(API 23)引入动态权限(Runtime Permissions)机制后,开发者需要手动处理权限请求流程。未经封装的权限请求代码通常存在以下问题:

  • 代码冗余:每个权限请求都需要重复编写检查、请求、回调处理代码
  • 逻辑分散:权限相关代码散布在各个Activity或Fragment中,难以维护
  • 不一致性:不同开发者实现的权限处理逻辑风格不一
  • 异常情况:容易忽略"不再询问"等特殊场景处理

EasyPermissions库(README.md)作为Android权限处理的优秀封装,已经简化了基础权限逻辑,但在大型项目中仍需进一步封装以实现全应用统一管理。

准备工作:了解EasyPermissions核心API

在开始封装前,我们先了解EasyPermissions提供的核心能力:

核心方法作用所在文件
hasPermissions()检查是否已获得权限easypermissions/src/main/java/pub/devrel/easypermissions/EasyPermissions.java
requestPermissions()请求权限[easypermissions/src/main/java/pub/devrel/easypermissions/EasyPermissions.java#L137-L154)
onRequestPermissionsResult()处理权限请求结果[easypermissions/src/main/java/pub/devrel/easypermissions/EasyPermissions.java#L171-L208)
somePermissionPermanentlyDenied()检查是否被永久拒绝[easypermissions/src/main/java/pub/devrel/easypermissions/EasyPermissions.java#L225-L229)
AppSettingsDialog引导用户到应用设置界面easypermissions/src/main/java/pub/devrel/easypermissions/AppSettingsDialog.java

EasyPermissions的示例代码展示了基础用法,如app/src/main/java/pub/devrel/easypermissions/sample/MainActivity.java中的相机权限请求:

@AfterPermissionGranted(RC_CAMERA_PERM)
public void cameraTask() {
    if (hasCameraPermission()) {
        // 有权限,执行操作
        Toast.makeText(this, "TODO: Camera things", Toast.LENGTH_LONG).show();
    } else {
        // 无权限,请求权限
        EasyPermissions.requestPermissions(
                this,
                getString(R.string.rationale_camera),
                RC_CAMERA_PERM,
                Manifest.permission.CAMERA);
    }
}

第1步:创建权限工具类基础架构

首先创建一个PermissionHelper工具类,作为权限请求的统一入口。这个类将封装EasyPermissions的核心功能,并提供简洁的API。

public class PermissionHelper {
    private static final String TAG = "PermissionHelper";
    private WeakReference<Activity> mActivity;
    private WeakReference<Fragment> mFragment;
    private OnPermissionCallback mCallback;
    
    // 权限回调接口
    public interface OnPermissionCallback {
        void onPermissionGranted(int requestCode, List<String> perms);
        void onPermissionDenied(int requestCode, List<String> perms);
    }
    
    // 构造方法,支持Activity和Fragment
    public static PermissionHelper with(Activity activity) {
        return new PermissionHelper(activity);
    }
    
    public static PermissionHelper with(Fragment fragment) {
        return new PermissionHelper(fragment);
    }
    
    private PermissionHelper(Activity activity) {
        this.mActivity = new WeakReference<>(activity);
    }
    
    private PermissionHelper(Fragment fragment) {
        this.mFragment = new WeakReference<>(fragment);
    }
    
    // 设置回调监听
    public PermissionHelper setCallback(OnPermissionCallback callback) {
        this.mCallback = callback;
        return this;
    }
    
    // 检查是否有权限
    public boolean hasPermissions(String... perms) {
        Context context = getContext();
        if (context == null) return false;
        return EasyPermissions.hasPermissions(context, perms);
    }
    
    // 获取上下文
    private Context getContext() {
        if (mActivity != null && mActivity.get() != null) {
            return mActivity.get();
        }
        if (mFragment != null && mFragment.get() != null) {
            return mFragment.get().getActivity();
        }
        return null;
    }
    
    // 获取宿主(Activity或Fragment)
    private Object getHost() {
        if (mActivity != null && mActivity.get() != null) {
            return mActivity.get();
        }
        if (mFragment != null && mFragment.get() != null) {
            return mFragment.get();
        }
        return null;
    }
}

这个基础架构实现了:

  • 支持Activity和Fragment两种使用场景
  • 使用弱引用(WeakReference)避免内存泄漏
  • 定义权限回调接口
  • 封装上下文获取逻辑

第2步:实现权限请求核心逻辑

接下来为工具类添加权限请求的核心实现,包括请求权限方法和结果处理方法:

// 继续在PermissionHelper类中添加

// 请求权限
public void requestPermissions(int requestCode, String rationale, String... perms) {
    Object host = getHost();
    if (host == null) return;
    
    // 如果已经有权限,直接回调成功
    if (hasPermissions(perms)) {
        if (mCallback != null) {
            mCallback.onPermissionGranted(requestCode, Arrays.asList(perms));
        }
        return;
    }
    
    // 构建权限请求
    PermissionRequest request = new PermissionRequest.Builder(getHost(), requestCode, perms)
            .setRationale(rationale)
            .setPositiveButtonText(android.R.string.ok)
            .setNegativeButtonText(android.R.string.cancel)
            .build();
            
    EasyPermissions.requestPermissions(request);
}

// 处理权限请求结果
public static void onRequestPermissionsResult(int requestCode, String[] permissions, 
                                             int[] grantResults, Object host) {
    // 将结果转发给EasyPermissions
    EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, host);
}

同时,我们需要在工具类中实现EasyPermissions的回调接口,统一处理权限结果:

// 让PermissionHelper实现EasyPermissions的回调接口
public class PermissionHelper implements EasyPermissions.PermissionCallbacks {
    // ... 之前的代码 ...
    
    @Override
    public void onPermissionsGranted(int requestCode, List<String> perms) {
        if (mCallback != null) {
            mCallback.onPermissionGranted(requestCode, perms);
        }
    }
    
    @Override
    public void onPermissionsDenied(int requestCode, List<String> perms) {
        if (mCallback != null) {
            mCallback.onPermissionDenied(requestCode, perms);
        }
        
        // 检查是否有永久拒绝的权限
        if (somePermissionPermanentlyDenied(perms)) {
            showAppSettingsDialog(requestCode);
        }
    }
    
    // 检查是否有永久拒绝的权限
    private boolean somePermissionPermanentlyDenied(List<String> perms) {
        Object host = getHost();
        if (host instanceof Activity) {
            return EasyPermissions.somePermissionPermanentlyDenied((Activity) host, perms);
        } else if (host instanceof Fragment) {
            return EasyPermissions.somePermissionPermanentlyDenied((Fragment) host, perms);
        }
        return false;
    }
    
    // 显示应用设置对话框
    private void showAppSettingsDialog(int requestCode) {
        Context context = getContext();
        if (context == null) return;
        
        new AppSettingsDialog.Builder(context)
                .setTitle("权限需要")
                .setRationale("此功能需要以下权限,请在设置中开启:")
                .setPositiveButton("去设置")
                .setNegativeButton("取消")
                .setRequestCode(requestCode)
                .build()
                .show();
    }
}

第3步:使用与扩展工具类

完成工具类封装后,我们来看看如何在Activity或Fragment中使用它。

在Activity中使用

public class MainActivity extends AppCompatActivity {
    private static final int RC_CAMERA_PERM = 123;
    private PermissionHelper mPermissionHelper;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // 初始化权限工具
        mPermissionHelper = PermissionHelper.with(this)
                .setCallback(new PermissionHelper.OnPermissionCallback() {
                    @Override
                    public void onPermissionGranted(int requestCode, List<String> perms) {
                        if (requestCode == RC_CAMERA_PERM) {
                            // 相机权限已授予,执行相机操作
                            openCamera();
                        }
                    }
                    
                    @Override
                    public void onPermissionDenied(int requestCode, List<String> perms) {
                        Toast.makeText(MainActivity.this, "权限被拒绝", Toast.LENGTH_SHORT).show();
                    }
                });
                
        // 点击按钮请求相机权限
        findViewById(R.id.btn_camera).setOnClickListener(v -> {
            mPermissionHelper.requestPermissions(
                    RC_CAMERA_PERM,
                    "需要相机权限来拍摄照片",
                    Manifest.permission.CAMERA);
        });
    }
    
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 
                                          @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        // 将权限结果转发给工具类处理
        PermissionHelper.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }
    
    private void openCamera() {
        // 相机操作实现
    }
}

在Fragment中使用

public class MyFragment extends Fragment {
    private static final int RC_STORAGE_PERM = 124;
    private PermissionHelper mPermissionHelper;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 初始化权限工具
        mPermissionHelper = PermissionHelper.with(this)
                .setCallback(new PermissionHelper.OnPermissionCallback() {
                    @Override
                    public void onPermissionGranted(int requestCode, List<String> perms) {
                        if (requestCode == RC_STORAGE_PERM) {
                            // 存储权限已授予,执行文件操作
                            saveFile();
                        }
                    }
                    
                    @Override
                    public void onPermissionDenied(int requestCode, List<String> perms) {
                        Toast.makeText(getActivity(), "存储权限被拒绝", Toast.LENGTH_SHORT).show();
                    }
                });
    }
    
    // 请求存储权限的方法
    private void requestStoragePermission() {
        mPermissionHelper.requestPermissions(
                RC_STORAGE_PERM,
                "需要存储权限来保存文件",
                Manifest.permission.WRITE_EXTERNAL_STORAGE);
    }
    
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 
                                          @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        // 将权限结果转发给工具类处理
        PermissionHelper.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }
    
    private void saveFile() {
        // 文件保存操作实现
    }
}

高级扩展:添加权限组管理

对于需要多个权限的场景,可以进一步扩展工具类,添加权限组管理功能:

// 在PermissionHelper中添加
private static final Map<String, Integer> PERMISSION_GROUPS = new HashMap<>();

// 静态代码块初始化权限组
static {
    PERMISSION_GROUPS.put("CAMERA_GROUP", 100);
    PERMISSION_GROUPS.put("STORAGE_GROUP", 101);
    PERMISSION_GROUPS.put("LOCATION_GROUP", 102);
}

// 获取权限组对应的请求码
public static int getGroupRequestCode(String groupName) {
    return PERMISSION_GROUPS.getOrDefault(groupName, -1);
}

// 获取权限组包含的权限
public static String[] getGroupPermissions(String groupName) {
    switch (groupName) {
        case "CAMERA_GROUP":
            return new String[]{Manifest.permission.CAMERA};
        case "STORAGE_GROUP":
            return new String[]{
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            };
        case "LOCATION_GROUP":
            return new String[]{
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION
            };
        default:
            return new String[0];
    }
}

// 请求权限组
public void requestPermissionGroup(String groupName, String rationale) {
    int requestCode = getGroupRequestCode(groupName);
    if (requestCode == -1) return;
    
    String[] perms = getGroupPermissions(groupName);
    requestPermissions(requestCode, rationale, perms);
}

使用权限组:

// 请求存储权限组
mPermissionHelper.requestPermissionGroup(
    "STORAGE_GROUP", 
    "需要存储权限来读取和保存文件");

完整工具类代码结构

最终封装的权限请求工具类完整路径建议放在:app/src/main/java/pub/devrel/easypermissions/util/PermissionHelper.java,其核心结构如下:

PermissionHelper
├── 构造方法
│   ├── with(Activity)
│   └── with(Fragment)
├── 配置方法
│   └── setCallback(OnPermissionCallback)
├── 核心方法
│   ├── hasPermissions(String...)
│   ├── requestPermissions(int, String, String...)
│   ├── requestPermissionGroup(String, String)
│   └── onRequestPermissionsResult(...)
└── 回调接口
    ├── onPermissionGranted(int, List<String>)
    └── onPermissionDenied(int, List<String>)

总结与最佳实践

通过本文介绍的3个步骤,我们基于EasyPermissions库成功封装了一个通用的权限请求工具类。这个工具类具有以下优点:

  1. 使用简单:一行代码即可发起权限请求
  2. 支持多种场景:兼容Activity和Fragment
  3. 自动处理异常情况:包括"不再询问"场景
  4. 避免内存泄漏:使用弱引用管理上下文
  5. 易于扩展:支持权限组和自定义对话框

在实际项目中使用时,建议遵循以下最佳实践:

  • 将所有权限请求集中通过工具类处理
  • 为不同权限组定义常量,如LOCATION_PERMISSIONS
  • 统一管理权限请求码,避免冲突
  • 权限 rationale 信息使用资源文件定义,便于国际化
  • onPermissionDenied中向用户解释为何需要该权限

通过这种封装方式,不仅可以大幅减少重复代码,还能保证全应用权限处理逻辑的一致性和可维护性,是Android开发中权限管理的推荐实践。

【免费下载链接】easypermissions Simplify Android M system permissions 【免费下载链接】easypermissions 项目地址: https://gitcode.com/gh_mirrors/ea/easypermissions

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值