(注意:Android O 8.0对于权限更加严格,下面会说一下8.0)
android6.0之后有些危险权限须要手动去受权,就有了运行时权限的处理。下面的表格就是危险权限组:android
权限组名 | 权限名 |
---|---|
CALENDAR 日历 | READ_CALENDAR WRITE_CALENDER |
CAMERA 相机 | CAMERA |
CONTACTS 联系人 | READ_CONTACTS WRITE_CONTACTS GET_ACCOUNTS |
LOCATION 定位 | ACCESS_FINE_LOCATION ACCESS_COARSE_LOCATION |
MICROPHONE 麦克风 | RECORD_AUDIO |
PHONE 电话 | READ_PHONE_STATE CALL_PHONE READ_CALL_LOG WRITE_CALL_LOG ADD_VOICEMAIL USE_SIP PROCESS_OUTGOING_CALLS |
SENSORS 传感器 | BODY_SENSORS |
SMS 短信 | Short Message Service SEND_SMS RECEIVE_SMS READ_SMS RECEIVE_WAP_PUSH RECEIVE_MMS |
STORAGE 数据存储 | READ_EXTRAL_STRORAGE WRITE_EXTERNAL_STORAGE |
申请权限时:
一、在清单文件中声明权限(若是不在这张表中,声明完就能够了)
二、若是在这张表中的权限须要手动来申请git
这些权限6.0之后须要手动申请,,每个权限组中的权限只要有一个权限赞成受权了,整个权限组中的权限就不用重复申请了。
若是若是查看全部的权限,请参考:https://segmentfault.com/a/11...github
传统的申请过程是:
一、在AndroidManifest文件中添加须要的权限。
二、检查权限是否受权
三、申请权限
四、处理受权的结果segmentfault
一步步来:
一、首先在请单文件中声明,这个不用说
二、检查权限是否受权api
if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { //没有受权,编写申请权限代码 }else{ //已经受权,执行操做代码 }
基本上调用checkSelfPermission()函数传入权限参数,返回的结果又两个:
若是是已受权的权限,该方法返回结果是 PackageManager.PERMISSION_GRANTED 常量为 0,
若是是未受权的权限,该方法返回结果是 PackageManager.PERMISSION_DENIED 常量为 -1。
这样就能够判断是否已经受权,来进行下一步的操做。数组
三、若是没有受权,须要申请权限app
ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS);
这是一个异步的方法,第一个参数是Context;第二个参数是须要申请的权限的字符串数组(这个是支持同时申请多个权限,系统会逐个询问是否受权);第三个参数为请求码requestCode,主要用于回调的时候检测。框架
四、处理权限申请的回调结果
重写Activity或者fragment的 onRequestPermissionsResul()方法异步
//权限回调方法 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode){ case 0: //grantResults数组存储的申请的返回结果, //PERMISSION_GRANTED 表示申请成功 if (grantResults.length>0&&grantResults[0]== PackageManager.PERMISSION_GRANTED){ //受权成功, //这里写相应的 操做代码 }else{ //受权失败,能够简单提示用户 Toast.makeText(this, "没有受权继续操做", Toast.LENGTH_SHORT).show(); } break; case 1: //同上 break; default: break; } } 这里稍微说一下,申请的时候是一个一个的申请的话,每次申请都有一个请求码, 这里的grantResults数组就只有一个值,因此都是grantResults[0]来和 PERMISSION_GRANTED来进行比较 若是是一次申请多个权限,grantResults数组返回的值就不止一个,可是,直接遍历 它就行,只要所有知足条件才算申请成功,才能进行相应的操做 通常的写法是:经过 if判断权限是否申请,没有申请,把它加到一个集合里面,把全部的权限都判断一遍 之后,去遍历这个集合,只要有一个没有申请的,就需、要去申请权限, 把这个集合转为数组,传到requestPermissions的第二个参数,而后就处理相应 结果就能够了,遍历grantResults数组,判断是否是所有知足条件
GitHub地址:https://github.com/googlesamp...
EasyPermissions是谷歌封装的一个运行时权限申请的库,简化了操做的过程。
使用过程: 没有什么前后顺序,下面没有按这个顺序。这么作是能够的,固然还有其余的使用方法ide
一、builde gradle中依赖
二、清单文件中声明权限
三、重写onRequestPermissionsResult()方法,把执行操做给easyPermissions来
四、经过hasPermissions检查权限,或者原生的也行,而后去申请权限
五、实现EasyPermissions.PermissionCallbacks接口,重写两个方法,成功或失败
六、在成功或者失败方法中编写要具体作的事。
GitHub地址:
(1)依赖库
dependencies { compile 'pub.devrel:easypermissions:1.0.1' }
(2)再在清单文件中声明要申请的危险权限
若是不声明的话,直接在代码中写也能申请成功,可是好想不会弹出询问框,直接就申请了
(3)申请权限
能够直接申请
EasyPermissions.requestPermissions( MainActivity.this, "申请权限", 0, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO);
最好仍是检查一下权限是否申请:
EasyPermissions.hasPermissions(Context context, @NonNull String… perms)方法来检测一个或者多个权限是否被容许,第二个参数是个可变数组,能够申请多个
String[] perms = {Manifest.permission.CAMERA, Manifest.permission.ACCESS_FINE_LOCATION}; if (EasyPermissions.hasPermissions(this, perms)) { // 已经申请过权限,作想作的事 } else { // 没有申请过权限,如今去申请 EasyPermissions.requestPermissions(this, getString(R.string.camera_and_location_rationale), RC_CAMERA_AND_LOCATION, perms); }
下面来讲一个申请权限这个方法:
EasyPermissions.requestPermissions():
requestPermissions() 通常用这个四个参数的就能够
第一个参数:Context对象
第二个参数:权限弹窗上的文字提示语。告诉用户,这个权限用途。
第三个参数:此次请求权限的惟一标识请求码,code。
第四个参数 : 一些系列的权限。
这里说一下第二个参数,不是第一次申请系统默认弹出的提示语,而是,咱们拒绝后,再次点击申请弹出的对话框,,显示咱们设置的提示语,下面有两个按钮,确认和取消,我就不贴图了。
还有六个参数的,多了两个参数就是,修改咱们上面那个确认和取消的字样,你能够干成yes 和no.
四、重写onRequestPermissionsResult()方法,把执行操做给easyPermissions
一行代码就搞定了
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); }
五、实现EasyPermissions.PermissionCallbacks接口,重写两个方法
public class MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); // 把执行结果的操做给EasyPermissions EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); } @Override //申请成功时调用 public void onPermissionsGranted(int requestCode, List<String> list) { //请求成功执行相应的操做 好比,举个例子 switch (requestCode){ case 0: Toast.makeText(this, "已获取WRITE_EXTERNAL_STORAGE权限", Toast.LENGTH_SHORT).show(); break; case 1: Toast.makeText(this, "已获取WRITE_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限", Toast.LENGTH_SHORT).show(); break; } } @Override //申请失败时调用 public void onPermissionsDenied(int requestCode, List<String> list) { // 请求失败,执行相应操做 } }
接下来就要说一下成功或者失败后的操做了: 申请成功就直接作该作的事就好了,没啥。
申请若是失败了,这时候有个方法出现了EasyPermissions.somePermissionPermanentlyDenied(this, perms)
这个方法是谷歌建议的。就是在咱们点了不在询问并拒绝,会弹出对话框,告诉用户这个权限时干吗的,很重要,建议不要拒绝哈哈
好比这样:
@Override public void onPermissionsDenied(int requestCode, List<String> perms) { if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) { new AppSettingsDialog.Builder(this).build().show(); //弹出个对话框 }
}
固然咱们能够定制一下这个对话框:
@Override public void onPermissionsDenied(int requestCode, List<String> perms) { //处理权限名字字符串 StringBuffer sb = new StringBuffer(); for (String str : perms){ sb.append(str); sb.append("\n"); } sb.replace(sb.length() - 2,sb.length(),""); switch (requestCode){ case 0: Toast.makeText(this, "已拒绝权限" + perms.get(0), Toast.LENGTH_SHORT).show(); break; case 1: Toast.makeText(this, "已拒绝WRITE_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限"+ perms.get(0), Toast.LENGTH_SHORT).show(); break; } if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) { Toast.makeText(this, "已拒绝权限" + sb + "并再也不询问" , Toast.LENGTH_SHORT).show(); new AppSettingsDialog .Builder(this) .setRationale("此功能须要" + sb + "权限,不然没法正常使用,是否打开设置") .setPositiveButton("是") .setNegativeButton("否") .build() .show(); } }
六、(可选)@AfterPermissionGranted()注解
使用 AfterPermissioonGranted 注解。这是可选的,可是提供出来是为了方便。若是全部的请求的权限都被授予了,被注解的方法将会被执行,这样作是为了简化一般的请求权限成功以后再调用方法的流程。同时也能够在onPermissionsGranted 的回调中添加逻辑操做:
好比官网上的这个实例代码:
这里的方法名能够本身取,主要是权限都申请完,就调用这个方法,执行里面的操做。
其实就至关于在onPermissionsGranted()调用这个方法而已:
@AfterPermissionGranted(RC_CAMERA_AND_LOCATION) private void methodRequiresTwoPermission() { String[] perms = {Manifest.permission.CAMERA, Manifest.permission.ACCESS_FINE_LOCATION}; if (EasyPermissions.hasPermissions(this, perms)) { // Already have permission, do the thing // ... } else { // Do not have permissions, request them now EasyPermissions.requestPermissions(this, getString(R.string.camera_and_location_rationale), RC_CAMERA_AND_LOCATION, perms); } }
基本上介绍完了
对于针对Android O的应用,此行为已被纠正。系统只会授予应用明确请求的权限。然而一旦用户为应用授予某个权限,则全部后续对该权限组中权限的请求都将被自动批准。
例如,假设某个应用在其清单中列出READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE。应用请求READ_EXTERNAL_STORAGE,而且用户授予了该权限,若是该应用针对的是API级别24或更低级别,系统还会同时授予WRITE_EXTERNAL_STORAGE,由于该权限也属于STORAGE权限组而且也在清单中注册过。若是该应用针对的是Android O,则系统此时仅会授予READ_EXTERNAL_STORAGE,不过在该应用之后申请WRITE_EXTERNAL_STORAGE权限时,系统会当即授予该权限,而不会提示用户。
注意:若是使用了没有受权的权限,会崩溃的
因此对于8.0权限,咱们要作的处理,是尽可能把所用到的危险权限所有申请。可是有的权限在不一样版本出现,因此要兼容不一样的版本,因此要加一个版本的判断。
归根结底:android M (6.0)之后,申请权限组一个,即表示整个权限组能够用,因此咱们干脆,只要api 版本大于23(6.0),咱们申请的权限就是申请整个权限组。这样就兼容了android8.0-------------------为了省事的话能够用AndPermission这个第三方框架,或者本身封装一个。