Android 6.0以上 须要运行时申请的权限

转载:http://www.cnblogs.com/tangs/articles/6377347.htmlhtml

自从Android6.0发布以来,在权限上作出了很大的变更,再也不是以前的只要在manifest设置就能够任意获取权限,而是更加的注重用户的隐私和体验,不会再强迫用户因拒毫不该拥有的权限而致使的没法安装的事情,也不会再不征求用户受权的状况下,就能够任意的访问用户隐私,并且即便在受权以后也能够及时的更改权限。这就是6.0版本作出的更拥护和注重用户的一大致现。android

1、认知

今天咱们就来学习下Android6.0的权限管理。安全

Android6.0系统把权限分为两个级别:网络

一个是Normal Permissions,即普通权限,这类权限不会潜藏有侵害用户隐私和安全的问题,好比,访问网络的权限,访问WIFI的权限等;框架

另外一类是Dangerous Permissions,即危险权限,这类权限会直接的威胁到用户的安全和隐私问题,好比说访问短信,相册等权限。ide

可是到底哪些是普通权限和危险权限呢,这里给出分类,你们在使用时以便参考。工具

一、Normal Permissions (普通权限)布局

  • ACCESS_LOCATION_EXTRA_COMMANDS
  • ACCESS_NETWORK_STATE
  • ACCESS_NOTIFICATION_POLICY
  • ACCESS_WIFI_STATE
  • BLUETOOTH
  • BLUETOOTH_ADMIN
  • BROADCAST_STICKY
  • CHANGE_NETWORK_STATE
  • CHANGE_WIFI_MULTICAST_STATE
  • CHANGE_WIFI_STATE
  • DISABLE_KEYGUARD
  • EXPAND_STATUS_BAR
  • GET_PACKAGE_SIZE
  • INSTALL_SHORTCUT
  • INTERNET
  • KILL_BACKGROUND_PROCESSES
  • MODIFY_AUDIO_SETTINGS
  • NFC
  • READ_SYNC_SETTINGS
  • READ_SYNC_STATS
  • RECEIVE_BOOT_COMPLETED
  • REORDER_TASKS
  • REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
  • REQUEST_INSTALL_PACKAGES
  • SET_ALARM
  • SET_TIME_ZONE
  • SET_WALLPAPER
  • SET_WALLPAPER_HINTS
  • TRANSMIT_IR
  • UNINSTALL_SHORTCUT
  • USE_FINGERPRINT
  • VIBRATE
  • WAKE_LOCK
  • WRITE_SYNC_SETTINGS

使用以上权限是不会威胁到用户安全的,因此这类权限是能够直接的在manifest里面直接的使用,并且在安装后也会直接的生效了。学习

二、Dangerous Permissions (危险权限)gradle

  • SMS(短信)
    • SEND_SMS
    • RECEIVE_SMS
    • READ_SMS
    • RECEIVE_WAP_PUSH
    • RECEIVE_MMS
  • STORAGE(存储卡)
    • READ_EXTERNAL_STORAGE
    • WRITE_EXTERNAL_STORAGE
  • CONTACTS(联系人)
    • READ_CONTACTS
    • WRITE_CONTACTS
    • GET_ACCOUNTS
  • PHONE(手机)
    • READ_PHONE_STATE
    • CALL_PHONE
    • READ_CALL_LOG
    • WRITE_CALL_LOG
    • ADD_VOICEMAIL
    • USE_SIP
    • PROCESS_OUTGOING_CALLS
  • CALENDAR(日历)
    • READ_CALENDAR
    • WRITE_CALENDAR
  • CAMERA(相机)
    • CAMERA
  • LOCATION(位置)
    • ACCESS_FINE_LOCATION
    • ACCESS_COARSE_LOCATION
  • SENSORS(传感器)
    • BODY_SENSORS
  • MICROPHONE(麦克风)
    • RECORD_AUDIO

危险权限和普通权限也有区别,普通权限是单条的权限,而危险权限是以组展现的,也就是说,当你接受一个危险权限时,不但但接受的是界面上展现的这一个权限,而是它所在这个组里面的其余全部访问权限也将会被自动获取权限,好比,一旦WRITE_CONTACTS被受权了,App也有READ_CONTACTS和GET_ACCOUNTS的权限了。
值得注意的是,这类权限也是须要在manifest中注册的。

ok,光说不练不是咱的风格,咱写东西都是基于本身遇到的问题,而后认真的学习后才记录下来的。一方面巩固本身的知识,另外一方面也但愿能帮助他人提供一点解决方案。

