android 动态权限申请源码,Android - 6.0动态权限申请封装

运行时权限

此版本引入了一种新的权限模式,如今,用户可直接在运行时管理应用权限。这种模式让用户能够更好地了解和控制权限,同时为应用开发者精简了安装和自动更新过程。用户可为所安装的各个应用分别授予或撤销权限。

对于以 Android 6.0(API 级别 23)或更高版本为目标平台的应用,请务必在运行时检查和请求权限。要确定您的应用是否已被授予权限,请调用新增的 checkSelfPermission() 方法。要请求权限,请调用新增的 requestPermissions() 方法。即使您的应用并不以 Android 6.0(API 级别 23)为目标平台,您也应该在新权限模式下测试您的应用。

如需了解有关在您的应用中支持新权限模式的详情,请参阅使用系统权限。如需了解有关如何评估新模式对应用的影响的提示,请参阅权限最佳做法。

新增检查方法 checkSelfPermission()

| 参数 |

permission String:正在检查的权限的名称。

这个值绝对不能null。

| 返回 |

| int | PackageManager.PERMISSION_GRANTED如果您有权限,或者如果没有。PackageManager.PERMISSION_DENIED

价值是PERMISSION_GRANTED或PERMISSION_DENIED。

新增请求权限方法 requestPermissions()

| 参数 |

permissions String:请求的权限。我必须非空并且不是空的。

requestCode int:特定于应用程序的请求代码以与报告的结果匹配。应该>=0onRequestPermissionsResult(int, String[], int[])

| 抛出 |

IllegalArgumentException 如果requestCode为负数。

官方有个地方说可以使用ContextWrapper.checkSelfPermission(String) 。其实这个方法很多地方都能使用到。

好,Android M 为什么会新增这两方法呢.因为在Android 6.0 (API 23) 开始用户开始在应用运行时向其授予权限,而不是在应用安装时授予。这种权限机制可以让用户更好的管理应用的权限,保障用户隐私。从此之后...

系统权限分为两种

正常权限

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

android.permission.ACCESS LOCATIONEXTRA_COMMANDS

android.permission.ACCESS NETWORKSTATE

android.permission.ACCESS NOTIFICATIONPOLICY

android.permission.ACCESS WIFISTATE

android.permission.ACCESS WIMAXSTATE

android.permission.BLUETOOTH

android.permission.BLUETOOTH_ADMIN

android.permission.BROADCAST_STICKY

android.permission.CHANGE NETWORKSTATE

android.permission.CHANGE WIFIMULTICAST_STATE

android.permission.CHANGE WIFISTATE

android.permission.CHANGE WIMAXSTATE

android.permission.DISABLE_KEYGUARD

android.permission.EXPAND STATUSBAR

android.permission.FLASHLIGHT

android.permission.GET_ACCOUNTS

android.permission.GET PACKAGESIZE

android.permission.INTERNET

android.permission.KILL BACKGROUNDPROCESSES

android.permission.MODIFY AUDIOSETTINGS

android.permission.NFC

android.permission.READ SYNCSETTINGS

android.permission.READ SYNCSTATS

android.permission.RECEIVE BOOTCOMPLETED

android.permission.REORDER_TASKS

android.permission.REQUEST INSTALLPACKAGES

android.permission.SET TIMEZONE

android.permission.SET_WALLPAPER

android.permission.SET WALLPAPERHINTS

android.permission.SUBSCRIBED FEEDSREAD

android.permission.TRANSMIT_IR

android.permission.USE_FINGERPRINT

android.permission.VIBRATE

android.permission.WAKE_LOCK

android.permission.WRITE SYNCSETTINGS

com.android.alarm.permission.SET_ALARM

com.android.launcher.permission.INSTALL_SHORTCUT

com.android.launcher.permission.UNINSTALL_SHORTCUT

危险权限

会授予应用访问用户机密数据的权限。如果您列出了危险权限,则用户必须明确批准您的应用使用这些权限。

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

阅读到这里,小伙伴会有疑问.为什么危险权限一组一组。这里解释一下,比如 permission-group.SMS 中的其中一条READ_SMS被授权了。那么在使用其他同组权限的时候就不会去向用户发起请求,我们使用checkSelfPermission得到的结果也是授权的。

兼容性的问题

在Android 6.0 以前只要在AndroidManifest.xml上申明了权限,应用就默认带有权限.(在原生系统中)。有些厂商的手机一样可以让用户关闭掉权限。那么...在API<23的情况下关掉权限.再使用权限.那么只有死路条.所以。采取良好的方案就是Try 。

封装思路

其实每写一篇简书前我都会看其他人写的文章,这样就可以把每个人的优势结合在一起。我之前做适配的时候也在Github上找过动态权限申请的库,也可以说成是工具类把。我去看了源码。又一个声称可以在任何地方都可以使用到权限,后来我就用上了这个。其实当时我并不是很理解,因为权限当时我去找资料了是Activity才能发起了.回调固然回到Activity,后来我翻看他的源码...是new 了一个Activity出来.还有一些工具类是让你一行代码调用.然后在onRequestPermissionsResult也要写一行工具类的代码.我觉得这种比较麻烦。后来我就想到了。将使用到的方法功能封装在一个Activity里面。让BaseActivity去继承这个PermissionRequestActivity。一个方法使用,给一个回调出来,授权权限是否成功。

PermissionRequestActivity

import android.content.DialogInterface;

import android.content.Intent;

import android.content.pm.PackageManager;

import android.net.Uri;

import android.os.Build;

import android.provider.Settings;

import android.support.annotation.NonNull;

