android 6.0 权限设置详解
从Android 6.0版本开始,在安装应用时,该应用无法取得任何权限。 相反,在使用应用的过程中,若某个功能需要获取某个权限,系统会弹出一个对话框,显式地由用户决定是否将该权限赋予应用。 只有得到了用户的许可,该功能才可以被使用。
新的权限机制更好的保护了用户的隐私,Google将权限分为两类,一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等;另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等。
1、Normal级别的权限只需要在AndroidManifest中声明就好,安装时就授权,不需要每次使用时都检查权限,而且用户不能取消以上授权
2、其他级别的权限在编译在Android M(即targetSdkVersion大于等于23时候)版本时候,不仅需要在AndroidManifest中声明,还得在运行的时候需要动态申请,而且还可以随时取消授权。
- 先在AndroidManifest中声明
- 再在运行的时候动态申请
权限流程
在API 23中,权限满足的标准流程:
但这里有个问题,那就是在系统授权弹窗环节,提醒框会有个不再提示的复选框,如果用户点击不太提示,并拒绝授权,那么再下次授权的时候,系统授权弹窗的提示框就不会在提示,所以我们很有必要需要自定义权限弹窗提示框,那么流程图就变成如下了。
我们来看具体的代码:
第一步检查权限是否可用:
动态权限的核心工作流程:checkSelfPermission检查是否已被授予——>requestPermissions申请权限——>自动回调onRequestPermissionsResult——shouldShowRequestPermissionRationale。无论什么框架变出花来都离不开这个基本的流程。
我们来看代码:
/***
*
* 检查访问外置sdk的权限是否可以
* */ public void checkstatus(){
if (Build.VERSION.SDK_INT >= 23) {
//我是在Fragment里写代码的,因此调用getActivity
//如果不想判断SDK,可以使用ActivityCompat的接口来检查和申请权限
int hasReadContactsPermission = checkSelfPermission(
Manifest.permission.WRITE_EXTERNAL_STORAGE); if (hasReadContactsPermission != PackageManager.PERMISSION_GRANTED) { //这里就会弹出系统权限对话框
requestPermissions( new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
ASK_READ_CONTACTS_PERMISSION); return;
}
} else {
//权限可用
}
}
此时,点击按键调用Activity的requestPermissions时,将会弹出对话框,类似于下图所示(不同设备商有不同的定制):
无论选择的是“允许”还是“拒绝”,系统都将回调Activity.onRequestPermissionsResult()方法,
并将选择的结果传到方法的第三个参数中。
此时的处理代码示例如下:
private static final int ASK_READ_CONTACTS_PERMISSION = 100;
/**
*
* 当用户操作了权限的按钮的时候会调用该函数
* */
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case ASK_READ_CONTACTS_PERMISSION:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//用户点击了运行权限 } else {
//用户拒绝了权限
Toast.makeText(this,
"READ_CONTACTS Denied",
Toast.LENGTH_SHORT)
.show();
//跳转到权限的设置界面,提示用户开启权限的设置
goToAppSettings(); }
return;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
这里如果用户选择了拒绝权限这里跳转到设置页面提示用户开启权限。
这里有一个很关键的地方,弹出系统权限对话框的时候,有有一个不再提示权限对话框的勾,当用户如果勾选了,在第二次调用requestPermissions申请权限的时候,是不会在弹出系统系统权限的对话框的,
如上图所示,每当系统申请权限时,弹出的对话框会有一个类似于“拒绝后不再询问”的勾选项。
若用户打了勾,并选择拒绝,那么下次程序调用Activity.requestPermissions()方法时,将不会弹出对话框,权限也不会被赋予
所以要实现下面的功能,第一次启动app的时候,如果用户勾选了不再提示,禁止了开启权限,在第二次进行app的时候,我们也应该提示用户权限被禁止,如何实现了
此时应调用Activity.shouldShowRequestPermissionRationale()方法,示例代码如下:
/***
*
* 检查访问外置sdk的权限是否可以
* */ public void checkstatus(){
if (Build.VERSION.SDK_INT >= 23) {
//我是在Fragment里写代码的,因此调用getActivity
//如果不想判断SDK,可以使用ActivityCompat的接口来检查和申请权限
int hasReadContactsPermission = checkSelfPermission(
Manifest.permission.WRITE_EXTERNAL_STORAGE); if (hasReadContactsPermission != PackageManager.PERMISSION_GRANTED) {
//判断是否点击过“拒绝并不再提示”,若点击了,则应用自己弹出一个Dialog
if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
showMessageOKCancel("You need to allow access to Contacts", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//这里就会弹出对话框
if (Build.VERSION.SDK_INT >= 23){
Log.d("123456","on2222222");
requestPermissions( new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
ASK_READ_CONTACTS_PERMISSION);
} }
});
return;
} //这里就会弹出对话框
requestPermissions( new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
ASK_READ_CONTACTS_PERMISSION); return;
} //高版本中检查是否有运行时权限,具有权限时才调用
//getPhoneNumberAndDial();
} else {
//在AndroidManifest.xml中仍然声明使用"android.permission.READ_CONTACTS"
//在低版本中直接调用该函数
//getPhoneNumberAndDial();
}
}
此时,应用第一次申请权限及用户勾选了“不再询问”复选框时,均会弹出类似如下的对话框:
1、若第一次申请时点击OK,将会弹出权限申请的界面;
2、第二次进入app,用户勾选过“拒绝后不再询问时”,点击OK不会再次拉起申请界面,但是会调用requestPermissions函数,回调同时onRequestPermissionsResult中收到的结果为PackageManager.PERMISSION_DENIED,此时提醒用户到设置界面去开启权限
private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(this)
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", null)
.create()
.show();
}
跳转至应用设置页
/**
* 应用设置页
*/
private void goToAppSettings() {
Intent myAppSettings = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + getPackageName()));
myAppSettings.addCategory(Intent.CATEGORY_DEFAULT);
// myAppSettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(myAppSettings, 5);
}
5. 用户在应用设置页设置完权限后回到应用,判断是否已获得权限
private String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 5){
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
//检查该权限是否已经获取
int i = ContextCompat.checkSelfPermission(this, permissions[0]);
// 权限是否已经 授权 GRANTED---授权 DINIED---拒绝
if (i != PackageManager.PERMISSION_GRANTED) {
goToAppSettings();
}else {
Toast.makeText(this, "权限获取成功", Toast.LENGTH_SHORT).show();
}
}
}
}
相当的经典。
我们来看整个activity的代码:
package application.weiyuan.com.download_demo; import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.opengl.Visibility;
import android.os.Build;
import android.os.Parcelable;
import android.os.SystemClock;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RemoteViews;
import android.widget.TextView;
import android.widget.Toast; import com.download.bean.FileInfo;
import com.download.com.download.utils.DownLoadApplication;
import com.download.com.download.utils.runtimepermissions.PermissionsManager;
import com.download.com.download.utils.runtimepermissions.PermissionsResultAction;
import com.download.constants.Constant;
import com.download.services.DownLoadService; import java.io.File;
import java.util.ArrayList;
import java.util.List; import static com.download.com.download.utils.DownLoadApplication.context; public class MainActivity extends Activity { private static final String TAG = Constant.TAG + " MainActivity";
private static final int ASK_READ_CONTACTS_PERMISSION = 100;
private TextView mTvFileName;
private ProgressBar mPbDownLoad;
private Button mBtnStart;
private Button mBtnStop;
private ListView mLv_show;
DownLoadAdapter adapter = null;
Notification notification;
private Button btn_main_update;
private NotificationManager mNotificationManager = null; /*private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "onReceive: " );
if(intent.getAction().equals(Constant.UPDATE_PROGRESSBAR)){
int progress = intent.getIntExtra("finished",0);
int id = intent.getIntExtra("file_id",0);
adapter.updateProgress(id,progress);
//更新通知栏的进度
notification.contentView.setTextViewText(R.id.tv_notification_progress,""+progress+"%");
notification.contentView.setProgressBar(R.id.pb_notification_download, 100, progress, false);
mNotificationManager.notify(id, notification);
Log.i(TAG, "onReceive: finished:" + progress); }
if(intent.getAction().equals(Constant.Finished_PROGRESSBAR)){
FileInfo fileInfo = intent.getParcelableExtra("fileInfo");
adapter.updateProgress(fileInfo.getFileId(),0);
Toast.makeText(MainActivity.this, fileInfo.getFileName()+"文件下载完成", Toast.LENGTH_SHORT).show();
//更新通知栏显示文件已经下载成功
notification.contentView.setTextViewText(R.id.tv_notification_progress,"密码卡管家下载完成,点击安装");
notification.contentView.setViewVisibility(R.id.pb_notification_download, View.GONE);
notification.contentView.setViewVisibility(R.id.tv_notification_name, View.GONE);
//点击安装目录
File apkFile = new File(Constant.DOWNLOAD_FILE_PATH+File.separator+fileInfo.getFileName());
if (!apkFile.exists()) {
return;
}
Intent i = new Intent(Intent.ACTION_VIEW);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.setDataAndType(Uri.parse("file://" + apkFile.toString()), "application/vnd.android.package-archive");
PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, i, PendingIntent.FLAG_ONE_SHOT);
notification.contentIntent = pendingIntent;
mNotificationManager.notify(fileInfo.getFileId(), notification);
// notification.contentView.setProgressBar(R.id.pb_notification_download, 100, progress, false);
installApk(fileInfo); }
if(intent.getAction().equalsIgnoreCase(Constant.NOTIFICATION_DOWNLOAD_START)){
// 下载开始的时候启动通知栏
Parcelable parcelable= intent.getParcelableExtra("fileInfo");
FileInfo fileInfo = (FileInfo)parcelable;
notification = new Notification();
notification.when = System.currentTimeMillis();
notification.icon = R.mipmap.ic_launcher;
notification.flags = Notification.FLAG_AUTO_CANCEL;
*//* Intent i = new Intent(MainActivity.this, MainActivity.class);
PendingIntent pd = PendingIntent.getActivity(i, 0, intent, PendingIntent.FLAG_NO_CREATE);
notification.contentIntent = pd;*//*
Intent i= new Intent(MainActivity.this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
notification.contentIntent = pendingIntent; // 设置远程试图RemoteViews对象
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.notification_2);
remoteViews.setTextViewText(R.id.tv_notification_name, "密码卡管家正在下载中...");
// 设置Notification的视图
notification.contentView = remoteViews;
// 发出Notification通知
mNotificationManager.notify(fileInfo.getFileId(), notification); }
}
};*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
//requestPermissions();
checkstatus();
Log.d("123456","oncreat is called");
mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
/* IntentFilter filter = new IntentFilter();
filter.addAction(Constant.UPDATE_PROGRESSBAR);
filter.addAction(Constant.Finished_PROGRESSBAR);
filter.addAction(Constant.NOTIFICATION_DOWNLOAD_START);
registerReceiver(broadcastReceiver, filter);*/ btn_main_update = (Button) findViewById(R.id.btn_main_update);
btn_main_update.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
/* final VersionDialogFragment dialogFragment = VersionDialogFragment.getInstance("2.0.1新版本发布啦", "更多功能等你体验,jsjjjkds" +
"sfdkkfskdkfd" +
"kskkkl" +
"sfkk,dfk" +
"sfdk,df","大小:5.06M","详情:1.7.0.1","12122");
dialogFragment.show(getFragmentManager());*/ new Thread(new Runnable() {
@Override
public void run() {
try {
final UpdateInfo updateInfo = new UpdateService().getUpdateInfo("http://10.12.7.21:8080/UpdateApk/UpdateServlet");
PackageManager manager = MainActivity.this.getPackageManager();
PackageInfo info = manager.getPackageInfo(MainActivity.this.getPackageName(), 0);
final int version = info.versionCode;
//判断是否是强制升级
if(Integer.parseInt(updateInfo.getServerSupportMinVer())>version){//说明是强制升级
runOnUiThread(new Runnable() {
@Override
public void run() {
final VersionDialogFragment dialogFragment = VersionDialogFragment.getInstance(
updateInfo.getVersionName()+"新版本发布啦",
updateInfo.getUpgradeDetailInfo(),
"大小:"+updateInfo.getFileSize(),
"详情:"+updateInfo.getServerVersion(),
updateInfo.getImageURL(),
updateInfo.getDownload_url());
dialogFragment.show(getFragmentManager(),true);
}
}); }else{ //判断是否是普通升级
if(Integer.parseInt(updateInfo.getVersionCode())> version){
//说明服务器版本是最大的
runOnUiThread(new Runnable() {
@Override
public void run() {
//判断是否是强制升级
final VersionDialogFragment dialogFragment = VersionDialogFragment.getInstance(
updateInfo.getVersionName()+"新版本发布啦",
updateInfo.getUpgradeDetailInfo(),
"大小:"+updateInfo.getFileSize(),
"详情:"+updateInfo.getServerVersion(),
updateInfo.getImageURL(),
updateInfo.getDownload_url());
dialogFragment.show(getFragmentManager(),false);
}
});
}else{
//说明服务器版本是最大的
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,"您所使用的已是最新的版本",Toast.LENGTH_LONG).show();
}
});
}
} } catch (final Exception e) {
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,"获得升级信息失败"+e.toString(),Toast.LENGTH_LONG).show();
}
});
}
}
}).start();
}
}); } private void initView() {
/* mTvFileName = (TextView)findViewById(R.id.tv_fileName);
mPbDownLoad = (ProgressBar)findViewById(R.id.pb_download);
mBtnStart = (Button)findViewById(R.id.btn_start);
mBtnStop = (Button)findViewById(R.id.btn_stop);
mPbDownLoad.setMax(100);*/
List<FileInfo>fileInfos = new ArrayList<>();
FileInfo fileInfo = new FileInfo(0, "http://ecm.sec-apps.com/download/ecm-professional/EncryptCardManager.apk",
"EncryptCardManager.apk", 0, 0);
fileInfos.add(fileInfo);
mLv_show = (ListView)findViewById(R.id.lv_show);
adapter = new DownLoadAdapter(fileInfos,MainActivity.this);
mLv_show.setAdapter(adapter); } @Override
protected void onDestroy() {
super.onDestroy();
} private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE" }; public static void verifyStoragePermissions(Activity activity) { try {
//检测是否有写的权限
int permission = ActivityCompat.checkSelfPermission(activity,
"android.permission.WRITE_EXTERNAL_STORAGE");
if (permission != PackageManager.PERMISSION_GRANTED) {
// 没有写的权限,去申请写的权限,会弹出对话框
ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE);
}
} catch (Exception e) {
e.printStackTrace();
}
} /**
* 下载完成点击安装apk
* */
private void installApk(FileInfo fileInfo) {
File apkFile = new File(Constant.DOWNLOAD_FILE_PATH+File.separator+fileInfo.getFileName());
if (!apkFile.exists()) {
return;
}
Intent i = new Intent(Intent.ACTION_VIEW);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.setDataAndType(Uri.parse("file://" + apkFile.toString()), "application/vnd.android.package-archive");
DownLoadApplication.getGlobalContext().startActivity(i);
} /**
* android 6.0以上检查下载所需的网络和sd卡的访问权限
* 当
* */
private void requestPermissions(){
PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(this, PERMISSIONS_STORAGE, new PermissionsResultAction() {
@Override
public void onGranted() {
Log.d("123456","1110");
} @Override
public void onDenied(String permission) {
Log.d("123456","on");
}
}); } /***
*
* 检查访问外置sdk的权限是否可以
* */ public void checkstatus(){
if (Build.VERSION.SDK_INT >= 23) {
//我是在Fragment里写代码的,因此调用getActivity
//如果不想判断SDK,可以使用ActivityCompat的接口来检查和申请权限
int hasReadContactsPermission = checkSelfPermission(
Manifest.permission.WRITE_EXTERNAL_STORAGE); if (hasReadContactsPermission != PackageManager.PERMISSION_GRANTED) {
//判断是否点击过“拒绝并不再提示”,若点击了,则应用自己弹出一个Dialog
if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
showMessageOKCancel("You need to allow access to Contacts", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//这里就会弹出对话框
if (Build.VERSION.SDK_INT >= 23){
Log.d("123456","on2222222");
requestPermissions( new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
ASK_READ_CONTACTS_PERMISSION);
} }
});
return;
} //这里就会弹出对话框
requestPermissions( new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
ASK_READ_CONTACTS_PERMISSION); return;
} //高版本中检查是否有运行时权限,具有权限时才调用
//getPhoneNumberAndDial();
} else {
//在AndroidManifest.xml中仍然声明使用"android.permission.READ_CONTACTS"
//在低版本中直接调用该函数
//getPhoneNumberAndDial();
}
}
/**
*
* 当用户操作了权限的按钮的时候会调用该函数
* */
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case ASK_READ_CONTACTS_PERMISSION:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//用户点击了运行权限 } else {
//用户拒绝了权限
Toast.makeText(this,
"READ_CONTACTS Denied",
Toast.LENGTH_SHORT)
.show();
//跳转到权限的设置界面,提示用户开启权限的设置
goToAppSettings(); }
return;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
} private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(this)
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", null)
.create()
.show();
} /**
* 应用设置页
*/
private void goToAppSettings() {
Intent myAppSettings = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + getPackageName()));
myAppSettings.addCategory(Intent.CATEGORY_DEFAULT);
// myAppSettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(myAppSettings, 5);
}
private String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 5){
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
//检查该权限是否已经获取
int i = ContextCompat.checkSelfPermission(this, permissions[0]);
// 权限是否已经 授权 GRANTED---授权 DINIED---拒绝
if (i != PackageManager.PERMISSION_GRANTED) {
goToAppSettings();
}else {
Toast.makeText(this, "权限获取成功", Toast.LENGTH_SHORT).show();
}
}
}
}
}
参看博客:http://www.jianshu.com/p/670088275094
http://blog.csdn.net/gaugamela/article/details/56277793
http://www.cnblogs.com/cr330326/p/5181283.html
项目代码2:上面的代码只是检查了一个存储权限,如果app需要申请多个权限如何处理了看下面的代码
package logback.ecmapplication.cetcs.com.quanxian; import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
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.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast; import java.util.ArrayList;
import java.util.List; public class MainActivity extends Activity {
private static final int ASK_READ_CONTACTS_PERMISSION = ;
public static final String[] COMPULSORY_PERMISSIONS = new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_COARSE_LOCATION,
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("","onCreate is called");
checkstatus();
} // 判断是否缺少权限
public static boolean lacksPermission(Context context, String permission) {
return ContextCompat.checkSelfPermission(context, permission) ==
PackageManager.PERMISSION_DENIED;
} public static String[] lackedPermissions(Context context, String... permissions){
List<String> lacks = new ArrayList();
for (String permission:permissions){
if (lacksPermission(context, permission)){
lacks.add(permission);
}
} if (lacks.size() == ){
return null;
}
return lacks.toArray(new String[lacks.size()]);
} /***
*
* 检查访问外置sdk的权限是否可以
* */ /***
*
* 检查访问外置sdk的权限是否可以
* */ public void checkstatus(){
if (Build.VERSION.SDK_INT >= ) {
//我是在Fragment里写代码的,因此调用getActivity
//如果不想判断SDK,可以使用ActivityCompat的接口来检查和申请权限
String[] lacked = lackedPermissions(getApplicationContext(), COMPULSORY_PERMISSIONS);
if(lacked != null && lacked.length > ){ requestPermissions(lacked,
ASK_READ_CONTACTS_PERMISSION);
}else{
//用户权限已经全部开启
}
//高版本中检查是否有运行时权限,具有权限时才调用
//getPhoneNumberAndDial();
} else {
//在AndroidManifest.xml中仍然声明使用"android.permission.READ_CONTACTS"
//在低版本中直接调用该函数
//getPhoneNumberAndDial();
}
} /**
*
* 当用户操作了权限的按钮的时候会调用该函数
* */
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
boolean allPermissionsOpened = true;
switch (requestCode) {
case ASK_READ_CONTACTS_PERMISSION:
for(int i = ;i< grantResults.length;i++){
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
allPermissionsOpened = false;
break;
} }
if(allPermissionsOpened){
//权限已经全部开启
Toast.makeText(this,
"allPermissionsOpened opened",
Toast.LENGTH_SHORT)
.show();
}else{
//提示跳转到权限的设置界面,提示用户开启权限的设置
showMessageOKCancel("密码卡管家缺少运行所需权限,请点击“设置”-“权限”打开所有权限", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
goToAppSettings();
}
});
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
break;
}
} /**
* 应用设置页
*/
private void goToAppSettings() {
Intent myAppSettings = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + getPackageName()));
myAppSettings.addCategory(Intent.CATEGORY_DEFAULT);
// myAppSettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(myAppSettings, ASK_READ_CONTACTS_PERMISSION);
} @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == ASK_READ_CONTACTS_PERMISSION){
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
/* //检查该权限是否已经获取
int i = ContextCompat.checkSelfPermission(this, permissions[0]);
// 权限是否已经 授权 GRANTED---授权 DINIED---拒绝
if (i != PackageManager.PERMISSION_GRANTED) {
//goToAppSettings();
Toast.makeText(this, "没有在权限中开启对应的权限", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(this, "权限获取成功", Toast.LENGTH_SHORT).show();
}*/
checkstatus();
}
}
} private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(this)
.setMessage(message)
.setPositiveButton("开启权限", okListener)
.setNegativeButton("退出应用", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.create()
.show();
}
}
上面的代码还存在一个问题:相当的经典
经典问题4:
/**
*
* 当用户操作了权限的按钮的时候会调用该函数,弹出系统权限对话框的时候,如果用户点击禁止按钮或者允许权限
* int[] grantResults的长度都不为0
* 但是这里有一个陷阱,当弹出系统权限对话框的时候,用户没有点击禁止或者允许权限按钮,这个时候点击了手机的home按钮
* 然后在点击app图标,这个时候不会再弹出系统的系统权限对话框,但是也会调用onRequestPermissionsResult函数,这个时候
* int[] grantResults长度是0,这个时候界面会调用onResume函数,这个时候要在OnResume函数中继续去调用权限检查的函数
* */
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
所以下面的代码应该修改为
package logback.ecmapplication.cetcs.com.quanxian; import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
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.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast; import java.util.ArrayList;
import java.util.List; public class MainActivity extends Activity {
private static final int ASK_READ_CONTACTS_PERMISSION = 100;
/**
* 表示在弹出系统权限对话框的时候,点击了手机的home按键
*/
public static boolean clickHomeButtonWhenSystemPermissionsDialogIsShowing = false;
public static final String[] COMPULSORY_PERMISSIONS = new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_COARSE_LOCATION,
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("123456","onCreate is called");
checkstatus();
} // 判断是否缺少权限
public static boolean lacksPermission(Context context, String permission) {
return ContextCompat.checkSelfPermission(context, permission) ==
PackageManager.PERMISSION_DENIED;
} public static String[] lackedPermissions(Context context, String... permissions){
List<String> lacks = new ArrayList();
for (String permission:permissions){
if (lacksPermission(context, permission)){
lacks.add(permission);
}
} if (lacks.size() == 0 ){
return null;
}
return lacks.toArray(new String[lacks.size()]);
} /***
*
* 检查访问外置sdk的权限是否可以
* */ /***
*
* 检查访问外置sdk的权限是否可以
* */ public void checkstatus(){
if (Build.VERSION.SDK_INT >= 23) {
//我是在Fragment里写代码的,因此调用getActivity
//如果不想判断SDK,可以使用ActivityCompat的接口来检查和申请权限
String[] lacked = lackedPermissions(getApplicationContext(), COMPULSORY_PERMISSIONS);
if(lacked != null && lacked.length > 0){ requestPermissions(lacked,
ASK_READ_CONTACTS_PERMISSION);
}else{
//用户权限已经全部开启
}
//高版本中检查是否有运行时权限,具有权限时才调用
//getPhoneNumberAndDial();
} else {
//在AndroidManifest.xml中仍然声明使用"android.permission.READ_CONTACTS"
//在低版本中直接调用该函数
//getPhoneNumberAndDial();
}
} /**
*
* 当用户操作了权限的按钮的时候会调用该函数
* */
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
boolean allPermissionsOpened = true;
switch (requestCode) {
case ASK_READ_CONTACTS_PERMISSION:
if(grantResults.length == 0){
clickHomeButtonWhenSystemPermissionsDialogIsShowing = true;
return;
}
clickHomeButtonWhenSystemPermissionsDialogIsShowing = false;
for(int i = 0 ;i< grantResults.length;i++){
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
allPermissionsOpened = false;
break;
} }
if(allPermissionsOpened){
//权限已经全部开启
Toast.makeText(this,
"allPermissionsOpened opened",
Toast.LENGTH_SHORT)
.show();
}else{
//提示跳转到权限的设置界面,提示用户开启权限的设置
showMessageOKCancel("密码卡管家缺少运行所需权限,请点击“设置”-“权限”打开所有权限", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
goToAppSettings();
}
});
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
break;
}
} /**
* 应用设置页
*/
private void goToAppSettings() {
Intent myAppSettings = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + getPackageName()));
myAppSettings.addCategory(Intent.CATEGORY_DEFAULT);
// myAppSettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(myAppSettings, ASK_READ_CONTACTS_PERMISSION);
} @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == ASK_READ_CONTACTS_PERMISSION){
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
/* //检查该权限是否已经获取
int i = ContextCompat.checkSelfPermission(this, permissions[0]);
// 权限是否已经 授权 GRANTED---授权 DINIED---拒绝
if (i != PackageManager.PERMISSION_GRANTED) {
//goToAppSettings();
Toast.makeText(this, "没有在权限中开启对应的权限", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(this, "权限获取成功", Toast.LENGTH_SHORT).show();
}*/
checkstatus();
}
}
} private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(this)
.setMessage(message)
.setPositiveButton("开启权限", okListener)
.setNegativeButton("退出应用", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.create()
.show();
}
@Override
protected void onResume() {
if(clickHomeButtonWhenSystemPermissionsDialogIsShowing){
checkstatus();
}
super.onResume();
}
}
程序代码下载地址:
https://pan.baidu.com/s/1hrWe7e0
android 6.0 权限设置详解的更多相关文章
- [转]Android 5.0——Material Design详解(动画篇)
Material Design:Google推出的一个全新的设计语言,它的特点就是拟物扁平化. Material Design包含了很多内容,今天跟大家分享一下Material新增的动画: 在Andr ...
- Android各种访问权限Permission详解
原文:http://jingyan.baidu.com/article/afd8f4de4688af34e386e976.html 在Android的设计中,资源的访问或者网络连接,要得到这些服务都需 ...
- Android 7.0 IMS框架详解
本文主要讲解IP Multimedia Subsystem (IMS)在Android 7.0上由谷歌Android实现的部分内容.从APP侧一直到Telephony Framework,是不区分CS ...
- mongodb 用户 权限 设置 详解
原文地址:http://blog.51yip.com/nosql/1575.html 我知道的关系型数据库都是有权限控制的,什么用户能访问什么库,什么表,什么用户可以插入,更新,而有的用户只有读取权限 ...
- Android EventBus 3.0 实例使用详解
EventBus的使用和原理在网上有很多的博客了,其中泓洋大哥和启舰写的非常非常棒,我也是跟着他们的博客学会的EventBus,因为是第一次接触并使用EventBus,所以我写的更多是如何使用,源码解 ...
- IIS7.0 Appcmd 命令详解和定时重启应用池及站点的设置
IIS7.0 Appcmd 命令详解 废话不说!虽然有配置界面管理器!但是做安装包的时候命令创建是必不可少的!最近使用NSIS制作安装包仔细研究了一下Appcmd的命令,可谓是功能齐全. 上网查了些资 ...
- Android高效率编码-第三方SDK详解系列(三)——JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送
Android高效率编码-第三方SDK详解系列(三)--JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送 很久没有更新第三方SDK这个系列了,所以更新一下这几天工作中使用到的推送, ...
- 【Android 应用开发】Ubuntu 下 Android Studio 开发工具使用详解 (旧版本 | 仅作参考)
. 基本上可以导入项目开始使用了 ... . 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/21035637 ...
- Android高效率编码-第三方SDK详解系列(二)——Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能
Android高效率编码-第三方SDK详解系列(二)--Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能 我的本意是第二篇写Mob的shareSD ...
随机推荐
- java内部类简单用法
package innerClass; /** * 特点 * 1:增强封装性,通过把内部类隐藏在外部类的里面,使得其他类不能访问外部类. * 2:增强可维护性. * 3:内部类可以访问外部的成员. * ...
- 一篇文章,全面掌握Git
版本控制 版本控制就是记录项目文件的历史变化.它为我们查阅日志,回退,协作等方面提供了有力的帮助. 版本控制一般分为集中化版本控制和分布式版本控制. 集中化主要的版本数据都保存服务端. 分布式版本数据 ...
- 如何发布一个 npm 包
一 背景 在工作时,突然接到经理的一个要求,需要将一个react的高阶组件函数封装成一个npm包.之前从没弄过,当场还是有些懵逼的,但是这毕竟是工作,不能推脱.于是开始了学习.汤坑之旅.最终包发布,线 ...
- Java 第十一届 蓝桥杯 省模拟赛 小明的城堡
小明用积木搭了一个城堡. 为了方便,小明在搭的时候用的是一样大小的正方体积本,搭在了一个 n 行 m 列的方格图上,每个积木正好占据方格图的一个小方格. 当然,小明的城堡并不是平面的,而是立体的.小明 ...
- Java实现蓝桥杯VIP算法训练 石子游戏
试题 算法训练 石子游戏 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 石子游戏的规则如下: 地上有n堆石子,每次操作可选取两堆石子(石子个数分别为x和y)并将它们合并,操作的得分 ...
- Java实现 LeetCode 171 Excel表列序号
171. Excel表列序号 给定一个Excel表格中的列名称,返回其相应的列序号. 例如, A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> ...
- Java实现 计蒜客 1251 仙岛求药
仙岛求药 少年李逍遥的婶婶病了,王小虎介绍他去一趟仙灵岛,向仙女姐姐要仙丹救婶婶.叛逆但孝顺的李逍遥闯进了仙灵岛,克服了千险万难来到岛的中心,发现仙药摆在了迷阵的深处.迷阵由 M \times NM× ...
- Java实现 蓝桥杯 算法提高 宰羊
试题 算法提高 宰羊 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 炫炫回了内蒙,肯定要吃羊肉啦,所有他家要宰羊吃. 炫炫家有N只羊,羊圈排成一排,标号1~N.炫炫每天吃掉一只羊( ...
- Java实现 LeetCode 60 第k个排列
60. 第k个排列 给出集合 [1,2,3,-,n],其所有元素共有 n! 种排列. 按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下: "123" &q ...
- Java实现 蓝桥杯 算法提高 双十一抢购
试题 算法提高 双十一抢购 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 一年一度的双十一又来了,某网购网站又开始了半价销售的活动. 小G打算在今年的双十一里尽情地购物,以享受购买 ...