安卓动态权限申请+RxPermissions+简单封装+完美复用+用户拒绝后应对方案

 

安卓6.0之后谷歌将权限分为:普通权限,敏感权限。普通权限直接在配置文件中配置即可,敏感权限则需要开发者手动申请,如果大家进行过动态权限申请,可能会发现写法很麻烦,回调也不直观,本文针对动态权限申请做了简单的封装,简化其操作,同时介绍用户拒绝权限再次提示后,如何引导用户进入应用设置页面自行授权。

我们申请权限的思路一般是

1、确认是否拥有权限A(或者多个权限)

2、如果有权限--------执行相应功能

3、如果没有权限----------申请权限

      1、申请通过后-----------执行相应功能

      2、申请被拒绝后----------提示用户或者引导用户自行授权

按照这个思路,我们写代码的话会疯掉,每次申请都要写一遍,这就是为什么我们要封装或者使用现有工具

1、RxPermissions

RxPermissions是基于RxJava2的动态权限框架,对其原理感兴趣的同学可以自行研究,本文只介绍其简单用法

第一步:添加依赖

    compile'com.tbruyelle.rxpermissions:rxpermissions:0.9.4@aar'

    compile'io.reactivex:rxandroid:1.2.1'

第二步:初始化RxPermissions,申请权限,添加回调(别忘记在Mainfest中注册需要的权限)

    private void requestPer() {//RxPermissions获取权限
        RxPermissions permissions = new RxPermissions(this);
        permissions.request(Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.WRITE_EXTERNAL_STORAGE).subscribe(new Observer<Boolean>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Boolean aBoolean) {
                if (aBoolean) {
                    Toast.makeText(MainActivity.this, "获取", Toast.LENGTH_LONG).show();
                } else {
                    Toast.makeText(MainActivity.this, "未获取", Toast.LENGTH_LONG).show();
                }
            }
        });
    }

大家可以直接复用上面的代码,简介的地方就在于我们不用去写一遍

onRequestPermissionsResult

 直观的在一个地方申请、获取权限后执行功能、未获取时提示等。比较简洁,下面介绍自行封装的方式

2、简单的自行封装-适用于整个工程

封装的目的是不需要重复写onRequestPermissionsResult和每次申请都要写一遍申请方法,以及简单直观的回调监控

第一步:创建基类ActivityBase

package com.demo.mybaidumapdemo;

import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by zyy on 2019/9/20.
 */

public class ActivityBase extends Activity {
    private applyPerCallBack callBack;
    private static final int PERMISSION_REQUESTCODE = 100;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    public void requestRunPermisssion(String[] permissions, applyPerCallBack mcallBack){
        callBack = mcallBack;
        List<String> permissionLists = new ArrayList<>();
        for(String permission : permissions){
            if(ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED){
                permissionLists.add(permission);
            }
        }

        if(!permissionLists.isEmpty()){
            ActivityCompat.requestPermissions(this, permissionLists.toArray(new String[permissionLists.size()]), PERMISSION_REQUESTCODE);
        }else{
            //表示全都授权了
            callBack.onGranted();
        }
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode){
            case PERMISSION_REQUESTCODE:
                if(grantResults.length > 0){
                    //存放没授权的权限
                    List<String> deniedPermissions = new ArrayList<>();
                    for(int i = 0; i < grantResults.length; i++){
                        int grantResult = grantResults[i];
                        String permission = permissions[i];
                        if(grantResult != PackageManager.PERMISSION_GRANTED){
                            deniedPermissions.add(permission);
                        }
                    }
                    if(deniedPermissions.isEmpty()){
                        //说明都授权了
                        callBack.onGranted();
                    }else{
                        callBack.onDenied(deniedPermissions);
                    }
                }
                break;
            default:
                break;
        }
    }
}

我们在基类中写好权限申请的方法和事件监控,同时创建回调类,在使用时实现此接口即可

