Android运行时权限
来源:互联网 发布:贝多芬梅毒 知乎 编辑:程序博客网 时间:2024/05/19 23:05
Android运行时权限
简介:Android 6.0 以后,对于一些用户隐私权限总会在第一次提示用户是否授予权限。
优点:
- 更好的保护了用户的隐私。
- 给了程序向用户说明权限的作用。
- 可以防止一些恶意程序盗取用户后者手机信息,增强了Android系统的安全性。
Android 6.0 将权限分为两类:
- 普通权限:不需要单独申请,直接在Manifest里注册即可。
- 危险权限&危险权限组:危险权限都是分组出现的,用户只要授权组内的一个权限,组内的其他权限就会立即授权。
危险权限列表:
申请方式一: 原生API
新增API:
- ContextCompat.checkSelfPermission:检查危险权限&危险权限组是否授权。
- ActivityCompat.requestPermissions:申请权限。
- onRequestPermissionsResult:申请权限的回调(用户授权或拒绝授权)。
- ActivityCompat.shouldShowRequestPermissionRationale:给用户解释,申请权限用户干什么。用户拒绝过权限后出现。
使用步骤:
- 在Manifest中添加需要的权限(不可省,因为要适配android 6.0 以下机型);
- 检查危险权限;
- 申请授权;
- 处理申请授权回调。
1.1 简单使用
示例:需要申请一个权限的功能(摄像头),需要申请多个(示例为2个:摄像头和手机状态)权限的功能。
public class PermissionActivity extends AppCompatActivity { private Context mContext = this; private final int PERMISSION_CAMERA = 100;//摄像头权限 private final int PERMISSION_PHONE = 101;//摄像头和手机状态权限 @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_permission); ButterKnife.bind(this); } @OnClick({R.id.per_btn_cc_cp, R.id.per_btn_cc_camera}) public void onViewClicked(View view) { switch (view.getId()) { case R.id.per_btn_cc_camera: openCCCamera();//原生运行时权限--摄像头 break; case R.id.per_btn_cc_cp: openCCCP();//原生运行时权限--摄像头和手机状态 break; } } /** 原生申请权限--摄像头 */ private void openCCCamera() { //2.检查权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { //进入到这里代表没有权限 if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) { //如果用户拒绝过该权限 new AlertDialog.Builder(this).setTitle("权限提示") .setMessage("之前拒绝授权,使用摄像头需要该权限") .setPositiveButton("知道了", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ActivityCompat.requestPermissions((Activity) mContext, new String[]{Manifest.permission.CAMERA}, PERMISSION_CAMERA); } }).show(); } else { //3. 申请权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, PERMISSION_CAMERA); } } else { Toast.makeText(this, "之前已经授权,现在可以使用摄像头了", Toast.LENGTH_SHORT).show(); } } /** 原生申请权限--摄像头 和 手机状态 */ private void openCCCP() { //2.检查权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { //3. 申请权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_PHONE_STATE}, PERMISSION_PHONE); } else { Toast.makeText(this, "之前已经授权,现在可以使用摄像头、读取手机状态了", Toast.LENGTH_SHORT).show(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { case PERMISSION_CAMERA://使用摄像头功能申请处理 if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {//用户授予权限,执行业务逻辑 Toast.makeText(this, "用户同意授权,现在可以使用摄像头了", Toast.LENGTH_SHORT).show(); } else {//用户拒绝权限,提示用户 Toast.makeText(this, "用户没有授权--摄像头!!!", Toast.LENGTH_SHORT).show(); } break; case PERMISSION_PHONE://摄像头和读取手机状态申请处理 if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {//用户授予权限,执行业务逻辑 Toast.makeText(this, "用户同意授权,现在可以使用摄像头和读取手机状态了", Toast.LENGTH_SHORT).show(); } else {//用户拒绝权限,提示用户 Toast.makeText(this, "用户没有授权--摄像头和读取手机状态!!!", Toast.LENGTH_SHORT).show(); } break; } }}
效果:
1.2 封装
1.2.1 封装常量–权限请求code
public class Const { public static class PERMISSION { public static final int CAMERA = 0x01; public static final int PHONE = 0x02; }}
1.2.2 封装父类–BasePermissionActivity
public class BasePermissionActivity extends AppCompatActivity { /** * 检查是否拥有权限 * @param permissions * @return */ protected boolean hasPermission(String...permissions){ for(String permission : permissions){ if(ContextCompat.checkSelfPermission(this,permission) != PackageManager.PERMISSION_GRANTED){ return false; } } return true; } /** * 申请权限 * @param requestCode * @param permissions */ protected void requestPermission(int requestCode,String...permissions){ ActivityCompat.requestPermissions(this,permissions,requestCode); } /** * 检查授权回调结果 * @param grantReslts * @return */ protected boolean checkGrantReslts(int[] grantReslts){ for(int grantReslt:grantReslts){ if( grantReslt != PackageManager.PERMISSION_GRANTED){ return false; } } return true; } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantReslts) { switch (requestCode) { case Const.PERMISSION.CAMERA://使用定义好的常量 if (grantReslts.length > 0 && checkGrantReslts(grantReslts)) { openCamera(); } else { Toast.makeText(this, "用户拒绝授权", Toast.LENGTH_SHORT).show(); } break; case Const.PERMISSION.PHONE://使用定义好的常量 if (grantReslts.length > 0 && checkGrantReslts(grantReslts)) { openCameraAndPhone(); } else { Toast.makeText(this, "用户拒绝授权", Toast.LENGTH_SHORT).show(); } break; } } /** 父类默认方法--打开相机和读取手机状态 */ protected void openCameraAndPhone() {} /** 父类默认方法--打开相机 */ protected void openCamera() {}}
1.2.3 子类使用
public class PermissionTestActivity extends BasePermissionActivity { private Context mContext = this; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_permission); ButterKnife.bind(this); } @OnClick({R.id.basePer_btn_camera, R.id.basePer_btn_phone}) public void onViewClicked(View view) { switch (view.getId()) { case R.id.basePer_btn_camera: if (hasPermission(Manifest.permission.CAMERA)) { openCamera(); } else { requestPermission(Const.PERMISSION.CAMERA, Manifest.permission.CAMERA); } break; case R.id.basePer_btn_phone: if (hasPermission(Manifest.permission.CAMERA, Manifest.permission.READ_PHONE_STATE)) { openCameraAndPhone(); } else { requestPermission(Const.PERMISSION.CAMERA, Manifest.permission.CAMERA, Manifest.permission.READ_PHONE_STATE); } break; } } // 重写父类方法--打开相机 @Override protected void openCamera() { Toast.makeText(mContext, "拥有授权,现在可以打开相机了", Toast.LENGTH_SHORT).show(); } // 重写父类方法--打开相机和读取手机状态 @Override protected void openCameraAndPhone() { Toast.makeText(mContext, "拥有授权,现在可以打开相机和读取手机状态了", Toast.LENGTH_SHORT).show(); }}
申请方式二: EasyPermission
简介:EasyPermission是googlesamples提供的用以简化运行时权限逻辑的库。
GitHub地址,点击这里跳转
2.1 主要API
2.1.1 @AfterPermissionGranted()
@AfterPermissionGranted(int requestCode)
用途:可选项。如果请求码给定的所有请求权限被授予,将执行该方法。
2.1.2 hasPermissions()
hasPermissions(Context context, @NonNull String... perms):
用途:检查权限。
2.1.3 requestPermissions()
requestPermissions(@NonNull Activity host, @NonNull String rationale,@StringRes int positiveButton, @StringRes int negativeButton,int requestCode, @NonNull String... perms) {
用途:申请权限。
参数说明:
- rationale:如果用户第一次拒绝请求,将显示为什么应用程序需要这组权限的消息。
- positiveButton:确定按钮文本。
- negativeButton:取消按钮文本。
2.1.4 PermissionCallbacks()
public interface PermissionCallbacks extends ActivityCompat.OnRequestPermissionsResultCallback { //Some permissions have been granted void onPermissionsGranted(int requestCode, List<String> perms); //Some permissions have been denied void onPermissionsDenied(int requestCode, List<String> perms);}
用途:权限申请回调。
2.1.5 somePermissionPermanentlyDenied()
somePermissionPermanentlyDenied(@NonNull Activity host,@NonNull List<String> deniedPermissions)
用途:如果用户选择“不再询问”选项禁止这些权限,将无法从用户请求这些权限,之后必须在应用程序设置中更改这些权限。使用这个方法显示一个对话框,用户点击“确定按钮后”直接跳转至“系统的应用程序设置”界面。
2.2 简单使用
2.2.1 导包
compile 'pub.devrel:easypermissions:0.4.3'
2.2.2 示例
使用步骤:
- 在Activity/Fragment中重写onRequestPermissionsResult()方法;
- 检查权限;
- 申请权限;
- 实现接口,处理回调;
示例代码:
public class Permission3Activity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks { private Context mContext = this; private final int PERMISSION_PHONE = 101;//摄像头和手机状态权限 @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_permission2); ButterKnife.bind(this); } @OnClick({R.id.basePer_btn_phone}) public void onViewClicked(View view) { switch (view.getId()) { case R.id.basePer_btn_phone: openCameraAndPhone(); break; } } @AfterPermissionGranted(PERMISSION_PHONE)//请求权限回调结果中,如果所有权限全部授予,直接执行该方法 private void recordVideo(){ Toast.makeText(mContext, "开始录制视频", Toast.LENGTH_SHORT).show(); } //点击录制视频按钮执行方法 private void openCameraAndPhone() { String[] perms = {Manifest.permission.CAMERA, Manifest.permission.READ_PHONE_STATE}; //2.检查权限 if (EasyPermissions.hasPermissions(mContext, perms)) { // 所有权限全部授权,进入这里 recordVideo(); } else { //3.有未授权的权限,请求权限 EasyPermissions.requestPermissions((Activity) mContext, "录制视频需要摄像头权限和读取手机信息权限", PERMISSION_PHONE, perms); } } //1.重写权限申请回调 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); } /** * 权限申请回调--某些同意 */ @Override public void onPermissionsGranted(int requestCode, List<String> perms) { //Some permissions have been granted } /** * 权限申请回调--某些拒绝 */ @Override public void onPermissionsDenied(int requestCode, List<String> perms) { //Some permissions have been denied if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {//不再询问--是否跳转至app设置界面 new AppSettingsDialog.Builder(this) .setRationale("缺少请求的权限倒是该功能无法使用,打开app设置界面开启相关权限").build().show(); } else { Toast.makeText(mContext, "用户拒绝某些授权", Toast.LENGTH_SHORT).show(); } }}
全部同意效果(直接执行指定方法):
拒绝效果(再次申请是解释为什么需要该权限):
不再询问效果:
申请方式三: PermissionsDispatcher
简介:使用注解申请运行时权限的开源框架,还有插件可以使用,很方便。
GitHub地址,点击这里跳转
注解说明:
- @RuntimePermissions:必填。在需要权限的Activity/Fragment前添加该注解。
- @NeedsPermission:必填。在需要权限的方法前添加该注解,并传入所需权限。
- @OnShowRationale:可选。在向用户解释为什么需要该权限的方法前添加该注解,并传入权限。
- @OnPermissionDenied:可选。在用户拒绝授权调用的方法前添加该注解。
- @OnNeverAskAgain:可选。在用户选择“不在询问”调用的方法前添加该注解。
注意:添加注解的方法不能是private的。
3.1 导包
compile("com.github.hotchemi:permissionsdispatcher:${latest.version}") { // if you don't use android.app.Fragment you can exclude support for them exclude module: "support-v13"}annotationProcessor "com.github.hotchemi:permissionsdispatcher-processor:${latest.version}"
3.2 示例
使用步骤:
- 在需要权限的Activity/Fragment前添加@RuntimePermissions注解;
- 在需要权限的方法前添加@NeedsPermission()注解;
- 按需求添加@OnShowRationale()注解、@OnPermissionDenied()注解、@OnNeverAskAgain()注解;
- Make Project;
- 使用自动生成的检查权限方法;
- 重写onRequestPermissionsResult()方法。
示例:
//第一步@RuntimePermissionspublic class Permission4Activity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_permission2); ButterKnife.bind(this); } @OnClick(R.id.basePer_btn_phone}) public void onViewClicked(View view) { switch (view.getId()) { case R.id.basePer_btn_phone: break; } } //第二步 @NeedsPermission({Manifest.permission.CAMERA,Manifest.permission.READ_PHONE_STATE}) void recordVideo() { Toast.makeText(this,"开始录制视频",Toast.LENGTH_SHORT).show(); } //第三步--可选 @OnShowRationale({Manifest.permission.CAMERA,Manifest.permission.READ_PHONE_STATE}) void showRationale(final PermissionRequest request) { new AlertDialog.Builder(this) .setMessage("录制视频需要摄像头权限和读取手机信息权限") .setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { request.proceed(); } }) .setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { request.cancel(); } }) .show(); } //第三步--可选 @OnPermissionDenied({Manifest.permission.CAMERA,Manifest.permission.READ_PHONE_STATE}) void showDenied(){ Toast.makeText(this, "用户拒绝某些授权", Toast.LENGTH_SHORT).show(); } //第三步--可选 @OnNeverAskAgain({Manifest.permission.CAMERA,Manifest.permission.READ_PHONE_STATE}) void showNeverAskAgain(){ new AppSettingsDialog.Builder(this) .setRationale("缺少请求的权限导致该功能无法使用,打开app设置界面开启相关权限").build().show(); }}
第四步:Make Project
完成后会自动生成[Activity Name] + PermissionsDispatcher类。
第五步:检查权限
第六步:重写onRequestPermissionsResult()方法
3.3 使用PermissionsDispatcher插件
3.3.1 安装插件
3.3.2 使用插件
3.3.2.1 动态导包
备注:执行一次即可。
3.3.2.2 添加权限
选择申请的权限和添加的方法:
完成后,在相应方法中添加逻辑。
检查权限
五、机型适配
5.1 小米手机
Manifest.permission.READ_PHONE_STATE权限要单独申请。
- Android 运行时权限
- android运行时权限
- Android运行时权限
- Android 运行时权限
- android运行时权限
- android运行时权限
- Android 运行时权限
- Android运行时权限
- Android 运行时权限
- Android运行时权限
- Android-运行时权限
- Android运行时权限
- Android 运行时权限
- Android运行时权限
- Android 运行时权限
- Android 运行时权限
- Android运行时权限(危险权限)
- Android 6.0运行时权限
- 18 个锻炼编程技能的网站
- selenium 截图 设置等待
- Huffman编码字典构造
- [OI阶段记录] 备战NOIP刷题记录
- POJ 2245 Lotto(水水的dfs)
- Android运行时权限
- 解决robotframwork ride运行过程中报错FAIL : No keyword with name 'Open browser' found.
- C++逗号运算符与逗号表达式
- 清除浮动那些事
- 杭电 6069 多校 Counting Divisors
- 归并排序(Merge Sort)
- Windows 64位下安装Redis
- HADO KART登陆中国 | Meleap发布全球首款HoloLens卡丁车游戏
- vs2013+g2o配置