import android.support.v4.app.ActivityCompat;

import android.support.v4.app.FragmentActivity;

import android.support.v7.app.AlertDialog;

/**

* Created by 卖火柴的小女孩 - Jc on 2018/8/21.

*/

public class PermissionRequestActivity extends FragmentActivity {

private static final int PERMISSION_REQUEST_CODE = 1088;

private String mPermissionDes;

private CallBack mCallBack;

/**

* 权限申请使用方法

*

* @param permissionDes 权限说明

* @param callBack 申请回调

* @param permissions 申请权限

*/

protected void requestPermission(String permissionDes, CallBack callBack, @NonNull String... permissions) {

mCallBack = callBack;

mPermissionDes = permissionDes;

if (checkPermission(permissions))

mCallBack.hasPermission();

else {

ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE);

}

}

/**

* 判断系统版本大于6.0的时候

*

* @param permissions 申请权限

* @return

*/

protected boolean checkPermission(@NonNull String... permissions) {

//大于6.0的时候需要动态申请权限.小于6.0的时候如果用户手动关闭权限,程序即崩 需要做Try处理

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

return checkSelfPermissions(permissions);

}

return true;

}

/**

* 检查权限是否已经授权

*

* @param permissions 申请权限

* @return

*/

private boolean checkSelfPermissions(@NonNull String... permissions) {

boolean flag = true;

for (String p : permissions) {

if (ActivityCompat.checkSelfPermission(this, p) != PackageManager.PERMISSION_GRANTED) {

flag = false;

break;

}

}

return flag;

}

@Override

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

boolean hasAllGranted = true;

for (int i = 0; i < grantResults.length; ++i) {

if (grantResults[i] == PackageManager.PERMISSION_DENIED) {

hasAllGranted = false;

if (!ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i])) {

showDialogPrompt();

} else {

//权限申请被拒绝 ,但用户未选择'不再提示'选项

mCallBack.lossPermission();

}

break;

}

}

if (hasAllGranted) {

mCallBack.hasPermission();

}

super.onRequestPermissionsResult(requestCode, permissions, grantResults);

}

/**

* 由于用户手动关闭权限提示。APP需要做人性化提示

*/

private void showDialogPrompt() {

new AlertDialog.Builder(this)

.setTitle("权限申请")

.setMessage(mPermissionDes)

.setCancelable(false)

.setPositiveButton("去设置", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

//引导用户至设置页手动授权

getAppSetting();

}

})

.setNegativeButton("取消", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

//引导用户手动授权,权限请求失败

mCallBack.lossPermission();

}

}).show();

}

/**

* 跳转设置 应用设置界面

*

* @return

*/

private Intent getAppSetting() {

Intent localIntent = null;

if (Build.VERSION.SDK_INT >= 9) {

localIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);

localIntent.setData(Uri.fromParts("package", getPackageName(), null));

localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

} else if (Build.VERSION.SDK_INT <= 8) {

localIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);

localIntent.setAction(Intent.ACTION_VIEW);

localIntent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails");

localIntent.putExtra("com.android.settings.ApplicationPkgName", getPackageName());

localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

}

startActivity(localIntent);

return localIntent;

}

/**

* 权限申请回调

*/

interface CallBack {

void hasPermission();

void lossPermission();

}

}

使用

requestPermission("获取手机信息-获取手机号码、IMEI、IMSI权限\n读写手机存储-读写手机存储", new CallBack() {

@Override

public void hasPermission() {

String IMEI = getIMEI(MainActivity.this);

((TextView) findViewById(R.id.tv)).setText(IMEI);

}

@Override

public void lossPermission() {

Toast.makeText(MainActivity.this, "权限申请被拒绝", Toast.LENGTH_SHORT).show();

}

}, Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_EXTERNAL_STORAGE);

代码讲解

其实代码不多,只有100多行。

方法: requestPermission

参数:String permissionDes -- 用于用户选择'不再提示'按钮提示语

CallBack callBack -- 应用是否带有权限或是否授权权限成功

@NonNull String... permissions -- 需要授权或检查的权限

这个方法一进去 我做了一个判断 checkPermission(permissions) , 先去检查是否有权限,如果有权限的话.那么就不去授权权限了.

方法 :checkPermission() 进来判断是否有权限的时候这个方法有一个API 就是刚才最上面开始讲的checkSelfPermission 这个需要 Build.VERSION.SDK_INT >= Build.VERSION_CODES.M..所以不满足这个条件的都以TRUE返回出去,表明应用在6.0以下的设备默认有这些权限。但是刚才在兼容性的时候讲过了.会崩。

接下来检测到没有权限,使用了这一段代码

ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE);

这一行就是向用户发起权限授权的代码了.接下来 我们看 onRequestPermissionsResult 。 这个方法是向用户请求权限的回调结果。这个方法里面我做了处理,我检测了用户是否点击了 ' 不再提示 ' 的按钮。(有些手机没有这个按钮,有些手机有,当选择了此按钮之后 再次发起授权请求,系统将不再向用户发起权限授权请求.而是直接返回拒绝的信息回来.)那么这时我们就需要做一个友好的提示了。如果用户是由于手动点击了这个不再提示的按钮而导致第二次或第n次没有收到授权的消息.那我们应用需要给用户一个提示框showDialogPrompt(),我这里写了一个最简单的弹窗。很多APP都有自己主题的弹窗.主要就是提示用户。告知用户 他的权限被他自己手动不再提示了.那么我们给他一个系统设置界面的跳转getAppSetting(); 然后这个方法的Build.VERSION.SDK_INT <= 8 我就不解释了.有兴趣的就自己去百度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值