一、权限介绍

对于6.0以下的权限及在安装的时候,根据权限声明产生一个权限列表,用户只有在同意之后才能完成app的安装,造成了我们想要使用某个app,就要默默忍受其一些不必要的权限(比如是个app都要访问通讯录、短信等)。而在6.0以后,我们可以直接安装,当app需要我们授予不恰当的权限的时候,我们可以予以拒绝(比如:单机的象棋对战,请求访问任何权限,我都是不同意的)。当然你也可以在设置界面对每个app的权限进行查看,以及对单个权限进行授权或者解除授权。

二、权限枚举

新的权限机制更好的保护了用户的隐私,Google将权限分为两类,一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等;另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等。

  • 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_INSTALL_PACKAGES
SET_ALARM
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS
  • Dangerous Permissions:
group:android.permission-group.CONTACTS
permission:android.permission.WRITE_CONTACTS
permission:android.permission.GET_ACCOUNTS
permission:android.permission.READ_CONTACTS 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 group:android.permission-group.CALENDAR
permission:android.permission.READ_CALENDAR
permission:android.permission.WRITE_CALENDAR group:android.permission-group.CAMERA
permission:android.permission.CAMERA group:android.permission-group.SENSORS
permission:android.permission.BODY_SENSORS group:android.permission-group.LOCATION
permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATION group:android.permission-group.STORAGE
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGE group:android.permission-group.MICROPHONE
permission:android.permission.RECORD_AUDIO 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

可以通过adb shell pm list permissions -d -g进行查看。

看到上面的dangerous permissions,会发现一个问题,好像危险权限都是一组一组的,恩,没错,的确是这样的,

那么有个问题:分组对我们的权限机制有什么影响吗?

的确是有影响的,如果app运行在android 6.x的机器上,对于授权机制是这样的。如果你申请某个危险的权限,假设你的app早已被用户授权了同一组的某个危险权限,那么系统会立即授权,而不需要用户去点击授权。比如你的app对READ_CONTACTS已经授权了,当你的app申请WRITE_CONTACTS时,系统会直接授权通过。此外,对于申请时弹出的dialog上面的文本说明也是对整个权限组的说明,而不是单个权限(ps:这个dialog是不能进行定制的)。

不过需要注意的是,不要对权限组过多的依赖,尽可能对每个危险权限都进行正常流程的申请,因为在后期的版本中这个权限组可能会产生变化。

三、相关API

好在运行时相关的API也比较简单,所以适配起来并不会非常痛苦。

API的讲解就跟着申请权限步骤一起了:

  1. 在AndroidManifest文件中添加需要的权限。

    这个步骤和我们之前的开发并没有什么变化,试图去申请一个没有声明的权限可能会导致程序崩溃。

  2. 检查权限

    if (ContextCompat.checkSelfPermission(thisActivity,
    Manifest.permission.READ_CONTACTS)
    != PackageManager.PERMISSION_GRANTED) {
    }else{
    //
    }
  3. 这里涉及到一个API,ContextCompat.checkSelfPermission,主要用于检测某个权限是否已经被授予,方法返回值为PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED。当返回DENIED就需要进行申请授权了。

  4. 申请授权

     ActivityCompat.requestPermissions(thisActivity,
    new String[]{Manifest.permission.READ_CONTACTS},
    MY_PERMISSIONS_REQUEST_READ_CONTACTS);
  5. 该方法是异步的,第一个参数是Context;第二个参数是需要申请的权限的字符串数组;第三个参数为requestCode,主要用于回调的时候检测。可以从方法名requestPermissions以及第二个参数看出,是支持一次性申请多个权限的,系统会通过对话框逐一询问用户是否授权。

  6. 处理权限申请回调

    @Override
    public void onRequestPermissionsResult(int requestCode,
    String permissions[], int[] grantResults) {
    switch (requestCode) {
    case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
    // If request is cancelled, the result arrays are empty.
    if (grantResults.length > 0
    && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission was granted, yay! Do the
    // contacts-related task you need to do. } else { // permission denied, boo! Disable the
    // functionality that depends on this permission.
    }
    return;
    }
    }
    }
  7. ok,对于权限的申请结果,首先验证requestCode定位到你的申请,然后验证grantResults对应于申请的结果,这里的数组对应于申请时的第二个权限字符串数组。如果你同时申请两个权限,那么grantResults的length就为2,分别记录你两个权限的申请结果。如果申请成功,就可以做你的事情了~