2、实战

实战部分分为几种状况,由于根据咱们的目标SDK版本和Android真机版本的不一样会有不一样的情景,针对普通权限你们都熟悉,就不介绍了,下面一一介绍危险权限的使用情景:

在介绍使用情景以前,先看下个人开发和真机的Android版本。

咱们这里以读取短信息为例讲解整个权限的使用:

一、没有访问权限的状况下:

首先咱们先来设计下布局,以下:

看下代码,很简单,就直接读取短息:

而后,点击界面上的“读取收件箱中的短信”,相信你们都会知道发生什么状况,果真不出意外的程序直接崩溃了,打下日志:

日志中很清晰的告诉咱们,这个异常是由于没有权限而形成的,那么咱们就直接给它加上读取短信的权限来看看吧。

二、在manifest中添加了权限:

在manifest中加了对读取短信的权限,你应该很高兴的等待着总共有多少条短信出如今咱们的界面上,可是,事实很让人崩溃:

再次出现了没有权限的异常,这是为何呢?

这里咱们先不解决这个问题,先来想象一种实际的状况,假如你现有的APP里面有不少使用到了危险权限,有时候你并彻底清楚到底在哪里使用了,可是你的目标版本又是像个人版本同样指向了6.0,而有可能用户的手机是6.0以上的版本,那么这时候你的APP就有可能会出现这种,那么在你还没查清楚有哪些地方使用了危险权限是,该怎么解决呢?

那么你能够这么解决:

修改你build.gradle 中的 targetSdkVersion 目标版本号:

而后手机版本仍是6.0以上,来看看结果:

能够了,哈哈,你很高兴,确实是能够了。

那么聪明的你或许意识到什么了,是的,以版本23,也就是android6.0位分割线,咱们能够得出一个小结论:

当targetSdkVersion >= 23,且真机版本 >= 23时,即便在manifest中添加了相应的危险权限,在没有作相应的处理时(至于怎么处理后面会讲),还时会出现限权的异常,这时manifest中的危险权限并无起做用,可是还必须声明。

当targetSdkVersion < 23,且真机版本 >= 23时,咱们并无作任何的相关处理,就获得了想要的访问权限,这说明在manifest中申请的危险权限起做用了。

咱们在来看另一种状况,就是,假如个人手机比较旧,还没更新6.0的系统,这种状况下又该是什么状况呢?

此次咱们用个4.4.4版本的模拟机

目标targetSdkVersion 为21 来看看结果:

也是能够的,0条信息是由于个人模拟机上没短信,这个数字多少和咱们没有关系。假如targetSdkVersion 为23呢,来看看结果:

很清晰的看出,咱们又获得了正确的结果。

由此咱们也获得了一个小结论:

当咱们的真机系统版本 < 23时,无论咱们的targetSdkVersion 值是否大于23,都不会影响咱们在manifest里面申请的权限,也就是说这时候真机的系统版本在起着主导做用。

由上面的几条结论,咱们应该很清晰的知道了访问权限在真机中的使用情况,可是咱们的手机在升级,版本也会愈来愈高,所以咱们如今的应用不可能一直只支持低版本的使用也不考虑兼顾高版本。因此如今APP权限升级是必然的趋势。

那么如今回来解决上面遗留的问题,当真机和目标版本都大于6.0时出现的权限异常咱们该怎么解决呢?

主要分为三个步骤:

1:检查是否拥有权限

2:假如没有权限,则申请权限

3:处理权限回调

下面咱们分别来看看这几个步骤。

1:检查是否拥有权限

检查是否已拥有了权限,可使用ContextCompat.checkSelfPermission(Context context, String permission);

checkSelfPermission方法中有两个参数,分别是上下文,以及所申请的权限。

若是有权限,请让它直接去读取短信信息。若是没有权限则去申请。

2:申请权限

申请权限则是使用:

public static void requestPermissions(final Activity activity,final String[] permissions, final int requestCode) {}

requestPermissions方法中须要三个参数,当前的activity,所申请的权限,能够是多个,最后就是请求码,既然有请求码说明它会有一个回调,也就是咱们下面要讲的处理回调。

3:处理权限回调

处理权限回调,须要在Activity中重写onRequestPermissionsResult方法:

而后在方法内判断用户是受权了该权限组仍是拒绝受权,若是受权则就去获取短信信息,不然,在这里我只是显示了一个toast提示框。