第二步,使用如下

        final int i = ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION);
        if (i != PackageManager.PERMISSION_GRANTED) {//检测是否获取权限
//            requestPer();//没获取权限则申请
            requestRunPermisssion(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE}, new applyPerCallBack() {
                @Override
                public void onGranted() {
                    Toast.makeText(MainActivity.this, "所有权限都授权", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onDenied(List<String> deniedPermission) {
                    for(String permission : deniedPermission){
                        Toast.makeText(MainActivity.this, "被拒绝的权限:" + permission, Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }

注意mainActivity继承ActivityBase

applyPerCallBack代码

import java.util.List;

/**
 * Created by zyy on 2019/9/20.
 */

public interface applyPerCallBack {
    void onGranted();//已授权
    void onDenied(List<String> deniedPermission);//未授权
}

总结:此方法封装需创建一个简单的基类,在使用时直接调用基类方法实现CallBack即可

3、用户拒绝再次提示

用户拒绝再次提示时,即使我们在代码中申请权限,弹框也不会出现,此时该如何引导用户自行开启权限,给用户更人性化的体验,不废话,看代码


import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.support.v7.appcompat.BuildConfig;

import static com.demo.mybaidumapdemo.PermissionsManager.PERMISSION_SETTING_FOR_RESULT;

/**
 * Created by zyy on 2018/3/12.
 * 直接跳转到权限后返回,可以监控权限授权情况,但是,跳转到应用详情页,无法监测权限情况
 * 是否要加以区分,若是应用详情页,则跳转回来后,onRestart检测所求权限,如果授权,则收回提示,如果没授权,则继续提示
 */

public class permissionUtilSetting {
    /**
     * Build.MANUFACTURER判断各大手机厂商品牌
     */
    private static final String MANUFACTURER_HUAWEI = "Huawei";//华为
    private static final String MANUFACTURER_MEIZU = "Meizu";//魅族
    private static final String MANUFACTURER_XIAOMI = "Xiaomi";//小米
    private static final String MANUFACTURER_SONY = "Sony";//索尼
    private static final String MANUFACTURER_OPPO = "OPPO";
    private static final String MANUFACTURER_LG = "LG";
    private static final String MANUFACTURER_VIVO = "vivo";
    private static final String MANUFACTURER_SAMSUNG = "samsung";//三星
    private static final String MANUFACTURER_LETV = "Letv";//乐视
    private static final String MANUFACTURER_ZTE = "ZTE";//中兴
    private static final String MANUFACTURER_YULONG = "YuLong";//酷派
    private static final String MANUFACTURER_LENOVO = "LENOVO";//联想

    public static boolean isAppSettingOpen=false;
    /**
     * 跳转到相应品牌手机系统权限设置页,如果跳转不成功,则跳转到应用详情页
     * 这里需要改造成返回true或者false,应用详情页:true,应用权限页:false
     * @param activity
     */
    public static void GoToSetting(Activity activity){
        switch (Build.MANUFACTURER){
            case MANUFACTURER_HUAWEI://华为
                Huawei(activity);
                break;
            case MANUFACTURER_MEIZU://魅族
                Meizu(activity);
                break;
            case MANUFACTURER_XIAOMI://小米
                Xiaomi(activity);
                break;
            case MANUFACTURER_SONY://索尼
                Sony(activity);
                break;
            case MANUFACTURER_OPPO://oppo
                OPPO(activity);
                break;
            case MANUFACTURER_LG://lg
                LG(activity);
                break;
            case MANUFACTURER_LETV://乐视
                Letv(activity);
                break;
            default://其他
                try {//防止应用详情页也找不到,捕获异常后跳转到设置,这里跳转最好是两级,太多用户也会觉得麻烦,还不如不跳
                    openAppDetailSetting(activity);
//                    activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
                }catch (Exception e){
                    SystemConfig(activity);
                }
                break;
        }
    }

    /**
     * 华为跳转权限设置页
     * @param activity
     */
    public static void Huawei(Activity activity) {
        try {
            Intent intent = new Intent();
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
            ComponentName comp = new ComponentName("com.huawei.systemmanager", "com.huawei.permissionmanager.ui.MainActivity");
            intent.setComponent(comp);
            activity.startActivityForResult(intent,PERMISSION_SETTING_FOR_RESULT);
            isAppSettingOpen=false;
        } catch (Exception e) {
            openAppDetailSetting(activity);
//            activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
        }
    }

    /**
     * 魅族跳转权限设置页,测试时,点击无反应,具体原因不明
     * @param activity
     */
    public static void Meizu(Activity activity) {
        try {
            Intent intent = new Intent("com.meizu.safe.security.SHOW_APPSEC");
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
            activity.startActivity(intent);
            isAppSettingOpen=false;
        }catch (Exception e){
            openAppDetailSetting(activity);
//            activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
        }
    }

    /**
     * 小米,功能正常
     * @param activity
     */
    public static void Xiaomi(Activity activity) {
        try { // MIUI 8 9
            Intent localIntent = new Intent("miui.intent.action.APP_PERM_EDITOR");
            localIntent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity");
            localIntent.putExtra("extra_pkgname", activity.getPackageName());
            activity.startActivityForResult(localIntent, PERMISSION_SETTING_FOR_RESULT);
            isAppSettingOpen=false;
//            activity.startActivity(localIntent);
        } catch (Exception e) {
            try { // MIUI 5/6/7
                Intent localIntent = new Intent("miui.intent.action.APP_PERM_EDITOR");
                localIntent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
                localIntent.putExtra("extra_pkgname", activity.getPackageName());
                activity.startActivityForResult(localIntent, PERMISSION_SETTING_FOR_RESULT);
                isAppSettingOpen=false;
//                activity.startActivity(localIntent);
            } catch (Exception e1) { // 否则跳转到应用详情
                openAppDetailSetting(activity);
//                activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
                //这里有个问题,进入活动后需要再跳一级活动,就检测不到返回结果
//                activity.startActivity(getAppDetailSettingIntent());
            }
        }
    }

    /**
     * 索尼,6.0以上的手机非常少,基本没看见
     * @param activity
     */
    public static void Sony(Activity activity) {
        try {
            Intent intent = new Intent();
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
            ComponentName comp = new ComponentName("com.sonymobile.cta", "com.sonymobile.cta.SomcCTAMainActivity");
            intent.setComponent(comp);
            activity.startActivity(intent);
            isAppSettingOpen=false;
        }catch (Exception e){
            openAppDetailSetting(activity);
//            activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
        }
    }

    /**
     * OPPO
     * @param activity
     */
    public static void OPPO(Activity activity) {
        try {
            Intent intent = new Intent();
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
            ComponentName comp = new ComponentName("com.color.safecenter", "com.color.safecenter.permission.PermissionManagerActivity");
            intent.setComponent(comp);
            activity.startActivity(intent);
            isAppSettingOpen=false;
        }catch (Exception e){
            openAppDetailSetting(activity);
//            activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
        }
    }

    /**
     * LG经过测试,正常使用
     * @param activity
     */
    public static void LG(Activity activity) {
        try {
            Intent intent = new Intent("android.intent.action.MAIN");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
            ComponentName comp = new ComponentName("com.android.settings", "com.android.settings.Settings$AccessLockSummaryActivity");
            intent.setComponent(comp);
            activity.startActivity(intent);
            isAppSettingOpen=false;
        }catch (Exception e){
            openAppDetailSetting(activity);
//            activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
        }
    }

    /**
     * 乐视6.0以上很少,基本都可以忽略了,现在乐视手机不多
     * @param activity
     */
    public static void Letv(Activity activity) {
        try {
            Intent intent = new Intent();
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
            ComponentName comp = new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.PermissionAndApps");
            intent.setComponent(comp);
            activity.startActivity(intent);
            isAppSettingOpen=false;
        }catch (Exception e){
            openAppDetailSetting(activity);
//            activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
        }
    }

    /**
     * 只能打开到自带安全软件
     * @param activity
     */
    public static void _360(Activity activity) {
        try {
            Intent intent = new Intent("android.intent.action.MAIN");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
            ComponentName comp = new ComponentName("com.qihoo360.mobilesafe", "com.qihoo360.mobilesafe.ui.index.AppEnterActivity");
            intent.setComponent(comp);
            activity.startActivity(intent);
        }catch (Exception e){
            openAppDetailSetting(activity);
//            activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
        }
    }
    /**
     * 系统设置界面
     * @param activity
     */
    public static void SystemConfig(Activity activity) {
        Intent intent = new Intent(Settings.ACTION_SETTINGS);
        activity.startActivity(intent);
    }
    /**
     * 获取应用详情页面
     * @return
     */
    private static Intent getAppDetailSettingIntent(Activity activity) {
        Intent localIntent = new Intent();
        localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (Build.VERSION.SDK_INT >= 9) {
            localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
            localIntent.setData(Uri.fromParts("package", activity.getPackageName(), null));
        } else if (Build.VERSION.SDK_INT <= 8) {
            localIntent.setAction(Intent.ACTION_VIEW);
            localIntent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails");
            localIntent.putExtra("com.android.settings.ApplicationPkgName", activity.getPackageName());
        }
        return localIntent;
    }
    public static void openAppDetailSetting(Activity activity){
        activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT);
        isAppSettingOpen=true;
    }
}

码字不易,转载请注明出处

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于Android项目中的网络请求,RxJava、Retrofit和MVP是常用的框架组合。下面是一个简单的网络框架封装示例: 首先,在项目中引入RxJava和Retrofit的依赖。 ``` implementation 'io.reactivex.rxjava2:rxjava:2.2.19' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0' ``` 然后,创建一个Retrofit的单例类,用于进行网络请求的初始化和配置。 ```java public class RetrofitClient { private static Retrofit retrofit; private static final String BASE_URL = "https://api.example.com/"; public static Retrofit getClient() { if (retrofit == null) { retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); } return retrofit; } } ``` 接下来,创建一个ApiService接口,定义网络请求的方法。 ```java public interface ApiService { @GET("users") Observable<List<User>> getUsers(); } ``` 然后,创建一个DataManager类,用于管理网络请求。 ```java public class DataManager { private ApiService apiService; public DataManager() { apiService = RetrofitClient.getClient().create(ApiService.class); } public Observable<List<User>> getUsers() { return apiService.getUsers(); } } ``` 最后,在MVP的Presenter中调用DataManager类进行网络请求。 ```java public class UserPresenter { private UserView userView; private DataManager dataManager; public UserPresenter(UserView userView) { this.userView = userView; dataManager = new DataManager(); } public void getUsers() { dataManager.getUsers() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<List<User>>() { @Override public void onSubscribe(Disposable d) { // 在请求开始时的操作 } @Override public void onNext(List<User> users) { // 请求成功返回数据时的操作 userView.showUsers(users); } @Override public void onError(Throwable e) { // 请求失败时的操作 userView.showError(e.getMessage()); } @Override public void onComplete() { // 请求完成时的操作 } }); } } ``` 这样,就完成了一个简单的Android RxJava + Retrofit + MVP网络框架封装。你可以根据自己的需要,进行进一步的封装和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值