当然,到此我们的权限申请的不走,基本介绍就如上述。不过还有个API值得提一下:

// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS))
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission. }

这个API主要用于给用户一个申请权限的解释,该方法只有在用户在上一次已经拒绝过你的这个权限申请。也就是说,用户已经拒绝一次了,你又弹个授权框,你需要给用户一个解释,为什么要授权,则使用该方法。

那么将上述几个步骤结合到一起就是:// Here, thisActivity is the current activity

if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) { // Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) { // Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission. } else { // No explanation needed, we can request the permission. ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS); // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
四、简单的例子

这里写一个简单的例子,针对于运行时权限。相信大家在最开始接触Android的时候,都利用Intent实验了打电话、发短信等功能。

我们看看直接拨打电话在Android 6.x的设备上权限需要如何处理。

当然代码非常简单:

package com.zhy.android160217;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast; public class MainActivity extends AppCompatActivity
{ private static final int MY_PERMISSIONS_REQUEST_CALL_PHONE = 1; @Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} public void testCall(View view)
{
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.CALL_PHONE)
!= PackageManager.PERMISSION_GRANTED)
{ ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CALL_PHONE},
MY_PERMISSIONS_REQUEST_CALL_PHONE);
} else
{
callPhone();
}
} public void callPhone()
{
Intent intent = new Intent(Intent.ACTION_CALL);
Uri data = Uri.parse("tel:" + "10086");
intent.setData(data);
startActivity(intent);
} @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
{ if (requestCode == MY_PERMISSIONS_REQUEST_CALL_PHONE)
{
if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
callPhone();
} else
{
// Permission Denied
Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT).show();
}
return;
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}

在Android 6.x上运行是,点击testCall,即会弹出授权窗口,如何你Allow则直接拨打电话,如果Denied则Toast弹出”Permission Denied”。

例子很简单,不过需要注意的是,对于Intent这种方式,很多情况下是不需要授权的甚至权限都不需要的,比如:你是到拨号界面而不是直接拨打电话,就不需要去申请权限;打开系统图库去选择照片;调用系统相机app去牌照等。更多请参考Consider Using an Intent.

当然,上例也说明了并非所有的通过Intent的方式都不需要申请权限。一般情况下,你是通过Intent打开另一个app,让用户通过该app去做一些事情,你只关注结果(onActivityResult),那么权限是不需要你处理的,而是由打开的app去处理。

