笛里谁知壮士心,沙头空照征人骨。这篇文章主要讲述Android 6.0权限申请相关的知识,希望能为你提供帮助。
一、6.0发布权限变化
1.android需要手动加入权限申请原因:
【Android 6.0权限申请】1)权限分为了两类:一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等;另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等。
- Normal Permissions如下
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_INSTALL_PACKAGES
SET_ALARM
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS
- Dangerous Permissions:
group:android.permission-group.CONTACTS
permission:android.permission.WRITE_CONTACTS
permission:android.permission.GET_ACCOUNTS
permission:android.permission.READ_CONTACTSgroup: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_VOICEMAILgroup:android.permission-group.CALENDAR
permission:android.permission.READ_CALENDAR
permission:android.permission.WRITE_CALENDARgroup:android.permission-group.CAMERA
permission:android.permission.CAMERAgroup:android.permission-group.SENSORS
permission:android.permission.BODY_SENSORSgroup:android.permission-group.LOCATION
permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATIONgroup:android.permission-group.STORAGE
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGEgroup:android.permission-group.MICROPHONE
permission:android.permission.RECORD_AUDIOgroup: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
2)权限不是所有的都自动允许给你的app的,默认是没有Dangerous Permission的,需要用户手动去申请,否则功能不能使用,例如:拍照、选取相册、下载、录音、打电话、发短信等等,可能会造成Crash崩溃。
3)6.0及之后系统不会自动去申请权限,也不会给提示,故需要手动自己添加申请。
二、Android程序内部加入6.0权限申请
1.确定自己App哪些地方需要申请?
针对自己对应的地方去写权限请求。
例如:拍照、选取相册、下载、录音、打电话、发短信等等;
android.Manifest.permission.CAMERA;
android.Manifest.permission.READ_EXTERNAL_STORAGE
Manifest.permission.WRITE_EXTERNAL_STORAGE;
android.Manifest.permission.READ_PHONE_STATE
android.Manifest.permission.PROCESS_OUTGOING_CALLS;
android.Manifest.permission.RECORD_AUDIO;
等等,
注意:Manifests里边必须注册权限,低版本手机才能用,高版本手机才可以申请。
2.申请权限并处理
1)在AndroidManifest文件中添加需要的权限,例:
< uses-permission android:name="android.permission.CAMERA"/>
2)加入检查权限的判断,例:
if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
}else{
//
}
这里涉及到一个API,ContextCompat.checkSelfPermission
,主要用于检测某个权限是否已经被授予,方法返回值
3)没有这个权限,去请求权限
ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS);
该方法是异步的,第一个参数是Context;第二个参数是需要申请的权限的字符串数组;第三个参数为requestCode,主要用于回调的时候检测。可以从方法名requestPermissions
以及第二个参数看出,是支持一次性申请多个权限的,系统会通过对话框逐一询问用户是否授权。
4)处理权限申请回调
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length >
0
&
&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {// permission was granted, yay! Do the
// contacts-related task you need to do.} else {// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
}
}
对于权限的申请结果,首先验证requestCode定位到你的申请,然后验证grantResults对应于申请的结果,这里的数组对应于申请时的第二个权限字符串数组。如果你同时申请两个权限,那么grantResults的length就为2,分别记录你两个权限的申请结果。如果申请成功,就可以做你的事情了~
3.针对大部分权限申请封装
1)权限工具类:PermissionUtils
package com.up366.mobile.common.utils;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
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.content.ContextCompat;
import android.view.View;
import com.up366.common.log.Logger;
import com.up366.mobile.R;
import com.up366.mobile.common.ui.baseui.BaseActivity;
import com.up366.mobile.common.ui.baseui.BaseFragmentActivity;
import com.up366.mobile.common.ui.baseui.IPermissionsCallback;
/**
* @author 王静
* @description 权限申请公用类
* @date 2017年3月9日 下午1:55:37
*/
public class PermissionUtils {
public static int permisionIndexCount = 1;
public static final int PERMISSION_ALL = 0;
public static final int PERMISSION_CAMERA = 1;
public static final int PERMISSION_READ_EXTERNAL_STORAGE = 2;
public static final int PERMISSION_WRITE_EXTERNAL_STORAGE = 3;
public static final int PERMISSION_READ_PHONE_STATE = 4;
public static final int PERMISSION_RECORD_AUDIO = 5;
/**
* 检查权限
*
* @param context
* @param permissionsCallback:回调做后续操作
*/
public static void requestToUserPermission(Context context, IPermissionsCallback permissionsCallback) {
//BaseActivity将PermissionsCallback传入,应用同一个callBack做同样的后续操作
if (context instanceof BaseActivity) {
((BaseActivity) context).setPermissionsCallback(permissionsCallback);
} else if (context instanceof BaseFragmentActivity) {
((BaseFragmentActivity) context).setPermissionsCallback(permissionsCallback);
} else {
throw new IllegalStateException("not Activity context");
}
//判断是哪种类型权限申请
switch (permisionIndexCount) {
case PERMISSION_ALL://所有的,针对小米6.0手机权限有问题,启动不了项目,故去掉刚刚进入app的MainVkActivity就调用申请,可写到内部的Fragment
int i = 0;
String[] permissionStr = new String[6];
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
permissionStr[i++] = android.Manifest.permission.CAMERA;
}
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
permissionStr[i++] = android.Manifest.permission.READ_EXTERNAL_STORAGE;
}
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
permissionStr[i++] = Manifest.permission.WRITE_EXTERNAL_STORAGE;
}
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
permissionStr[i++] = android.Manifest.permission.READ_PHONE_STATE;
permissionStr[i++] = android.Manifest.permission.PROCESS_OUTGOING_CALLS;
}
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
permissionStr[i++] = android.Manifest.permission.RECORD_AUDIO;
}
if (permissionStr.length != 0)
ActivityCompat.requestPermissions((Activity) context, permissionStr, 100); //去请求所有权限
break;
case PERMISSION_CAMERA://相机权限也要有存储权限
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
//没有此权限,去请求权限
ActivityCompat.requestPermissions((Activity) context, new String[]{android.Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);
} else {
//有权限,直接回去做后续操作
handleResult(context, permisionIndexCount);
}
break;
case PERMISSION_READ_EXTERNAL_STORAGE:
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions((Activity) context, new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, 100);
} else {
handleResult(context, permisionIndexCount);
}
break;
case PERMISSION_WRITE_EXTERNAL_STORAGE:
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);
} else {
handleResult(context, permisionIndexCount);
}
break;
case PERMISSION_READ_PHONE_STATE:
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.READ_PHONE_STATE, Manifest.permission.PROCESS_OUTGOING_CALLS}, 100);
} else {
handleResult(context, permisionIndexCount);
}
break;
case PERMISSION_RECORD_AUDIO:
if (ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.RECORD_AUDIO}, 100);
} else {
handleResult(context, permisionIndexCount);
}
break;
}
}
/**
* 有权限,直接去做后续操作
*
* @param context
* @param permisionIndexCount:权限类型index
*/
private static void handleResult(Context context, int permisionIndexCount) {
IPermissionsCallback permissionsCallback = null;
if (context instanceof BaseActivity) {
permissionsCallback = ((BaseActivity) context).getPermissionsCallback();
} else if (context instanceof BaseFragmentActivity) {
permissionsCallback = ((BaseFragmentActivity) context).getPermissionsCallback();
} else {
throw new IllegalStateException("not Activity context");
}
if (permissionsCallback == null) {
Logger.warn("没有注册IPermissionsCallback");
} else {
permissionsCallback.onResult(permisionIndexCount);
}
}
/**
* 申请权限,回调
*
* @param requestCode:code码=100成功
* @param permissions:所请求的权限名称
* @param grantResults:请求结果:PackageManager.PERMISSION_DENIED申请被用户点禁用;PERMISSION_GRANTED申请成功
* @param context:上下文
* @param result:回调,回去做后续操作
*/
public static void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults, final Context context, doSomethingResult result) {
if (requestCode == 100) {
if (grantResults.length > 0) {
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {//拒绝啦
String msg = "";
String permissionName = "";
switch (permisionIndexCount) {//根据请求的类型,弹提示“您已禁用应用所需权限,有些功能将无法使用,请返回重新尝试,并选择允许权限。”
case PERMISSION_ALL:
msg = context.getString(R.string.permission_all);
permissionName = "相关权限";
break;
case PERMISSION_CAMERA:
msg = context.getString(R.string.permission_camera);
permissionName = "相机权限";
break;
case PERMISSION_READ_EXTERNAL_STORAGE:
msg = context.getString(R.string.permission_read_exteranal_storage);
permissionName = "存储权限";
break;
case PERMISSION_WRITE_EXTERNAL_STORAGE:
msg = context.getString(R.string.permission_write_exteranal_storage);
permissionName = "存储权限";
break;
case PERMISSION_READ_PHONE_STATE:
msg = context.getString(R.string.permission_read_phone_state);
permissionName = "电话权限";
break;
case PERMISSION_RECORD_AUDIO:
msg = context.getString(R.string.permission_read_exteranal_storage);
permissionName = "录音权限";
break;
}
//这个用户拒绝了权限请求,并且选择了不再提示!跳转至设置页面
//shouldShowRequestPermissionRationale方法只能在23及以上版本调用
if (Build.VERSION.SDK_INT > = Build.VERSION_CODES.M & & !((Activity) context).shouldShowRequestPermissionRationale(permissions[i])) {
new CuDialog(context).create(R.layout.permission_denyed_forerer_to_setting)
.setText(R.id.dialog_msg, "无法获取" + permissionName + ",需要手动授权,否则该功能无法使用。")
.setOnClickListener(new int[]{R.id.dialog_leftbtn, R.id.dialog_rightbtn}, new View.OnClickListener() {
@Override
public void onClick(View v) {
if (v.getId() == R.id.dialog_rightbtn) {//去设置
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", context.getPackageName(), null);
intent.setData(uri);
((Activity) context).startActivityForResult(intent, 1024);
return;
} else if (v.getId() == R.id.dialog_leftbtn) {//取消
}
}
}).show();
} else {
CuDialog.showOkDialog((Activity) context, msg);
}
return;
}
}
//权限被同意,做后续操作
result.onResult(permisionIndexCount);
}
}
}
/**
* 做后续操作接口
*/
public interface doSomethingResult {
void onResult(int permisionIndexCount);
}
}
PermissionUtils的gist链接:https://gist.github.com/wangjing0311/bf33938d2a762870d406a1b10ace75fe
2)所用接口:
IPermissionsCallback
package com.up366.mobile.common.ui.baseui;
public interface IPermissionsCallback {
void onResult(int permisionIndexCount);
}
3)BaseActivity与BaseFragmentActivity加入
onRequestPermissionsResult回调处理,还有IPermissionsCallback变量及get,set方法
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (permissionsCallback != null)
PermissionUtils.onRequestPermissionsResult(requestCode, permissions, grantResults, this, new PermissionUtils.doSomethingResult() {
@Override
public void onResult(int permisionIndexCount) {
permissionsCallback.onResult(permisionIndexCount);
}
});
}
private IPermissionsCallback permissionsCallback;
public void setPermissionsCallback(IPermissionsCallback permissionsCallback) {
this.permissionsCallback = permissionsCallback;
}
public IPermissionsCallback getPermissionsCallback() {
return permissionsCallback;
}
4)Activity中权限申请的调用:
PermissionUtils.permisionIndexCount = PermissionUtils.PERMISSION_CAMERA;
PermissionUtils.requestToUserPermission(AlertUserInfoActivity.this, permissionsCallback);
及回调处理:
private IPermissionsCallback permissionsCallback = new IPermissionsCallback() {
@Override
public void onResult(int permisionIndexCount) {
switch (permisionIndexCount) {
case 1:
takePictureToPhoto();
break;
case 2:
getLocalPicToPhoto();
break;
}
}
};
本人封装处理,已用感觉比较好用,敬请使用。
推荐阅读
- Android实际开发中的首页框架搭建(首页框架实现)
- Android增加(键盘)按键
- Android帧动画实现,防OOM,比原生动画集节约超过十倍的资源
- GRE数据分析|数据分布,随机变量和概率分布
- Java程序打印字符串的不同排列
- Oracle面试经验|S62(校园服务器技术)
- Java使用正则表达式验证日期格式
- 按字典顺序,给定字符串的所有最短回文子字符串
- 打印数组A[]中的所有字符串,并将数组B[]中的所有字符串作为子序列