Android动态请求权限的工具类(可请求多个,并且功能完善)

Android动态请求权限的工具类

Android 6.0(SDK 23)以上才需要用到动态权限。

之前已经写过好多次关于Android动态权限的文章,但是后期发现每次都要进行复制粘贴,还要修改,

还不如写一个自己的工具类,那就方便多了!

网上也有很多关于动态权限的工具类,还有一些框架,
但是我发现有些使用还是挺麻烦,我感觉还是自己这个动态权限的工具类是非常好的。

一.我的动态权限工具类PermissionsUtils使用方法:

1.定义权限数组

 //比如:两个日历权限和一个数据读写权限
 String[] permissions = new String[]{Manifest.permission.WRITE_CALENDAR, Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_EXTERNAL_STORAGE};

一个或者多个权限都是可以的。

2.创建监听权限的接口对象

  //创建监听权限的接口对象
    PermissionsUtils.IPermissionsResult permissionsResult = new PermissionsUtils.IPermissionsResult() {
        @Override
        public void passPermissons() {
            Toast.makeText(MainActivity.this, "权限通过,可以做其他事情!", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void forbitPermissons() {
//            finish();
            Toast.makeText(MainActivity.this, "权限不通过!", Toast.LENGTH_SHORT).show();
        }
    };

这里权限禁止,也可以自己写得详细一些,比如还有什么权限没有通过,但是我感觉没有必要。

3.在Activity重写onRequestPermissionsResult方法

在重写的方法中需要调用工具类的onRequestPermissionsResult方法,这个方法需要传入Activity对象

   @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        //就多一个参数this
        PermissionsUtils.getInstance().onRequestPermissionsResult(this, requestCode, permissions, grantResults);
    }

4.调用checkPermissions方法

这个方法一般在onCreate使用,或者在执行某个事件前使用,在回调方法中觉得是否执行后续的动作!

 //这里的this不是上下文,是Activity对象!
 PermissionsUtils.getInstance().chekPermissions(this, permissions, permissionsResult);

5.属性showSystemSetting

showSystemSetting是一个静态属性,可以设置true和false,表示是否可以跳转到系统设置权限的窗口。

这个属性的作用是如果用户在勾选不再提示权限的情况下,可以帮助用户跳转到系统权限的窗口去设置这个属性。
防止这个权限可能一直没有得到允许的情况。

这个属性默认是true,在权限没有通过的情况,提示用户是否跳转到系统设置权限的窗口。

二.PermissionsUtils工具类的代码

package com.huawei.calendar.myapplication;

import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;

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

/**
 * 权限工具类
 */

public class PermissionsUtils {


    private final int mRequestCode = 100;//权限请求码
    public static boolean showSystemSetting = true;

    private PermissionsUtils() {
    }

    private static PermissionsUtils permissionsUtils;
    private IPermissionsResult mPermissionsResult;

    public static PermissionsUtils getInstance() {
        if (permissionsUtils == null) {
            permissionsUtils = new PermissionsUtils();
        }
        return permissionsUtils;
    }

    public void chekPermissions(Activity context, String[] permissions, @NonNull IPermissionsResult permissionsResult) {
        mPermissionsResult = permissionsResult;

        if (Build.VERSION.SDK_INT < 23) {//6.0才用动态权限
            permissionsResult.passPermissons();
            return;
        }

        //创建一个mPermissionList,逐个判断哪些权限未授予,未授予的权限存储到mPerrrmissionList中
        List<String> mPermissionList = new ArrayList<>();
        //逐个判断你要的权限是否已经通过
        for (int i = 0; i < permissions.length; i++) {
            if (ContextCompat.checkSelfPermission(context, permissions[i]) != PackageManager.PERMISSION_GRANTED) {
                mPermissionList.add(permissions[i]);//添加还未授予的权限
            }
        }

        //申请权限
        if (mPermissionList.size() > 0) {//有权限没有通过,需要申请
            ActivityCompat.requestPermissions(context, permissions, mRequestCode);
        } else {
            //说明权限都已经通过,可以做你想做的事情去
            permissionsResult.passPermissons();
            return;
        }


    }

    //请求权限后回调的方法
    //参数: requestCode  是我们自己定义的权限请求码
    //参数: permissions  是我们请求的权限名称数组
    //参数: grantResults 是我们在弹出页面后是否允许权限的标识数组,数组的长度对应的是权限名称数组的长度,数组的数据0表示允许权限,-1表示我们点击了禁止权限

    public void onRequestPermissionsResult(Activity context, int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        boolean hasPermissionDismiss = false;//有权限没有通过
        if (mRequestCode == requestCode) {
            for (int i = 0; i < grantResults.length; i++) {
                if (grantResults[i] == -1) {
                    hasPermissionDismiss = true;
                }
            }
            //如果有权限没有被允许
            if (hasPermissionDismiss) {
                if (showSystemSetting) {
                    showSystemPermissionsSettingDialog(context);//跳转到系统设置权限页面,或者直接关闭页面,不让他继续访问
                } else {
                    mPermissionsResult.forbitPermissons();
                }
            } else {
                //全部权限通过,可以进行下一步操作。。。
                mPermissionsResult.passPermissons();
            }
        }

    }


    /**
     * 不再提示权限时的展示对话框
     */
    AlertDialog mPermissionDialog;

    private void showSystemPermissionsSettingDialog(final Activity context) {
        final String mPackName = context.getPackageName();
        if (mPermissionDialog == null) {
            mPermissionDialog = new AlertDialog.Builder(context)
                    .setMessage("已禁用权限,请手动授予")
                    .setPositiveButton("设置", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            cancelPermissionDialog();

                            Uri packageURI = Uri.parse("package:" + mPackName);
                            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI);
                            context.startActivity(intent);
                            context.finish();
                        }
                    })
                    .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            //关闭页面或者做其他操作
                            cancelPermissionDialog();
                            //mContext.finish();
                            mPermissionsResult.forbitPermissons();
                        }
                    })
                    .create();
        }
        mPermissionDialog.show();
    }

    //关闭对话框
    private void cancelPermissionDialog() {
        if (mPermissionDialog != null) {
            mPermissionDialog.cancel();
            mPermissionDialog = null;
        }

    }


    public interface IPermissionsResult {
        void passPermissons();

        void forbitPermissons();
    }


}