Android适配API23之后权限的动态申请的更多相关文章

  1. android6.0以上权限动态申请,有视频链接可以看效果。

    android6.0以上某些权限需要动态申请,虽然现在大多的手机系统版本在6.0,但是升级到6.0及以上是迟早的事,所以如何能够更好的控制动态申请权限时能有好的提示用户,及给用户带去更好的体验,是需要 ...

  2. Android之动态申请权限(API23以上需求)

    API 23之前的版本都是自动获取权限,而从 Android 6.0 开始添加了权限申请的需求,更加安全. 这里以单个存储权限为例: · 在 Manifest 中添加访问权限:(只需设置可写,因为可写 ...

  3. android:动态申请权限(一)

    环境: android版本6.0 对应SDK版本23 动态申请权限说明:所有动态申请的权限,必须在AndroidManifest.xml中进行声明 步骤 1.新建一个android工程 默认创建即可 ...

  4. android 权限动态申请

    名字其实有点让人感觉高大上"权限动态申请",其实也没有什么, 以前做Android程序的时候,比如需要打开摄像头 那么需要在 然后就可以了, 但是Android6.0之后呢,有些权 ...

  5. Android 动态申请权限问题【转】

    Android 动态申请权限问题 感谢大佬:https://www.jianshu.com/p/2324a2bdb3d4 感谢大佬:https://blog.csdn.net/weixin_42910 ...

  6. Android 动态申请权限

    AndroidManifest.xml(清单文件)添加需要的权限 <uses-permission android:name="android.permission.ACCESS_CO ...

  7. Android权限之动态权限

    安卓系统的权限管理机制从API 23 (也就是Android 6.0 又叫做 Android M,)之后发生了比较大的改变,在一些比较危险的权限上要求必须申请动态权限,即使你在AndroidMainf ...

  8. 说说Android6.0动态申请权限的那些坑

    白天在做SDK23版本的适配,遇到了不少坑,现在抽空记下来,以此为戒. 首先要知道哪些坑,就得先了解一些定义和基本使用方式. 那么先介绍一下动态申请的权限分组情况. 下面的权限组是由谷歌官方定义的,目 ...

  9. Android6.0动态申请权限那些坑--以及避免用户选择不再提示后无法获取权限的问题

    Android 6.0 为了保护用户隐私,将一些权限的申请放在了应用运行的时候去申请, 比如以往的开发中,开发人员只需要将需要的权限在清单文件中配置即可,安装后用户可以在设置中的应用信息中看到:XX应 ...

随机推荐

  1. MFC中 获取新输入编辑框的内容

    //得到原始内容的长度 int len = m_editPoemFileStr.GetLength(); UpdateData(true); //得到新增加的内容 CString  sNewStrin ...

  2. DB2 SQL Error: SQLCODE=-805, SQLSTATE=51002 解决方法

    在操作大量数据时如果发生这种错误,说明不是db2 使用的 package没有绑定,而是 因为资源未释放,导致可以使用此package的资源不足,致使不能连接资源. 在程序中,对PreparedStat ...

  3. 2016.11.29 activiti实战--第19章--统一身份管理(含自定义用户与数组的实现)

    学习资料:<Activiti实战> 第十九章 统一身份管理 本章讲解如何统一业务系统与activiti的用户管理系统. 第5章的时候已经讲解过activiti的用户与组.一般来说业务系统都 ...

  4. Spring3和Quartz2的应用实例

    /** * 任务调度类 * @author Joyce.Luo * @date 2015-3-31 下午03:32:04 * @version V3.0 * @since Tomcat6.0,Jdk1 ...

  5. java查看工具jstack-windows

    Prints Java thread stack traces for a Java process, core file, or remote debug server. This command ...

  6. Vue 内容分发slot

    1.概述 内容分发:混合父组件的内容与子组件自己的模板. 2.单个插槽 当子组件模板只有一个没有属性的插槽时,父组件传入的整个内容片段将插入到插槽所在的 DOM 位置,并替换掉插槽标签本身. 最初在  ...

  7. 【Python】使用scatter()绘制散点图

    绘制简单散点图 要绘制单个点,使用scatter()函数,并向它传递一对x和y坐标,它将在指定位置绘制一个点 import matplotlib.pyplot as plt plt.scatter(2 ...

  8. QTreeWidget 的用法

    Qt QTreeWidget 新建一个Qt Widgets Application,拖拽一个Tree Widget 到 ui 界面上,最后实现的效果如下: 添加代码 //test.h //在头文件里添 ...

  9. Spring学习五----------Bean的配置之Bean的生命周期

    © 版权声明:本文为博主原创文章,转载请注明出处 Bean的生命周期 1.定义 2.初始化 3.使用 4.销毁 初始化和销毁的三种方式 1.实现org.springframework.beans.fa ...

  10. oracle不同用户间访问表不添加用户名(模式)前缀

    默认的情况下,oracle里面的用户A,要访问用户B的表需要带用户B的前缀,如访问用户B的 user表,需要这样访问 select * from B.user;如果想要不添加用户前缀,需要这样处理: ...