从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 权限设置详解的更多相关文章

  1. [转]Android 5.0——Material Design详解(动画篇)

    Material Design:Google推出的一个全新的设计语言,它的特点就是拟物扁平化. Material Design包含了很多内容,今天跟大家分享一下Material新增的动画: 在Andr ...

  2. Android各种访问权限Permission详解

    原文:http://jingyan.baidu.com/article/afd8f4de4688af34e386e976.html 在Android的设计中,资源的访问或者网络连接,要得到这些服务都需 ...

  3. Android 7.0 IMS框架详解

    本文主要讲解IP Multimedia Subsystem (IMS)在Android 7.0上由谷歌Android实现的部分内容.从APP侧一直到Telephony Framework,是不区分CS ...

  4. mongodb 用户 权限 设置 详解

    原文地址:http://blog.51yip.com/nosql/1575.html 我知道的关系型数据库都是有权限控制的,什么用户能访问什么库,什么表,什么用户可以插入,更新,而有的用户只有读取权限 ...

  5. Android EventBus 3.0 实例使用详解

    EventBus的使用和原理在网上有很多的博客了,其中泓洋大哥和启舰写的非常非常棒,我也是跟着他们的博客学会的EventBus,因为是第一次接触并使用EventBus,所以我写的更多是如何使用,源码解 ...

  6. IIS7.0 Appcmd 命令详解和定时重启应用池及站点的设置

    IIS7.0 Appcmd 命令详解 废话不说!虽然有配置界面管理器!但是做安装包的时候命令创建是必不可少的!最近使用NSIS制作安装包仔细研究了一下Appcmd的命令,可谓是功能齐全. 上网查了些资 ...

  7. Android高效率编码-第三方SDK详解系列(三)——JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送

    Android高效率编码-第三方SDK详解系列(三)--JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送 很久没有更新第三方SDK这个系列了,所以更新一下这几天工作中使用到的推送, ...

  8. 【Android 应用开发】Ubuntu 下 Android Studio 开发工具使用详解 (旧版本 | 仅作参考)

    . 基本上可以导入项目开始使用了 ... . 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/21035637 ...

  9. Android高效率编码-第三方SDK详解系列(二)——Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能

    Android高效率编码-第三方SDK详解系列(二)--Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能 我的本意是第二篇写Mob的shareSD ...

随机推荐

  1. BFC与优雅降级 渐进增强——学习笔记

    BFC(块级格式化上下文) BFC(Block formatting context) 直译为"块级格式化上下文". 元素的显示模式 我们前面讲过 元素的显示模式 display. ...

  2. 15 . PythonWeb框架本质

    PythonWeb框架的本质 简单描述就是:浏览器通过你输入的网址给你的socket服务端发送请求,服务端接受到请求给其回复一个对应的html页面,这就是web项目.所有的Web应用本质上就是一个so ...

  3. CSS3新增伪类有那些?

    p:first-of-type 选择属于其父元素的首个元素 p:last-of-type 选择属于其父元素的最后元素 p:only-of-type 选择属于其父元素唯一的元素 p:only-child ...

  4. Java并发编程 (十) 多线程并发拓展

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.死锁 1.死锁的定义 所谓的死锁是指两个或两个以上的线程在等待执行的过程中,因为竞争资源而造成的一种 ...

  5. WEB前端程序员需要的网站整理

    前端学习资源实在是又多又广,在这样的一个知识的海洋里,我们像一块海绵一样吸收,想要快速提高效率,平时的总结不可缺少,以下总结了一些,排版自我感觉良好,推送出来. 一.插件类网站 jQuery插件库:h ...

  6. vue+jquery使用FormData向后端传递数据和文件,express如何获取

    使用multiparty 模块 下载 cnpm install multiparty --save 前端代码: <template> <div class="add-are ...

  7. webpack+vue+.vue组件模板文件 所需要的包

    {  "name": "webpack-study02",  "version": "1.0.0",  "de ...

  8. Servlet Session MVC模式

    一   什么是Session 当首次使用session时,服务器端要创建session,session是保存在服务器端,而给客户端的session的id(一个cookie中保存了sessionId). ...

  9. GPIO功能框图

    (1)保护二极管 引脚内部加上这两个保护二级管可以防止引脚外部过高或过低的电压输入, 当引脚电压高于 VDD_FT 或 VDD 时,上方的二极管导通吸收这个高电压,当引脚 电压低于 VSS 时,下方的 ...

  10. <VCC笔记> 关于Assertion

    这篇博客开始介绍VCC的用法,先用简单的例子介绍VCC的基本语法,当然面对更复杂的程序时,VCC也是将他简化然后分析的. 1.Assertion #include <vcc.h> int ...