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 = 100; 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: 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(); } }
上面的代码还存在一个问题:相当的经典
经典问题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
posted on 2017-05-23 16:31 luzhouxiaoshuai 阅读(1301) 评论(0) 编辑 收藏 举报