三.调用工具类的示例代码


package com.huawei.calendar.myapplication;

import android.Manifest;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

import java.security.Permission;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //两个日历权限和一个数据读写权限
        String[] permissions = new String[]{Manifest.permission.WRITE_CALENDAR, Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_EXTERNAL_STORAGE};
//        PermissionsUtils.showSystemSetting = false;//是否支持显示系统设置权限设置窗口跳转
        //这里的this不是上下文,是Activity对象!
        PermissionsUtils.getInstance().chekPermissions(this, permissions, permissionsResult);
    }

    //创建监听权限的接口对象
    PermissionsUtils.IPermissionsResult permissionsResult = new PermissionsUtils.IPermissionsResult() {
        @Override
        public void passPermissons() {
            Toast.makeText(MainActivity.this, "权限通过,可以做其他事情!", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void forbitPermissons() {
//            finish();
            Toast.makeText(MainActivity.this, "权限不通过!", Toast.LENGTH_SHORT).show();
        }
    };

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        //就多一个参数this
        PermissionsUtils.getInstance().onRequestPermissionsResult(this, requestCode, permissions, grantResults);
    }
}

记得在AndroidManifest中添加权限

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

使用效果图

1.申请权限的时候

1

2.有权限没有通过的情况

1

3.点击跳转到系统权限设置页面的时候

3
showSystemSetting属性为true的情况才会提示这个对话框!
我看了其他人动态权限的写法,都没有跳转到设置系统权限的对话框的,但是我感觉这个在需要的时候还是比较管用的。

四.其他的

这个工具类还是比较完善的了,如果需要修改一些字符串或者逻辑可以自己修改,工具类的逻辑应该也是比较清晰的。

android6.0后,仅在manifest.xml清单中配置相关权限时,如果将targetSdkVersion设置为23及以上,部分敏感权限需要动态申请后才能使用;
如果不想处理6.0以上的适配,请将targetSdkVersion设置为22或以下;但是低版本的SDK可能没有高版本的一些属性或者类。

