Code4Android .jpg

前言

现在谈论Android权限适配可能有点没必要,因为网上关于权限适配的文章很多,搜一下Android6.0权限适配关键词能搜到一堆文章,而且很多写的还很不错。不过自己想了想还是总结一下,因为那些文章都是别人的,不是自己的,之前一直想总结一下,但是一直没做,今天就简单记录一下,方便以后查阅,也对Android6.0的权限机制再次进行一次全面的认识。

从Android M开始,用户开始在应用运行时向其授予权限,而不是在应用安装时授予。这样更友好的让用户选择,当真正需要权限的时候再去申请权限,而不是Android M之前在安装时一下子去申请。

正常权限

正常权限不会直接给用户隐私权带来风险。如果您的应用在其清单中列出了正常权限,系统将自动授予该权限。而不需要我们去请求权限。

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

危险权限

危险权限涵盖应用需要涉及用户隐私信息的数据或资源,或者可能对用户存储的数据或其他应用的操作产生影响的区域。例如,能够读取用户的联系人属于危险权限。如果应用声明其需要危险权限,则用户必须明确向应用授予该权限。

在危险权限中,我们需要了解一个权限组的概念,所有危险的 Android 系统权限都属于权限组,如果应用请求其清单中列出的危险权限,而应用目前在权限组中没有拥有任何权限,则系统会向用户显示一个对话框,描述应用要访问的权限组。对话框不描述该组内的具体权限。

例如我们需要读取获取手机卡imsi,此时需要请求权限READ_PHONE_STATE,发现此时提示框也展示了请求打电话权限。(系统只告诉用户应用需要的权限组,而不告知具体权限)其实READ_PHONE_STATE和打电话权限CALL_PHONE都属于一个权限组PHONE,如果我们此时允许了权限,那么下次再其他地方使用了打电话权限时系统将立即授予该权限。

这里写图片描述

注:任何权限都可属于一个权限组,包括正常权限和应用定义的权限。但权限组仅当权限危险时才影响用户体验。可以忽略正常权限的权限组。

权限组

权限

CALENDAR

READ_CALENDAR

WRITE_CALENDAR

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

SEND_SMS

RECEIVE_SMS

READ_SMS

RECEIVE_WAP_PUSH

RECEIVE_MMS

权限请求API

/**

* 确定权限是否已经被授予

* @param permission 被检测权限的名字.

* @return {@link android.content.pm.PackageManager#PERMISSION_GRANTED} 如果权限被授予,

* {@link android.content.pm.PackageManager#PERMISSION_DENIED} 如果权限被拒绝返回值.

*/

public static int checkSelfPermission(@NonNull Context context, @NonNull String permission)

/**

* 是否显示自定义UI提示用户

* 华为手机测试 第一次使用时返回false

* 如果拒绝返回true

* 如果拒绝并点击不在提醒返回false

* 已经同意过权限,但在设置拒绝此时返回true

* 没有同意过权限,在设置中开启并拒绝权限返回false

* @param activity 请求权限Activity.

* @param permission 需要请求的权限.

* @return 是否显示自定义对话框提示用户.

*/

public static boolean shouldShowRequestPermissionRationale(@NonNull Activity activity,

@NonNull String permission)

/**

* 给应用申请权限,申请的权限必须在manifest文件注册,正常权限在安装时自动被授权,不需要使用此方法请求权限

* 请求之后会弹出系统提示框,供我们选择是拒绝还是允许,点击后

* android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult(

* int, String[], int[])} 方法将会被回调,

* @param activity 请求权限的Activity.

* @param permissions 需要请求的权限.

* @param requestCode 指定一个请求码,用于区别返回结果

*

*/

public static void requestPermissions(final @NonNull Activity activity,

final @NonNull String[] permissions, final int requestCode)

/**

* 调用requestPermissions方法请求权限的回调

*需要注意的是可能请求的权限与用户互动中断;正在这种情况下回调将接收一个空的permissions和grantResults数组

* @param permissions 请求的权限. 不为null,长度可能为0.

* @param grantResults 请求权限的结果PERMISSION_GRANTED表示权限被允许,PERMISSION_DENIED表示权限被拒绝

*/

void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,

@NonNull int[] grantResults)

