原文地址:https://www.jianshu.com/p/b4a8b3d4f587
解决方法2:https://www.jianshu.com/p/31cf0cd9cbd1
Android 6.0在我们原有的AndroidManifest.xml声明权限的基础上,
又新增了运行时权限动态检测,以下权限都需要在运行时判断:
Android6.0系统默认为targetSdkVersion小于23的应用默认授予了所申请的所有权限,
所以如果你以前的APP设置的targetSdkVersion低于23,在运行时也不会崩溃,
但这也只是一个临时的救急策略,用户还是可以在设置中取消授予的权限。
声明目标SDK版本
我们需要在build.gradle中声明targetSdkVersion为23
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "com.yourcomany.app
minSdkVersion 18
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
检查并申请权限
我们需要在用到权限的地方,每次都检查是否APP已经拥有权限,
比如我们有一个下载功能,需要写SD卡的权限,
我们在写入之前检查是否有WRITE_EXTERNAL_STORAGE权限,没有则申请权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
//申请WRITE_EXTERNAL_STORAGE权限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
WRITE_EXTERNAL_STORAGE_REQUEST_CODE);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
doNext(requestCode,grantResults);
}
private void doNext(int requestCode, int[] grantResults) {
if (requestCode == WRITE_EXTERNAL_STORAGE_REQUEST_CODE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission Granted
} else {
// Permission Denied
}
}
}
Fragment中运行时权限的特殊处理
在Fragment中申请权限,不要使用ActivityCompat.requestPermissions, 直接使用Fragment的requestPermissions方法,否则会回调到Activity的onRequestPermissionsResult
如果在Fragment中嵌套Fragment,在子Fragment中使用requestPermissions方法,onRequestPermissionsResult不会回调回来,建议使用getParentFragment().requestPermissions方法,
这个方法会回调到父Fragment中的onRequestPermissionsResult,加入以下代码可以把回调透传到子Fragment
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
List fragments = getChildFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
if (fragment != null) {
fragment.onRequestPermissionsResult(requestCode,permissions,grantResults);
}
}
}
}
第二种方法:
第一种:简单粗暴最有效的是在工程下的build.gradle中的 targetSdkVersion 改为21或22,因为Android6.0系统或以上默认为targetSdkVersion小于23的应用默认授予了所申请的所有权限,
如果不想这么简单粗暴的话,则:
首先我们要声明权限
然后我的build.gradle 中targetSdkVersion 为25
然后针对一个API>=23的手机,
然后在代码中动态申请权限:
private static final int WRITE_EXTERNAL_STORAGE_REQUEST_CODE = 127;//这个值是自定义的一个int值,在申请多个权限时要保证这个值不重复,才能在回调时进行判断
@Override
protected void onResume() {
super.onResume();
getPersimmion();
}
@TargetApi(23)
private void getPersimmion() {
// 如果应用没有获得对应权限
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
//申请WRITE_EXTERNAL_STORAGE权限
//第一个字符串列是预申请的权限,第三個int是本次请求的辨认编号
requestPermissions(new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE_REQUEST_CODE);
}
}
但是用户要点击拒绝呢?如果程序不做处理,还是和没有申请权限一样!都会在写入sd卡时程序崩溃,所以要做后续的处理,此时我们要重写一个方法onRequestPermissionsResult,用户选择允许或拒绝后,会回调onRequestPermissionsResult方法, 该方法类似于onActivityResult,
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
dealWithResult(requestCode,grantResults);
}
//我们接着需要根据requestCode和grantResults(授权结果)做相应的后续处理
private void dealWithResult(int requestCode, int[] grantResults) {
if (requestCode == WRITE_EXTERNAL_STORAGE_REQUEST_CODE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission Granted 用户允许
} else {
// Permission Denied 用户拒绝
}
}
}