但是注意一点,无论版本高低,需要的权限一定要写在AndroidManifest中,如果在动态权限中申请的权限在Manife中没有写,你会发现他不会询问你这个权限。
所有你不可能获取到这个权限。

如果你在AndroidManifest中写了多个需要动态申请的权限,在动态权限申请的时候可以只申请一个或者一部分。没有问题的。
如果你跳转到这个程序的系统设置权限界面,你会发现AndroidManifest中所有申明的权限都显示在这里,可以对任何一个权限进行禁止或者允许。

1.敏感权限也是危险权限Dangerous-Permisson,能够获取到用户的隐私;

共9类/组

权限组名称
CALENDAR日历
CAMERA相机
CONTACTS联系人
LOCATION定位
MICROPHONE麦克相关,比如录音
PHONE手机状态
SENSORS传感器
SMS短信
STORAGE存储权限
2.详细敏感权限
1 group:android.permission-group.CONTACTS
    permission:android.permission.WRITE_CONTACTS
    permission:android.permission.GET_ACCOUNTS    
    permission:android.permission.READ_CONTACTS

2  group:android.permission-group.PHONE
    permission:android.permission.READ_CALL_LOG
    permission:android.permission.READ_PHONE_STATE 
    permission:android.permission.CALL_PHONE
    permission:android.permission.WRITE_CALL_LOG
    permission:android.permission.USE_SIP
    permission:android.permission.PROCESS_OUTGOING_CALLS
    permission:com.android.voicemail.permission.ADD_VOICEMAIL

3  group:android.permission-group.CALENDAR
    permission:android.permission.READ_CALENDAR
    permission:android.permission.WRITE_CALENDAR

4  group:android.permission-group.CAMERA
    permission:android.permission.CAMERA

5  group:android.permission-group.SENSORS
    permission:android.permission.BODY_SENSORS

6  group:android.permission-group.LOCATION
    permission:android.permission.ACCESS_FINE_LOCATION
    permission:android.permission.ACCESS_COARSE_LOCATION

7  group:android.permission-group.STORAGE
    permission:android.permission.READ_EXTERNAL_STORAGE
    permission:android.permission.WRITE_EXTERNAL_STORAGE

8  group:android.permission-group.MICROPHONE
    permission:android.permission.RECORD_AUDIO

9  group:android.permission-group.SMS
    permission:android.permission.READ_SMS
    permission:android.permission.RECEIVE_WAP_PUSH
    permission:android.permission.RECEIVE_MMS
    permission:android.permission.RECEIVE_SMS
    permission:android.permission.SEND_SMS
    permission:android.permission.READ_CELL_BROADCASTS 

如果需要不妨收藏记下。