需要注意的是,对于如果在Activity中请求权限则可使用上面API ActivityCompat类,如果在Frament请求权限则,需要使用Fragment类中的对应方法,否则回调会有问题。

简单封装

/**

* 判断是否具备所有权限

*

* @param permissions 所有权限

* @return true 具有所有权限 false没有具有所有权限,此时包含未授予的权限

*/

public static boolean isHasPermissions(String... permissions) {

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)

return true;

for (String permission : permissions) {

if (!isHasPermission(permission))

return false;

}

return true;

}

/**

* 判断该权限是否已经被授予

*

* @param permission

* @return true 已经授予该权限 ,false未授予该权限

*/

private static boolean isHasPermission(String permission) {

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)

return true;

return ContextCompat.checkSelfPermission(MyApplication.getAppContext(), permission) == PackageManager.PERMISSION_GRANTED;

}

/**

* 请求权限,经测试发现TabActivity管理Activity时,在Activity中请求权限时需要传入父Activity对象,即TabActivity对象

* 并在TabActivity管理Activity中重写onRequestPermissionsResult并分发到子Activity,否则回调不执行 。TabActivity回调中 调用getLocalActivityManager().getCurrentActivity().onRequestPermissionsResult(requestCode, permissions, grantResults);分发到子Activity

*

*

* @param object Activity or Fragment

* @param requestCode 请求码

* @param permissions 请求权限

*/

public static void requestPermissions(Object object, int requestCode, String... permissions) {

ArrayList arrayList = new ArrayList<>();

for (String permission : permissions) {

if (!isHasPermissions(permission)) {

arrayList.add(permission);

}

}

if (arrayList.size() > 0) {

if (object instanceof Activity) {

Activity activity = (Activity) object;

Activity activity1 = activity.getParent() != null && activity.getParent() instanceof TabActivity ? activity.getParent() : activity;

ActivityCompat.requestPermissions(activity1, arrayList.toArray(new String[]{}), requestCode);

} else if (object instanceof Fragment) {

Fragment fragment = (Fragment) object;

//当Fragment嵌套Fragment时使用getParentFragment(),然后在父Fragment进行分发,否则回调不执行

Fragment fragment1 = fragment.getParentFragment() != null ? fragment.getParentFragment() : fragment;

fragment1.requestPermissions(arrayList.toArray(new String[]{}), requestCode);

} else {

throw new RuntimeException("the object must be Activity or Fragment");

}

}

}

如果想展示自定义UI友好的提示用户申请该权限的原因,则需要使用shouldShowRequestPermissionRationale方法,简要封装如下

public static boolean shouldShowRequestPermissionRationale(@NonNull Object object, String... permissions) {

for (String permission : permissions) {

if (object instanceof Activity) {

if (ActivityCompat.shouldShowRequestPermissionRationale((Activity) object, permission)) {

return true;

}

} else if (object instanceof Fragment) {

if(((Fragment) object).shouldShowRequestPermissionRationale(permission)){

return true;

}

} else {

throw new RuntimeException("the object must be Activity or Fragment");

}

}

return false;

}

/**

* 二次申请权限时,弹出自定义提示对话框

*

* @param activity

* @param message

* @param iPermissionRequest

* @see com.example.xh.ui.BaiduLocationFragment 可以查看该类onRequestPermissionsResult方法当选择永不提醒时的处理办法。

*/

public static void showDialog(Activity activity, String message, final IPermissionRequest iPermissionRequest) {

new AlertDialog.Builder(activity)

.setPositiveButton("允许", new DialogInterface.OnClickListener() {

@Override

public void onClick(@NonNull DialogInterface dialog, int which) {

iPermissionRequest.agree();

dialog.dismiss();

}

})

.setNegativeButton("拒绝", new DialogInterface.OnClickListener() {

@Override

public void onClick(@NonNull DialogInterface dialog, int which) {

iPermissionRequest.refuse();

dialog.dismiss();

}

})

.setCancelable(false)

.setMessage(message)

.show();

}

弹出对话框后,点击了拒绝或者允许后,给一个回调,方便进行不同的处理,当然如果统一处理的话,就不需要写接口,直接在上述点击允许的时候请求权限,点击不允许的时候,显示一个Toast再次做下权限拒绝提示。当然也可在onRequestPermissionsResult中进行判断,当选中永不提醒后给用户一个友好跳转到权限设置界面。