这里再次说明下,权限组内只要有一个被受权,其余的权限也就有了权限,这也是为何直接使用grantResults[0] == PackageManager.PERMISSION_GRANTED的缘由。

ok,下面来具体的界面显示:

咱们能够看到,当咱们第一次点击读取短信时,它会先检查该应用是否有权限,若是没有,就去申请,这里在界面上对应的就是显示一个受权的对话框,第一次咱们选择了拒绝受权,而后在回调里面就会对应先打印了咱们的一个toast消失提醒咱们拒绝了受权,可是当咱们再次须要读取短信时,它还会去申请受权,这时咱们容许受权,而后咱们就看到了,在显示短信条数的TextView显示了短信的条数。(这里0条是由于的用的模拟器没有短信,这不是重点。)

值得提醒的事,当咱们第一次选择拒绝受权时,当再次点击读取短信时,这时在受权对话框中会多一个“再也不提醒”的提示,当咱们在拒绝了受权,并选择再也不提醒时,那么会出现什么状况呢?请看演示:

当屡次拒绝并选择不提提醒,那么下次再去读取就不会在去申请受权,而是直接在回调中说明用户已拒绝受权。

那么这时候假如用户出于某种须要必须得给应用受权该怎么作呢,其实很简单,在回调中,提醒用户去“设置”里面手动给应用受权,或是发个广播打开设置界面等等均可,这里和我显示的提醒“权限已被拒绝”基本同样,只需在稍微优化便可,这里不在演示。

其实到这里已经差很少讲完,可是,有一个方法咱们能够留一下,那就是shouldShowRequestPermissionRationale,这个方法默认返回false,但当用户在上一次已经拒绝过这个权限申请时,再次须要申请该权限时,就会返回ture,它的寓意是你已经拒绝了一次,结果又弹出个受权框,你须要给我一个解释,为何要受权,也就是说对屡次受权这个权限作出解释,以便用户知道为何必须受权了才可以完成他操做。

下面,来看看它的使用:

我这里就简单的弹出个对话框,说明下为何要用这个权限,而后再次去调用这个申请的权限的方法了,你们能够同回调的方法一块儿封装下,能够更好的应用。

看下界面操做:

讲到这里基本差不地讲完了,这里只是讲了单个申请权限,多个一块儿也是能够的,你们能够本身试试,基本是同样的操做,另外在说明一点,可能咱们一个应用里,须要多出的使用到危险权限,这样就形成咱们须要屡次重写同样的代码,很不便利,因此网上也就出现了不少关于权限框架的开源代码,你们能够自行的使用。

关于打电话的一个完整代码:

复制代码
         callPhoneIntent = new Intent(Intent.ACTION_DIAL);
                callPhoneIntent.setData(uri);
                //若是有权限(实际这个方法只是检测你的APP是否使用了某个权限,可是不能检测是否被限制了)
                if (ContextCompat.checkSelfPermission(SkipWebActivity.this, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
                    startActivity(callPhoneIntent);
                }else{
                    //当屡次拒绝并选择不提提醒,那么下次再去读取就不会在去申请受权,而是直接在回调中说明用户已拒绝受权
                    if(ActivityCompat.shouldShowRequestPermissionRationale(SkipWebActivity.this,Manifest.permission.CALL_PHONE)){
                        showRequestPermission();
                    }else{
                        //只被拒绝过一次该权限的申请
                        ActivityCompat.requestPermissions(SkipWebActivity.this,new String[]{Manifest.permission.CALL_PHONE},REQUEST_CALLPHONE_PERMISSION);
                    }
                }




  /**
     * 申请打电话的权限得的对话框,以前被勾选再也不提醒申请权限
     */
    private void showRequestPermission(){
        new AlertDialog.Builder(SkipWebActivity.this)
                .setTitle("申请权限")
                .setMessage("请求权限拨打电话")
                .setPositiveButton("赞成", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        //申请权限
                        ActivityCompat.requestPermissions(SkipWebActivity.this,new String[]{Manifest.permission.CALL_PHONE},REQUEST_CALLPHONE_PERMISSION);
                    }
                })
                .setNegativeButton("拒绝", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        //拒绝受权
                    }
                })
                .show();
    }

  @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if(requestCode == REQUEST_CALLPHONE_PERMISSION){
            if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
                startActivity(callPhoneIntent);
            }else{
                T.showS("拒绝了打电话权限");
            }
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
复制代码

 工具类的使用: Android开源项目-Easypermissions  http://www.jianshu.com/p/2b3661928e66

相关文章
相关标签/搜索