共勉:生命太短没有时间留给遗憾,若不是终点,请努力一直前行。

  • 16
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
1.GsonFormat(GsonFormat) 快速将json字符串转换成一个Java Bean,免去我们根据json字符串手写对应Java Bean的过程。 使用方法:快捷键Alt+S也可以使用Alt+Insert选择GsonFormat 2.Android ButterKnife Zelezny 配合ButterKnife实现注解,从此不用写findViewById,想着就爽啊。在Activity,Fragment,Adapter中选中布局xml的资源id自动生成butterknife注解。 使用方法:Ctrl+Shift+B选择图上所示选项 3.Android Code Generator 根据布局文件快速生成对应的Activity,Fragment,Adapter,Menu。 4.Android Parcelable code generator JavaBean序列化,快速实现Parcelable接口。 5.Android Methods Count 显示依赖库中得方法数 6.Lifecycle Sorter 可以根据Activity或者fragment的生命周期对其生命周期方法位置进行先后排序,快捷键Ctrl + alt + K 7.CodeGlance 在右边可以预览代码,实现快速定位 8.findBugs-IDEA 查找bug的插件,Android Studio也提供了代码审查的功能(Analyze-Inspect Code…) 9.ADB WIFI 使用wifi无线调试你的app,无需root权限 也可参考以下文章: Android wifi无线调试App新玩法ADB WIFI 10.AndroidPixelDimenGenerator Android Studio自动生成dimen.xml文件插件 11.JsonOnlineViewer 在Android Studio中请求、调试接口 12.Android Styler 根据xml自动生成style代码的插件 13.Android Drawable Importer 这是一个非常强大的图片导入插件。它导入Android图标与Material图标的Drawable ,批量导入Drawable ,多源导入Drawable(即导入某张图片各种dpi对应的图片) 14.SelectorChapek for Android 通过资源文件命名自动生成Selector文件。 15.GenerateSerialVersionUID 实现Serializable序列化bean 16.genymotion 速度较快的android模拟器 17.LeakCanary 帮助你在开发阶段方便的检测出内存泄露的问题,使用起来更简单方便。 可以参考以下文章: LeakCanary 中文使用说明 18.Android Postfix Completion 可根据后缀快速完成代码,这个属于拓展吧,系统已经有这些功能,如sout、notnull等,这个插件在原有的基础上增添了一些新的功能,我更想做的是通过原作者的代码自己定制功能,那就更爽了 19.Android Holo Colors Generator 通过自定义Holo主题颜色生成对应的Drawable和布局文件 20.dagger-intellij-plugin dagger可视化辅助工具 21.GradleDependenciesHelperPlugin maven gradle 依赖支持自动补全 22.RemoveButterKnife ButterKnife这个第三方库每次更新之后,绑定view的注解都会改变,从bind,到inject,再到bindview,搞得很多人都不敢升级,一旦升级,就会有巨量的代码需要手动修改,非常痛苦 当我们有一些非常棒的代码需要拿到其他项目使用,但是我们发现,那个项目对第三方库的使用是有限制的,我们不能使用butterknife,这时候,我们又得从注解改回findviewbyid 针对上面的两种情况,如果view比较少还好说,如果有几十个view,那么我们一个个的手动删除注解,写findviewbyid语句,简直是一场噩梦(别问我为什么知道这是噩梦) 所以,这种有规律又重复简单的工作为什么不能用一个插件来实现呢?于是RemoveButterKnife的想法就出现了。 具体介绍 23.AndroidProguardPlugin 一键生成项目混淆代码插件,值得你安装~(不过目前可能有些第三方项目的混淆还未添加完全) 24.otto-intellij-plugin otto事件导航工具。 25.eventbus-intellij-plugin eventbus导航插件 26.idea-markdown markdown插件 27.Sexy Editor 设置AS代码编辑区的背景图 首先点击界面的设置按钮 进入设置界面,选中Plugins,右边选择 Browser … ,输入Sexy … 下面自动弹出候选插件,右边点击Install 安装 安装成功 后需要重启AS 重启完成之后 进入设置界面 选择other Setting 下的Sexy Editor , 右侧 insert 一张或多张图片即可,上面的其他设置可以设置方位 间隔时间 透明度等等,设置完成后,要关闭打开的文件,重新打开项目文件即可在代码编辑区显示插入的图片,作为代码编辑区的背景图。 28.folding-plugin 布局文件分组的插件 29.Android-DPI-Calculator DPI计算插件 30.gradle-retrolambda 在java 6 7中使用 lambda表达式插件 修改编译的jdk为java8: 31.Android Studio Prettify 可以将代码中的字符串写在string.xml文件中 这个插件还可以自动书写findViewById 32.Material Theme UI 添加Material主题到你的AS 33..ignore 我 们都知道在Git 中想要过滤掉一些不想提交的文件,可以把相应的文件添加到.gitignore 中,而.gitignore 这个Android Studio 插件根据不同的语言来选择模板,就不用自己在费事添加一些文件了,而且还有自动补全功能,过滤文件再也不要复制文件名了。我们做项目的时候,并不是所有文 件都是要提交的,比如构建的build 文件夹,本地配置文件,每个Module 生成的iml 文件,但是我们每次add,commit 都会不小心把它们添加上去,而gitignore 就是解决这种痛点的,如果你不想提交的文件,就可以在创建项目的时候将这个文件中添加即可,将一些通用的东西屏蔽掉。 34.CheckStyle-IDEA CheckStyle-IDEA 是一个检查代码风格的插件,比如像命名约定,Javadoc,类设计等方面进行代码规范和风格的检查,你们可以遵从像Google Oracle 的Java 代码指南 ,当然也可以按照自己的规则来设置配置文件,从而有效约束你自己更好地遵循代码编写规范。 35.Markdown Navigator github:Markdown Navigator Markdown插件 36.ECTranslation Android Studio Plugin,Translate English to Chinese. Android Studio 翻译插件,可以将英文翻译为中文。 37.PermissionsDispatcher plugin github:PermissionsDispatcher plugin 自动生成6.0权限的代码 38.WakaTime github:WakaTime 记录你在IDE上的工作时间 39.AndroidWiFiADB 无线调试应用 40.AndroidLocalizationer 可用于将项目中的 string 资源自动翻译为其他语言的 Android Studio/IntelliJ IDEA 插件
### 回答1: 如果你想要写一个 Android 的应用程序 (APK),你需要具备一定的编程基础,并掌握使用 Android 开发工具,例如 Android Studio。 1. 安装 Android Studio。 2. 新建一个 Android 项目。 3. 设计应用程序的用户界面 (UI)。 4. 编写代码来实现应用程序的功能。 5. 测试应用程序。 6. 打包应用程序为 APK 文件。 7. 将 APK 安装到手机或模拟器上进行测试。 8. 将 APK 发布到应用商店或直接分发给用户。 在开始写代码之前,建议先了解 Android 的基本概念,例如 Activity、Intent、Fragment 等。也建议学习一些基本的 Java 编程知识,因为 Android 的应用程序是使用 Java 编写的。 ### 回答2: 编写一个Android APK需要使用Java或Kotlin编程语言,并使用Android Studio作为开发工具。以下是一个简单的例子来演示如何编写一个Android APK: 首先,你需要创建一个新的Android项目并配置好所需的权限和依赖项。然后,在项目的MainActivity类中,你可以编写应用的主要功能。 在onCreate方法中,你可以设置应用的布局,创建必要的视图和按钮,并设置点击事件。例如,你可以创建一个按钮,并为其设置一个点击监听器。 在点击监听器中,你可以编写一些代码来执行特定的功能。例如,你可以在按钮点击时显示一个简单的Toast消息。 此外,你还可以编写其他功能,如网络请求、数据存储、调用其他应用程序等。这些功能可以在MainActivity类或其他辅助类中实现。 最后,你需要构建并打包应用。通过Android Studio的Build选项可以生成APK文件。你可以将该APK文件安装到Android设备或模拟器上进行测试。 总结起来,编写一个Android APK涉及创建Android项目、编写功能代码、设置布局和视图、使用事件监听器、打包APK等步骤。这只是一个简单的例子,实际上你可以根据自己的需求和时间进行更复杂的开发。 ### 回答3: 编写一个Android APK(Android Application Package)需要一定的编程知识和技能。下面是一个简单的示例,展示如何编写一个最基本的Android APK: 1. 首先,在电脑上安装Java开发工具包(JDK),然后安装一个集成开发环境(IDE),例如Android Studio。 2. 打开Android Studio,选择创建一个新的项目。 3. 在项目设置中选择一个适合的应用程序名称和包名称。 4. 创建一个新的活动(Activity),该活动将作为应用程序的入口点。 5. 在活动的布局文件中设计应用程序的用户界面(如按钮、文本框等)。 6. 在活动的Java文件中编写代码,实现应用程序的逻辑。例如,当用户点击按钮时,执行一个特定的操作。 7. 使用安卓的Manifest文件配置应用程序的权限和其他应用程序相关的设置。 8. 调试应用程序,确保它在模拟器或真实设备上正常运行。 9. 构建APK文件,这是一个已经打包和编译的应用程序文件。 10. 将APK文件安装到Android设备上进行测试和使用。 以上只是一个简单的示例,一个真正的Android APK可能会有更多的功能和复杂性。编写一个Android APK需要深入了解Java编程语言、Android开发框架和与设备交互的各种API。因此,对于初学者来说,从简单的应用程序开始,并参考一些教程和指南是非常重要的。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

峥嵘life

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

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

抵扣说明:

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

余额充值