接口方法

public interface IPermissionRequest {

void agree();

void refuse();

}

特殊权限

有许多权限其行为方式与正常权限及危险权限都不同。SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS 特别敏感,因此大多数应用不应该使用它们。如果某应用需要其中一种权限,必须在清单中声明该权限,并且发送请求用户授权的 intent(注意特殊权限和危险权限请求方式不一样)。系统将向用户显示详细管理屏幕,以响应该 intent。

请求WRITE_SETTINGS权限

/**

* 测试请求WRITE_SETTINGS权限

*/

@OnClick(R.id.request_write_setting)

@TargetApi(android.os.Build.VERSION_CODES.M)

public void requestWriteSetting() {

if (!Settings.System.canWrite(this)) {

Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS,

Uri.parse("package:" + getPackageName()));

startActivityForResult(intent, requestCodeWriteSetting);

} else {

Toast.makeText(PermissionTestActivity.this, "WRITE_SETTINGS 已经被授权", Toast.LENGTH_SHORT).show();

}

}

@TargetApi(Build.VERSION_CODES.M)

private void showToast() {

if (Settings.System.canWrite(this)) {

//检查返回结果

Toast.makeText(PermissionTestActivity.this, "WRITE_SETTINGS 被授权", Toast.LENGTH_SHORT).show();

} else {

Toast.makeText(PermissionTestActivity.this, "WRITE_SETTINGS 没有被授权", Toast.LENGTH_SHORT).show();

}

}

@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

super.onActivityResult(requestCode, resultCode, data);

if (requestCode == requestCodeWriteSetting) {

showToast();

}else if(requestCode==requestCodeAlertWindow){

showToastAlerterWindow();

}

}

请求SYSTEM_ALERT_WINDOW权限

/**

* 测试请求SYSTEM_ALERT_WINDOW权限

*/

@OnClick(R.id.request_alert_window)

@TargetApi(android.os.Build.VERSION_CODES.M)

public void requestAlertWindow() {

if (!Settings.canDrawOverlays(this)) {

Intent intent = new Intent(Settings. ACTION_MANAGE_OVERLAY_PERMISSION,

Uri.parse("package:" + getPackageName()));

startActivityForResult(intent, requestCodeAlertWindow);

} else {

Toast.makeText(PermissionTestActivity.this, "SYSTEM_ALERT_WINDOW 已经被授权", Toast.LENGTH_SHORT).show();

}

}

@TargetApi(Build.VERSION_CODES.M)

private void showToastAlerterWindow() {

if (Settings.System.canWrite(this)) {

//检查返回结果

Toast.makeText(PermissionTestActivity.this, "SYSTEM_ALERT_WINDOW 被授权", Toast.LENGTH_SHORT).show();

} else {

Toast.makeText(PermissionTestActivity.this, "SYSTEM_ALERT_WINDOW 没有被授权", Toast.LENGTH_SHORT).show();

}

}

WRITE_SETTINGS权限设置界面

SYSTEM_ALERT_WINDOW权限设置界面

注意:权限必须在清单文件中声明,否则进入上面界面时开关是不可点击的灰色。

打开权限设置界面

在上面危险权限申请中,如果用户拒绝了权限,并且选中永不提醒,那么下次请求权限时直接执行onRequestPermissionsResult回调,并且返回状态是权限被拒绝状态,那么若想授予权限,必须去手机的权限管理中设置,如果用户去手机里找是不是很麻烦,况且一步人不知道设置权限的地方在哪,那么为了程序的体验更好,我们可以在我们的应用中引导用户跳转到设置权限的界面。实现代码如下

/**

* 打开应用权限设置界面

*/

@OnClick(R.id.open_permission_setting)

public void requestOpenPermissionSetting() {

Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);

// Uri uri = Uri.fromParts("package", getPackageName(), null);

Uri uri1=Uri.parse("package:" + getPackageName());

intent.setData(uri1);

startActivity(intent);

}

介绍到此就结束了,水平有限若有问题请指出,Hava a wonderful day.

最后放几篇感觉不错的文章:

android 6.0 短信权限,Android6.0权限适配相关推荐

  1. android 实现发送短信功能以及解决权限问题

    1.创建项目,新建Activity 2.sendSmsActivity.java package com.otis.ui;import androidx.appcompat.app.AppCompat ...

  2. 电信smgp3.0短信发送问题

    smgp3.0短信 问题,返回错误码46 怎么解决 从网上下载的smgp的jar ,最终返回的status错误码是46 非法的发送方号码 ,求教怎么解决 SMGP3 smgp = new SMGP3( ...

  3. 子佩短信管家 v1.0.0

    类型:系统工具 版本:v1.0.0 大小:13.9M 更新:2019/3/1 语言:简体 等级: 平台:安卓, 4.0以上 下载地址: 子佩短信管家 v1.0.0(1) 子佩短信管家 v1.0.0(2 ...

  4. 文涛短信通 v1.0 绿色

    Welcome to my blog! <script language="javascript" src="http://avss.b15.cnwg.cn/cou ...

  5. android-短信验证功能,Android实现获取短信验证码的功能以及自定义GUI短信验证详解...

    <Android实现获取短信验证码的功能以及自定义GUI短信验证详解>由会员分享,可在线阅读,更多相关<Android实现获取短信验证码的功能以及自定义GUI短信验证详解(8页珍藏版 ...

  6. android sms 接收短信,Android SMS 短信操作

    android的短信保存在短信库里,但并提供类似Contacts的公开的Content Provider方便操作.这里简单的介绍下:android中的短信信息保存在/data/data/com.and ...

  7. Android之修改短信程序

    今天搞了个小程序,可以修改你自己android手机的任何一条短信. 直接进入正题,先放两张效果图: 主界面就是四个按钮加一个显示短信的listview: <LinearLayout xmlns: ...

  8. android 监听短信并获取验证码

    最近想给 app 添加自动获取短信验证码的功能,让注册流程更加友好,在网上搜索了一些资料,主要的实现方法有两种. 第一:实现广播 BroadCastReceiver 来监听收件箱,在需要监听的地方注册 ...

  9. Android实现发短信,打电话

    最近做的这个HTML5项目中有2个调用本地的打电话,发短信功能,之后就去在网上找实现方式下面就是实现方式. 首先想到就是权限问题所以在AndroidManifest中添加权限 <?xml ver ...

  10. android应用发短信

    首选在AndroidManifest.xml 申请权限 <uses-permission android:name="android.permission.SEND_SMS" ...

最新文章

  1. 使用VMware桥接模式组建局域网测试MSMQ(二)
  2. 你遇到过哪些理工科的实验高手,他们有哪些优秀的思维习惯?
  3. 每个程序员都应该挑战的6个项目
  4. javascript等号判断相等流程
  5. Fedora 21 中添加及更新源的命令
  6. 二分查找和折半插入排序一块说说-很合适~~~
  7. 为什么应该避免JSF
  8. php 什么函数获取ip,在PHP中获取ip地址的方法有哪些
  9. 精益思想,从哪里开始?
  10. Django官方中文文档
  11. 东南亚金融服务商Pundi X正式加入 Achain 生态
  12. 【话题:工作生活】2021年工作总结--这些人,那些事。
  13. pythondocx_python docx文档转html页面
  14. python练习题(3)--字符串及正则表达式的应用
  15. 求具体方程的解的c语言程序,怎样用c语言求方程的解
  16. 成都服务器销售熊掌号,熊掌号如何运营推广呢
  17. Android开发技巧——自定义控件之组合控件
  18. 软件架构师书籍及高效读书心得
  19. 前端开发:keep-alive的使用详解
  20. 四级高频词汇---词根串讲---day1

热门文章

  1. 简述mysql事件作用_MYSQL使用简述
  2. Android音视频从入门到提高---任务列表
  3. C++之找不到libboost_system.so.1.76库解决
  4. 浏览器获取CA认证流程
  5. start_kernel之前的调用流程(head.s)
  6. webgis之相关工具
  7. python之pyc
  8. 数学与泛型编程:高效编程的奥秘pdf_Java 泛型与类型擦除
  9. 字节跳动教育业务怎么样_字节跳动将重点关注教育业务,今年预计招聘超过一万人...
  10. python 程序块 挂掉的服务_写一个python的服务监控程序