您的位置:首页 > 移动开发 > Android开发

Android6.0动态申请权限那些坑--以及避免用户选择不再提示后无法获取权限的问题

2016-11-09 18:07 726 查看
Android6.0为了保护用户隐私,将一些权限的申请放在了应用运行的时候去申请,比如以往的开发中,开发人员只需要将需要的权限在清单文件中配置即可,安装后用户可以在设置中的应用信息中看到:XX应用以获取****权限。用户点击可以选择给应用相应的权限。此前的应用权限用户可以选择允许、提醒和拒绝。在安装的时候用户是已经知道应用需要的权限的。但是这样存在一个问题,就是用户在安装的时候,应用需要的权限十分的多(有些开发者为了省事,会请求一些不必要的权限或者请求全部的权限),这个时候用户在安装应用的时候也许并没有发现某些侵犯自己隐私的权限请求,安装之后才发现自己的隐私数据被窃取。其实Android6.0动态权限一方面是为了广大用户考虑,另一方面其实是Google为了避免一些不必要的官司。下面就说一下Android6.0对权限的分割:

这类权限需要在需要的时候,需要我们动态申请,比如:当我们需要打开相机拍摄照片的时候需要我们通过代码的方式在需要的地方去申请权限。Android6.0中权限问题中我们需要注意的是:

[b][b][b][b][b][b][b][b][b][b][b][b]具体的权限分组情况如下表:[/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b]


[b][b]
group:android.permission-group.[b]CONTACTS
[/b][/b][/b]
[b]
permission:android.permission.WRITE_CONTACTS
[/b]
[b]
permission:android.permission.GET_ACCOUNTS
[/b]
[b]
permission:android.permission.READ_CONTACTS
[/b]
[b]
[/b]
[b]
group:android.permission-group.[b]PHONE
[/b][/b]
[b]
permission:android.permission.READ_CALL_LOG
[/b]
[b]
permission:android.permission.READ_PHONE_STATE
[/b]
[b]
permission:android.permission.CALL_PHONE
[/b]
[b]
permission:android.permission.WRITE_CALL_LOG
[/b]
[b]
permission:android.permission.USE_SIP
[/b]
[b]
permission:android.permission.PROCESS_OUTGOING_CALLS
[/b]
[b]
permission:com.android.voicemail.permission.ADD_VOICEMAIL
[/b]
[b]
[/b]
[b]
group:android.permission-group.[b]CALENDAR
[/b][/b]
[b]
permission:android.permission.READ_CALENDAR
[/b]
[b]
permission:android.permission.WRITE_CALENDAR
[/b]
[b]
[/b]
[b]
group:android.permission-group.[b]CAMERA
[/b][/b]
[b]
permission:android.permission.CAMERA
[/b]
[b]
[/b]
[b]
group:android.permission-group.[b]SENSORS
[/b][/b]
[b]
permission:android.permission.BODY_SENSORS
[/b]
[b]
[/b]
[b]
group:android.permission-group.[b]LOCATION
[/b][/b]
[b]
permission:android.permission.ACCESS_FINE_LOCATION
[/b]
[b]
permission:android.permission.ACCESS_COARSE_LOCATION
[/b]
[b]
[/b]
[b]
group:android.permission-group.[b]STORAGE
[/b][/b]
[b]
permission:android.permission.READ_EXTERNAL_STORAGE
[/b]
[b]
permission:android.permission.WRITE_EXTERNAL_STORAGE
[/b]
[b]
[/b]
[b]
group:android.permission-group.[b]MICROPHONE
[/b][/b]
[b]
permission:android.permission.RECORD_AUDIO
[/b]
[b]
[/b]
[b]
group:android.permission-group.[b]SMS
[/b][/b]
[b]
permission:android.permission.READ_SMS
[/b]
[b]
permission:android.permission.RECEIVE_WAP_PUSH
[/b]
[b]
permission:android.permission.RECEIVE_MMS
[/b]
[b]
permission:android.permission.RECEIVE_SMS
[/b]
[b]
permission:android.permission.SEND_SMS
[/b]
[b]
permission:android.permission.READ_CELL_BROADCASTS
[/b]

[b]
[b]普通权限的总结:
[/b][/b]
[b]
[/b]
[b]
ACCESS_LOCATION_EXTRA_COMMANDS定位权限
[/b]
[b]
[/b]
[b]
ACCESS_NETWORK_STATE网络状态权限
[/b]
[b]
[/b]
[b]
ACCESS_NOTIFICATION_POLICY通知APP通知显示在状态栏
[/b]
[b]
[/b]
[b]
ACCESS_WIFI_STATEWiFi状态权限
[/b]
[b]
[/b]
[b]
BLUETOOTH使用蓝牙权限
[/b]
[b]
[/b]
[b]
BLUETOOTH_ADMIN控制蓝牙开关
[/b]
[b]
[/b]
[b]
BROADCAST_STICKY粘性广播
[/b]
[b]
[/b]
[b]
CHANGE_NETWORK_STATE改变网络状态
[/b]
[b]
[/b]
[b]
CHANGE_WIFI_MULTICAST_STATE改变WiFi多播状态,应该是控制手机热点(猜测)
[/b]
[b]
[/b]
[b]
CHANGE_WIFI_STATE控制WiFi开关,改变WiFi状态
[/b]
[b]
[/b]
[b]
DISABLE_KEYGUARD改变键盘为不可用
[/b]
[b]
[/b]
[b]
EXPAND_STATUS_BAR扩展bar的状态
[/b]
[b]
[/b]
[b]
GET_PACKAGE_SIZE获取应用安装包大小
[/b]
[b]
[/b]
[b]
INTERNET网络权限
[/b]
[b]
[/b]
[b]
KILL_BACKGROUND_PROCESSES杀死后台进程
[/b]
[b]
[/b]
[b]
MODIFY_AUDIO_SETTINGS改变音频输出设置
[/b]
[b]
[/b]
[b]
NFC支付
[/b]
[b]
[/b]
[b]
READ_SYNC_SETTINGS获取手机设置信息
[/b]
[b]
[/b]
[b]
READ_SYNC_STATS数据统计
[/b]
[b]
[/b]
[b]
RECEIVE_BOOT_COMPLETED监听启动广播
[/b]
[b]
[/b]
[b]
REORDER_TASKS创建新栈
[/b]
[b]
[/b]
[b]
REQUEST_INSTALL_PACKAGES安装应用程序
[/b]
[b]
[/b]
[b]
SET_TIME_ZONE允许应用程序设置系统时间区域
[/b]
[b]
[/b]
[b]
SET_WALLPAPER设置壁纸
[/b]
[b]
[/b]
[b]
SET_WALLPAPER_HINTS设置壁纸上的提示信息,个性化语言
[/b]
[b]
[/b]
[b]
TRANSMIT_IR红外发射
[/b]
[b]
[/b]
[b]
USE_FINGERPRINT指纹识别
[/b]
[b]
[/b]
[b]
VIBRATE震动
[/b]
[b]
[/b]
[b]
WAKE_LOCK锁屏
[/b]
[b]
[/b]
[b]
WRITE_SYNC_SETTINGS改变设置
[/b]
[b]
[/b]
[b]
SET_ALARM设置警告提示
[/b]
[b]
[/b]
[b]
INSTALL_SHORTCUT创建快捷方式
[/b]
[b]
[/b]
[b]
UNINSTALL_SHORTCUT删除快捷方式
[/b]
[b]
[/b]
[b]
以上这些只是普通权限,我们开发的时候,正常使用就行了,需要的权限在清单文件配置即可。
[/b]

[b]申请步骤[/b]

[b]将targetSdkVersion设置为23,注意,如果你将targetSdkVersion设置为>=23,则必须按照Android谷歌的要求,动态的申请权限,如果你暂时不打算支持动态权限申请,则targetSdkVersion最大只能设置为22.[/b]

[b]2在AndroidManifest.xml中申请你需要的权限,包括普通权限和需要申请的特殊权限。[/b]

[b]3.开始申请权限,此处分为3部。[/b]

[b](1)检查是否由此权限checkSelfPermission(),如果已经开启,则直接做你想做的。[/b]

[b](2)如果未开启,则判断是否需要向用户解释为何申请权限shouldShowRequestPermissionRationale。[/b]

[b](3)如果需要(即返回true),则可以弹出对话框提示用户申请权限原因,用户确认后申请权限requestPermissions(),如果不需要(即返回false),则直接申请权限requestPermissions()。

[/b]

[b]单个权限申请.png[/b]

[b]
/**
[/b]
[b]
*Requestspermission.
[/b]
[b]
*
[/b]
[b]
*@paramactivity
[/b]
[b]
*@paramrequestCoderequestcode,e.g.ifyouneedrequestCAMERApermission,parametersisPermissionUtils.CODE_CAMERA
[/b]
[b]
*/
[/b]
[b]
publicstaticvoidrequestPermission(finalActivityactivity,finalintrequestCode,PermissionGrantpermissionGrant){
[/b]
[b]
if(activity==null){
[/b]
[b]
return;
[/b]
[b]
}
[/b]
[b]
[/b]
[b]
Log.i(TAG,"requestPermissionrequestCode:"+requestCode);
[/b]
[b]
if(requestCode<0||requestCode>=requestPermissions.length){
[/b]
[b]
Log.w(TAG,"requestPermissionillegalrequestCode:"+requestCode);
[/b]
[b]
return;
[/b]
[b]
}
[/b]
[b]
[/b]
[b]
finalStringrequestPermission=requestPermissions[requestCode];
[/b]
[b]
[/b]
[b]
//如果是6.0以下的手机,ActivityCompat.checkSelfPermission()会始终等于PERMISSION_GRANTED,
[/b]
[b]
//但是,如果用户关闭了你申请的权限(如下图,在安装的时候,将一些权限关闭了),ActivityCompat.checkSelfPermission()则可能会导致程序崩溃(java.lang.RuntimeException:Unknownexceptioncode:1msgnull),
[/b]
[b]
//你可以使用try{}catch(){},处理异常,也可以判断系统版本,低于23就不申请权限,直接做你想做的。permissionGrant.onPermissionGranted(requestCode);
[/b]
[b]
//if(Build.VERSION.SDK_INT<23){
[/b]
[b]
//permissionGrant.onPermissionGranted(requestCode);
[/b]
[b]
//return;
[/b]
[b]
//}
[/b]
[b]
[/b]
[b]
intcheckSelfPermission;
[/b]
[b]
try{
[/b]
[b]
checkSelfPermission=ActivityCompat.checkSelfPermission(activity,requestPermission);
[/b]
[b]
}catch(RuntimeExceptione){
[/b]
[b]
Toast.makeText(activity,"pleaseopenthispermission",Toast.LENGTH_SHORT)
[/b]
[b]
.show();
[/b]
[b]
Log.e(TAG,"RuntimeException:"+e.getMessage());
[/b]
[b]
return;
[/b]
[b]
}
[/b]
[b]
[/b]
[b]
if(checkSelfPermission!=PackageManager.PERMISSION_GRANTED){
[/b]
[b]
Log.i(TAG,"ActivityCompat.checkSelfPermission!=PackageManager.PERMISSION_GRANTED");
[/b]
[b]
[/b]
[b]
[/b]
[b]
if(ActivityCompat.shouldShowRequestPermissionRationale(activity,requestPermission)){
[/b]
[b]
Log.i(TAG,"requestPermissionshouldShowRequestPermissionRationale");
[/b]
[b]
shouldShowRationale(activity,requestCode,requestPermission);
[/b]
[b]
[/b]
[b]
}else{
[/b]
[b]
Log.d(TAG,"requestCameraPermissionelse");
[/b]
[b]
ActivityCompat.requestPermissions(activity,newString[]{requestPermission},requestCode);
[/b]
[b]
}
[/b]
[b]
[/b]
[b]
}else{
[/b]
[b]
Log.d(TAG,"ActivityCompat.checkSelfPermission====PackageManager.PERMISSION_GRANTED");
[/b]
[b]
Toast.makeText(activity,"opened:"+requestPermissions[requestCode],Toast.LENGTH_SHORT).show();
[/b]
[b]
//得到权限的时候,就可以在回调里面做你想做的事情了
[/b]
[b]
permissionGrant.onPermissionGranted(requestCode);
[/b]
[b]
}
[/b]
[b]
}
[/b]



[b]
[b]备注!!!
[/b][/b]
[b]
(1)checkSelfPermission:检查是否拥有这个权限
[/b]
[b]
(2)requestPermissions:请求权限,一般会弹出一个系统对话框,询问用户是否开启这个权限。
[/b]
[b]
(3)shouldShowRequestPermissionRationale:Android原生系统中,如果第二次弹出权限申请的对话框,会出现“以后不再弹出”的提示框,如果用户勾选了,你再申请权限,则shouldShowRequestPermissionRationale返回true,意思是说要给用户一个解释,告诉用户为什么要这个权限。然而,在实际开发中,需要注意的是,很多手机对原生系统做了修改,比如小米,小米4的6.0的shouldShowRequestPermissionRationale就一直返回false,而且在申请权限时,如果用户选择了拒绝,则不会再弹出对话框了。。。。所以说这个地方有坑,我的解决方法是,在回调里面处理,如果用户拒绝了这个权限,则打开本应用信息界面,由用户自己手动开启这个权限。
[/b]
[b]
(4)每个应用都有自己的权限管理界面,里面有本应用申请的权限以及各种状态,即使用户已经同意了你申请的权限,他也随时可以关闭
[/b]





[b][b]注意事项[/b][/b]

[b]API问题[/b]

[b]由于checkSelfPermission和requestPermissions从API23才加入,低于23版本,需要在运行时判断或者使用SupportLibraryv4中提供的方法[/b]

[b]ContextCompat.checkSelfPermission[/b]

[b]ActivityCompat.requestPermissions[/b]

[b]ActivityCompat.shouldShowRequestPermissionRationale[/b]

[b]多系统问题[/b]

[b]当我们支持了6.0必须也要支持4.4,5.0这些系统,所以需要在很多情况下,需要有两套处理。比如Camera权限[/b]

[b][b][java]copy?[/b][/b]

[b]if[/b]

[b]{[/b]





两个特殊权限

特殊权限,顾名思义,就是一些特别敏感的权限,在Android系统中,主要由两个

SYSTEM_ALERT_WINDOW,设置悬浮窗,进行一些黑科技

WRITE_SETTINGS修改系统设置

关于上面两个特殊权限的授权,做法是使用startActivityForResult启动授权界面来完成。

请求SYSTEM_ALERT_WINDOW

[java]copy?

privateREQUEST_CODE=;

privaterequestAlertWindowPermission(){

Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);

+getPackageName()));

@OverrideprotectedonActivityResult(requestCode,resultCode,Intentdata){

.onActivityResult(requestCode,resultCode,data);

(requestCode==REQUEST_CODE){

(Settings.canDrawOverlays()){

上述代码需要注意的是

使用ActionSettings.ACTION_MANAGE_OVERLAY_PERMISSION启动隐式Intent

使用"package:"+getPackageName()携带App的包名信息

使用Settings.canDrawOverlays方法判断授权结果

请求WRITE_SETTINGS

[java]copy?

privateREQUEST_CODE_WRITE_SETTINGS=;

privaterequestWriteSettings(){

Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);

+getPackageName()));

@OverrideprotectedonActivityResult(requestCode,resultCode,Intentdata){

.onActivityResult(requestCode,resultCode,data);

(requestCode==REQUEST_CODE_WRITE_SETTINGS){

(Settings.System.canWrite()){

上述代码需要注意的是

使用ActionSettings.ACTION_MANAGE_WRITE_SETTINGS启动隐式Intent

使用"package:"+getPackageName()携带App的包名信息

使用Settings.System.canWrite方法检测授权结果

注意:关于这两个特殊权限,一般不建议应用申请。

关于本demo的所有代码:
整个申请权限工具类代码

packagecom.example.android.system.runtimepermissions;


importandroid.Manifest;

importandroid.app.Activity;

importandroid.content.DialogInterface;

importandroid.content.Intent;

importandroid.content.pm.PackageManager;

importandroid.net.Uri;

importandroid.provider.Settings;

importandroid.support.annotation.NonNull;

importandroid.support.v4.app.ActivityCompat;

importandroid.support.v7.app.AlertDialog;

importandroid.util.Log;

importandroid.widget.Toast;


importjava.util.ArrayList;

importjava.util.HashMap;

importjava.util.List;

importjava.util.Map;


/**

*Createdbyqianxiaoaion2016/7/7.

*/

publicclassPermissionUtils{


privatestaticfinalStringTAG=PermissionUtils.class.getSimpleName();

publicstaticfinalintCODE_RECORD_AUDIO=0;

publicstaticfinalintCODE_GET_ACCOUNTS=1;

publicstaticfinalintCODE_READ_PHONE_STATE=2;

publicstaticfinalintCODE_CALL_PHONE=3;

publicstaticfinalintCODE_CAMERA=4;

publicstaticfinalintCODE_ACCESS_FINE_LOCATION=5;

publicstaticfinalintCODE_ACCESS_COARSE_LOCATION=6;

publicstaticfinalintCODE_READ_EXTERNAL_STORAGE=7;

publicstaticfinalintCODE_WRITE_EXTERNAL_STORAGE=8;

publicstaticfinalintCODE_MULTI_PERMISSION=100;


publicstaticfinalStringPERMISSION_RECORD_AUDIO=Manifest.permission.RECORD_AUDIO;

publicstaticfinalStringPERMISSION_GET_ACCOUNTS=Manifest.permission.GET_ACCOUNTS;

publicstaticfinalStringPERMISSION_READ_PHONE_STATE=Manifest.permission.READ_PHONE_STATE;

publicstaticfinalStringPERMISSION_CALL_PHONE=Manifest.permission.CALL_PHONE;

publicstaticfinalStringPERMISSION_CAMERA=Manifest.permission.CAMERA;

publicstaticfinalStringPERMISSION_ACCESS_FINE_LOCATION=Manifest.permission.ACCESS_FINE_LOCATION;

publicstaticfinalStringPERMISSION_ACCESS_COARSE_LOCATION=Manifest.permission.ACCESS_COARSE_LOCATION;

publicstaticfinalStringPERMISSION_READ_EXTERNAL_STORAGE=Manifest.permission.READ_EXTERNAL_STORAGE;

publicstaticfinalStringPERMISSION_WRITE_EXTERNAL_STORAGE=Manifest.permission.WRITE_EXTERNAL_STORAGE;


privatestaticfinalString[]requestPermissions={

PERMISSION_RECORD_AUDIO,

PERMISSION_GET_ACCOUNTS,

PERMISSION_READ_PHONE_STATE,

PERMISSION_CALL_PHONE,

PERMISSION_CAMERA,

PERMISSION_ACCESS_FINE_LOCATION,

PERMISSION_ACCESS_COARSE_LOCATION,

PERMISSION_READ_EXTERNAL_STORAGE,

PERMISSION_WRITE_EXTERNAL_STORAGE

};


interfacePermissionGrant{

voidonPermissionGranted(intrequestCode);

}


/**

*Requestspermission.

*

*@paramactivity

*@paramrequestCoderequestcode,e.g.ifyouneedrequestCAMERApermission,parametersisPermissionUtils.CODE_CAMERA

*/

publicstaticvoidrequestPermission(finalActivityactivity,finalintrequestCode,PermissionGrantpermissionGrant){

if(activity==null){

return;

}


Log.i(TAG,"requestPermissionrequestCode:"+requestCode);

if(requestCode<0||requestCode>=requestPermissions.length){

Log.w(TAG,"requestPermissionillegalrequestCode:"+requestCode);

return;

}


finalStringrequestPermission=requestPermissions[requestCode];


//如果是6.0以下的手机,ActivityCompat.checkSelfPermission()会始终等于PERMISSION_GRANTED,

//但是,如果用户关闭了你申请的权限,ActivityCompat.checkSelfPermission(),会导致程序崩溃(java.lang.RuntimeException:Unknownexceptioncode:1msgnull),

//你可以使用try{}catch(){},处理异常,也可以在这个地方,低于23就什么都不做,

//个人建议try{}catch(){}单独处理,提示用户开启权限。

//if(Build.VERSION.SDK_INT<23){

//return;

//}


intcheckSelfPermission;

try{

checkSelfPermission=ActivityCompat.checkSelfPermission(activity,requestPermission);

}catch(RuntimeExceptione){

Toast.makeText(activity,"pleaseopenthispermission",Toast.LENGTH_SHORT)

.show();

Log.e(TAG,"RuntimeException:"+e.getMessage());

return;

}


if(checkSelfPermission!=PackageManager.PERMISSION_GRANTED){

Log.i(TAG,"ActivityCompat.checkSelfPermission!=PackageManager.PERMISSION_GRANTED");



if(ActivityCompat.shouldShowRequestPermissionRationale(activity,requestPermission)){

Log.i(TAG,"requestPermissionshouldShowRequestPermissionRationale");

shouldShowRationale(activity,requestCode,requestPermission);


}else{

Log.d(TAG,"requestCameraPermissionelse");

ActivityCompat.requestPermissions(activity,newString[]{requestPermission},requestCode);

}


}else{

Log.d(TAG,"ActivityCompat.checkSelfPermission====PackageManager.PERMISSION_GRANTED");

Toast.makeText(activity,"opened:"+requestPermissions[requestCode],Toast.LENGTH_SHORT).show();

permissionGrant.onPermissionGranted(requestCode);

}

}


privatestaticvoidrequestMultiResult(Activityactivity,String[]permissions,int[]grantResults,PermissionGrantpermissionGrant){


if(activity==null){

return;

}


//TODO

Log.d(TAG,"onRequestPermissionsResultpermissionslength:"+permissions.length);

Map<String,Integer>perms=newHashMap<>();


ArrayList<String>notGranted=newArrayList<>();

for(inti=0;i<permissions.length;i++){

Log.d(TAG,"permissions:[i]:"+i+",permissions[i]"+permissions[i]+",grantResults[i]:"+grantResults[i]);

perms.put(permissions[i],grantResults[i]);

if(grantResults[i]!=PackageManager.PERMISSION_GRANTED){

notGranted.add(permissions[i]);

}

}


if(notGranted.size()==0){

Toast.makeText(activity,"allpermissionsuccess"+notGranted,Toast.LENGTH_SHORT)

.show();

permissionGrant.onPermissionGranted(CODE_MULTI_PERMISSION);

}else{

openSettingActivity(activity,"thosepermissionneedgranted!");

}


}



/**

*一次申请多个权限

*/

publicstaticvoidrequestMultiPermissions(finalActivityactivity,PermissionGrantgrant){


finalList<String>permissionsList=getNoGrantedPermission(activity,false);

finalList<String>shouldRationalePermissionsList=getNoGrantedPermission(activity,true);


//TODOcheckSelfPermission

if(permissionsList==null||shouldRationalePermissionsList==null){

return;

}

Log.d(TAG,"requestMultiPermissionspermissionsList:"+permissionsList.size()+",shouldRationalePermissionsList:"+shouldRationalePermissionsList.size());


if(permissionsList.size()>0){

ActivityCompat.requestPermissions(activity,permissionsList.toArray(newString[permissionsList.size()]),

CODE_MULTI_PERMISSION);

Log.d(TAG,"showMessageOKCancelrequestPermissions");


}elseif(shouldRationalePermissionsList.size()>0){

showMessageOKCancel(activity,"shouldopenthosepermission",

newDialogInterface.OnClickListener(){

@Override

publicvoidonClick(DialogInterfacedialog,intwhich){

ActivityCompat.requestPermissions(activity,shouldRationalePermissionsList.toArray(newString[shouldRationalePermissionsList.size()]),

CODE_MULTI_PERMISSION);

Log.d(TAG,"showMessageOKCancelrequestPermissions");

}

});

}else{

grant.onPermissionGranted(CODE_MULTI_PERMISSION);

}


}



privatestaticvoidshouldShowRationale(finalActivityactivity,finalintrequestCode,finalStringrequestPermission){

//TODO

String[]permissionsHint=activity.getResources().getStringArray(R.array.permissions);

showMessageOKCancel(activity,"Rationale:"+permissionsHint[requestCode],newDialogInterface.OnClickListener(){

@Override

publicvoidonClick(DialogInterfacedialog,intwhich){

ActivityCompat.requestPermissions(activity,

newString[]{requestPermission},

requestCode);

Log.d(TAG,"showMessageOKCancelrequestPermissions:"+requestPermission);

}

});

}


privatestaticvoidshowMessageOKCancel(finalActivitycontext,Stringmessage,DialogInterface.OnClickListenerokListener){

newAlertDialog.Builder(context)

.setMessage(message)

.setPositiveButton("OK",okListener)

.setNegativeButton("Cancel",null)

.create()

.show();


}


/**

*@paramactivity

*@paramrequestCodeNeedconsistentwithrequestPermission

*@parampermissions

*@paramgrantResults

*/

publicstaticvoidrequestPermissionsResult(finalActivityactivity,finalintrequestCode,@NonNullString[]permissions,

@NonNullint[]grantResults,PermissionGrantpermissionGrant){


if(activity==null){

return;

}

Log.d(TAG,"requestPermissionsResultrequestCode:"+requestCode);


if(requestCode==CODE_MULTI_PERMISSION){

requestMultiResult(activity,permissions,grantResults,permissionGrant);

return;

}


if(requestCode<0||requestCode>=requestPermissions.length){

Log.w(TAG,"requestPermissionsResultillegalrequestCode:"+requestCode);

Toast.makeText(activity,"illegalrequestCode:"+requestCode,Toast.LENGTH_SHORT).show();

return;

}


Log.i(TAG,"onRequestPermissionsResultrequestCode:"+requestCode+",permissions:"+permissions.toString()

+",grantResults:"+grantResults.toString()+",length:"+grantResults.length);


if(grantResults.length==1&&grantResults[0]==PackageManager.PERMISSION_GRANTED){

Log.i(TAG,"onRequestPermissionsResultPERMISSION_GRANTED");

//TODOsuccess,dosomething,canusecallback

permissionGrant.onPermissionGranted(requestCode);


}else{

//TODOhintuserthispermissionfunction

Log.i(TAG,"onRequestPermissionsResultPERMISSIONNOTGRANTED");

//TODO

String[]permissionsHint=activity.getResources().getStringArray(R.array.permissions);

openSettingActivity(activity,"Result"+permissionsHint[requestCode]);

}


}


privatestaticvoidopenSettingActivity(finalActivityactivity,Stringmessage){


showMessageOKCancel(activity,message,newDialogInterface.OnClickListener(){

@Override

publicvoidonClick(DialogInterfacedialog,intwhich){

Intentintent=newIntent();

intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);

Log.d(TAG,"getPackageName():"+activity.getPackageName());

Uriuri=Uri.fromParts("package",activity.getPackageName(),null);

intent.setData(uri);

activity.startActivity(intent);

}

});

}



/**

*@paramactivity

*@paramisShouldRationaletrue:returnnograntedandshouldShowRequestPermissionRationalepermissions,false:returnnograntedand!shouldShowRequestPermissionRationale

*@return

*/

publicstaticArrayList<String>getNoGrantedPermission(Activityactivity,booleanisShouldRationale){


ArrayList<String>permissions=newArrayList<>();


for(inti=0;i<requestPermissions.length;i++){

StringrequestPermission=requestPermissions[i];



//TODOcheckSelfPermission

intcheckSelfPermission=-1;

try{

checkSelfPermission=ActivityCompat.checkSelfPermission(activity,requestPermission);

}catch(RuntimeExceptione){

Toast.makeText(activity,"pleaseopenthosepermission",Toast.LENGTH_SHORT)

.show();

Log.e(TAG,"RuntimeException:"+e.getMessage());

returnnull;

}


if(checkSelfPermission!=PackageManager.PERMISSION_GRANTED){

Log.i(TAG,"getNoGrantedPermissionActivityCompat.checkSelfPermission!=PackageManager.PERMISSION_GRANTED:"+requestPermission);


if(ActivityCompat.shouldShowRequestPermissionRationale(activity,requestPermission)){

Log.d(TAG,"shouldShowRequestPermissionRationaleif");

if(isShouldRationale){

permissions.add(requestPermission);

}


}else{


if(!isShouldRationale){

permissions.add(requestPermission);

}

Log.d(TAG,"shouldShowRequestPermissionRationaleelse");

}


}

}


returnpermissions;

}


}


界面调用代码

packagecom.example.android.system.runtimepermissions;


importandroid.os.Bundle;

importandroid.support.annotation.NonNull;

importandroid.support.v4.app.ActivityCompat;

importandroid.support.v4.app.FragmentActivity;

importandroid.support.v4.app.FragmentTransaction;

importandroid.view.View;

importandroid.widget.Toast;


importcom.example.android.common.logger.Log;


/**

*Createdbyqianxiaoaion2016/7/8.

*/

publicclassPermissionActivityextendsFragmentActivityimplementsActivityCompat.OnRequestPermissionsResultCallback{

privatestaticfinalStringTAG=PermissionActivity.class.getSimpleName();


@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_permission);

FragmentTransactiontransaction=getSupportFragmentManager().beginTransaction();

PermissionsFragmentfragment=newPermissionsFragment();

transaction.replace(R.id.content_fragment,fragment);

transaction.commit();


}


/**

*Calledwhenthe'showcamera'buttonisclicked.

*Callbackisdefinedinresourcelayoutdefinition.

*/

publicvoidshowCamera(Viewview){

Log.i(TAG,"Showcamerabuttonpressed.Checkingpermission.");

PermissionUtils.requestPermission(this,PermissionUtils.CODE_CAMERA,mPermissionGrant);

}


publicvoidgetAccounts(Viewview){

PermissionUtils.requestPermission(this,PermissionUtils.CODE_GET_ACCOUNTS,mPermissionGrant);

}


publicvoidcallPhone(Viewview){

PermissionUtils.requestPermission(this,PermissionUtils.CODE_CALL_PHONE,mPermissionGrant);

}


publicvoidreadPhoneState(Viewview){

PermissionUtils.requestPermission(this,PermissionUtils.CODE_READ_PHONE_STATE,mPermissionGrant);

}


publicvoidaccessFineLocation(Viewview){

PermissionUtils.requestPermission(this,PermissionUtils.CODE_ACCESS_FINE_LOCATION,mPermissionGrant);

}


publicvoidaccessCoarseLocation(Viewview){

PermissionUtils.requestPermission(this,PermissionUtils.CODE_ACCESS_COARSE_LOCATION,mPermissionGrant);

}


publicvoidreadExternalStorage(Viewview){

PermissionUtils.requestPermission(this,PermissionUtils.CODE_READ_EXTERNAL_STORAGE,mPermissionGrant);

}


publicvoidwriteExternalStorage(Viewview){

PermissionUtils.requestPermission(this,PermissionUtils.CODE_WRITE_EXTERNAL_STORAGE,mPermissionGrant);

}


publicvoidrecordAudio(Viewview){

PermissionUtils.requestPermission(this,PermissionUtils.CODE_RECORD_AUDIO,mPermissionGrant);

}



privatePermissionUtils.PermissionGrantmPermissionGrant=newPermissionUtils.PermissionGrant(){

@Override

publicvoidonPermissionGranted(intrequestCode){

switch(requestCode){

casePermissionUtils.CODE_RECORD_AUDIO:

Toast.makeText(PermissionActivity.this,"ResultPermissionGrantCODE_RECORD_AUDIO",Toast.LENGTH_SHORT).show();

break;

casePermissionUtils.CODE_GET_ACCOUNTS:

Toast.makeText(PermissionActivity.this,"ResultPermissionGrantCODE_GET_ACCOUNTS",Toast.LENGTH_SHORT).show();

break;

casePermissionUtils.CODE_READ_PHONE_STATE:

Toast.makeText(PermissionActivity.this,"ResultPermissionGrantCODE_READ_PHONE_STATE",Toast.LENGTH_SHORT).show();

break;

casePermissionUtils.CODE_CALL_PHONE:

Toast.makeText(PermissionActivity.this,"ResultPermissionGrantCODE_CALL_PHONE",Toast.LENGTH_SHORT).show();

break;

casePermissionUtils.CODE_CAMERA:

Toast.makeText(PermissionActivity.this,"ResultPermissionGrantCODE_CAMERA",Toast.LENGTH_SHORT).show();

break;

casePermissionUtils.CODE_ACCESS_FINE_LOCATION:

Toast.makeText(PermissionActivity.this,"ResultPermissionGrantCODE_ACCESS_FINE_LOCATION",Toast.LENGTH_SHORT).show();

break;

casePermissionUtils.CODE_ACCESS_COARSE_LOCATION:

Toast.makeText(PermissionActivity.this,"ResultPermissionGrantCODE_ACCESS_COARSE_LOCATION",Toast.LENGTH_SHORT).show();

break;

casePermissionUtils.CODE_READ_EXTERNAL_STORAGE:

Toast.makeText(PermissionActivity.this,"ResultPermissionGrantCODE_READ_EXTERNAL_STORAGE",Toast.LENGTH_SHORT).show();

break;

casePermissionUtils.CODE_WRITE_EXTERNAL_STORAGE:

Toast.makeText(PermissionActivity.this,"ResultPermissionGrantCODE_WRITE_EXTERNAL_STORAGE",Toast.LENGTH_SHORT).show();

break;

default:

break;

}

}

};


/**

*Callbackreceivedwhenapermissionsrequesthasbeencompleted.

*/

@Override

publicvoidonRequestPermissionsResult(finalintrequestCode,@NonNullString[]permissions,

@NonNullint[]grantResults){

PermissionUtils.requestPermissionsResult(this,requestCode,permissions,grantResults,mPermissionGrant);

}

}


xml布局

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:paddingLeft="@dimen/horizontal_page_margin"

android:paddingRight="@dimen/horizontal_page_margin"

android:paddingTop="@dimen/vertical_page_margin"

android:paddingBottom="@dimen/vertical_page_margin"

android:orientation="vertical"

>


<FrameLayout

android:id="@+id/content_fragment"

android:layout_width="match_parent"

android:layout_height="0dp"

android:layout_weight="1"/>


<ScrollView

android:layout_width="match_parent"

android:layout_height="0dp"

android:layout_weight="1">


<LinearLayout

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical">


<LinearLayout

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="horizontal">


<Button

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Camera"

android:id="@+id/button_camera"

android:onClick="showCamera"/>


<Button

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="RECORD_AUDIO"

android:onClick="recordAudio"/>

</LinearLayout>


<LinearLayout

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="horizontal">


<Button

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="GET_ACCOUNTS"

android:onClick="getAccounts"/>


<Button

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="CALL_PHONE"

android:onClick="callPhone"/>

</LinearLayout>


<Button

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="PERMISSION_READ_PHONE_STATE"

android:onClick="readPhoneState"/>


<Button

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="ACCESS_FINE_LOCATION"

android:onClick="accessFineLocation"/>


<Button

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="ACCESS_COARSE_LOCATION"

android:onClick="accessCoarseLocation"/>


<Button

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="READ_EXTERNAL_STORAGE"

android:onClick="readExternalStorage"/>


<Button

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="WRITE_EXTERNAL_STORAGE"

android:onClick="writeExternalStorage"/>


</LinearLayout>

</ScrollView>


</LinearLayout>


清单文件申请的权限

<uses-permissionandroid:name="android.permission.CAMERA"/>

<uses-permissionandroid:name="android.permission.ACCESS_FINE_LOCATION"/>

<uses-permissionandroid:name="android.permission.ACCESS_COARSE_LOCATION"/>

<uses-permissionandroid:name="android.permission.CALL_PHONE"/>

<uses-permissionandroid:name="android.permission.SEND_SMS"/>

<uses-permissionandroid:name="android.permission.READ_SMS"/>


<uses-permissionandroid:name="android.permission.GET_ACCOUNTS"/>

<uses-permissionandroid:name="android.permission.READ_PHONE_STATE"/>

<uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"/>

<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<uses-permissionandroid:name="android.permission.RECORD_AUDIO"/>


部分资源文件

<?xmlversion="1.0"encoding="utf-8"?>

<resources>

<string-arrayname="permissions">

<item>@string/permission_recode_audio_hint</item>

<item>@string/permission_get_accounts_hint</item>

<item>@string/permission_read_phone_hint</item>

<item>@string/permission_call_phone_hint</item>

<item>@string/permission_camera_hint</item>

<item>@string/permission_access_fine_location_hint</item>

<item>@string/permission_access_coarse_location_hint</item>

<item>@string/permission_read_external_hint</item>

<item>@string/permission_white_external_hint</item>

</string-array>

</resources>


<stringname="permission_get_accounts_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_GET_ACCOUNTS</string>

<stringname="permission_read_phone_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_READ_PHONE_STATE</string>

<stringname="permission_call_phone_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_CALL_PHONE</string>

<stringname="permission_camera_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_CAMERA</string>

<stringname="permission_access_fine_location_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_ACCESS_FINE_LOCATION</string>

<stringname="permission_access_coarse_location_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_ACCESS_COARSE_LOCATION</string>

<stringname="permission_read_external_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_READ_EXTERNAL_STORAGE</string>

<stringname="permission_white_external_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_WRITE_EXTERNAL_STORAGE</string>

<stringname="permission_recode_audio_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_RE


关于自定义权限申请弹框
避免用户不再申请的问题

Android6.0版本(Api
23)推出了很多新的特性,大幅提升了用户体验,同时也为程序员带来新的负担.动态权限管理就是这样,一方面让用户更加容易的控制自己的隐私,一方面需要重新适配应用权限.时代总是不断发展,程序总是以人为本,让我们为应用添加动态权限管理吧!这里提供了一个非常不错的解决方案,提供源码,项目可以直接使用.



Android系统包含默认的授权提示框,
但是我们仍需要设置自己的页面.原因是系统提供的授权框,会有不再提示的选项.如果用户选择,则无法触发授权提示.使用自定义的提示页面,可以给予用户手动修改授权的指导.

本文示例GitHub下载地址.

在Api
23中,权限需要动态获取,核心权限必须满足.标准流程:



如果用户点击,不再提示,
则系统授权弹窗将不会弹出.流程变为:



流程就这些,
让我们看看代码吧.

1.
权限

在AndroidManifest中,添加两个权限,录音和修改音量.

<!--危险权限--><uses-permissionandroid:name="android.permission.RECORD_AUDIO"/><!--一般权限--><uses-permissionandroid:name="android.permission.MODIFY_AUDIO_SETTINGS"/>



危险权限必须要授权,一般权限不需要.


检测权限类

/**

*检查权限的工具类

*<p/>

*Createdbywangchenlongon16/1/26.

*/publicclassPermissionsChecker{privatefinalContextmContext;


publicPermissionsChecker(Contextcontext){

mContext=context.getApplicationContext();

}


//判断权限集合publicbooleanlacksPermissions(String...permissions){

for(Stringpermission:permissions){

if(lacksPermission(permission)){

returntrue;

}

}

returnfalse;

}


//判断是否缺少权限privatebooleanlacksPermission(Stringpermission){

returnContextCompat.checkSelfPermission(mContext,permission)==

PackageManager.PERMISSION_DENIED;

}

}


2.首页

假设首页需要使用权限,在页面显示前,即onResume时,检测权限,
如果缺少,则进入权限获取页面;接收返回值,拒绝权限时,直接关闭.

publicclassMainActivityextendsAppCompatActivity{privatestaticfinalintREQUEST_CODE=0;//请求码//所需的全部权限staticfinalString[]PERMISSIONS=newString[]{

Manifest.permission.RECORD_AUDIO,

Manifest.permission.MODIFY_AUDIO_SETTINGS

};


@Bind(R.id.main_t_toolbar)ToolbarmTToolbar;


privatePermissionsCheckermPermissionsChecker;//权限检测器@OverrideprotectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

ButterKnife.bind(this);


setSupportActionBar(mTToolbar);


mPermissionsChecker=newPermissionsChecker(this);

}


@OverrideprotectedvoidonResume(){

super.onResume();


//缺少权限时,进入权限配置页面if(mPermissionsChecker.lacksPermissions(PERMISSIONS)){

startPermissionsActivity();

}

}


privatevoidstartPermissionsActivity(){

PermissionsActivity.startActivityForResult(this,REQUEST_CODE,PERMISSIONS);

}


@OverrideprotectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){

super.onActivityResult(requestCode,resultCode,data);

//拒绝时,关闭页面,缺少主要权限,无法运行if(requestCode==REQUEST_CODE&&resultCode==PermissionsActivity.PERMISSIONS_DENIED){

finish();

}

}

}



核心权限必须满足,
如摄像应用,摄像头权限就是必须的,如果用户不予授权,则直接关闭.



3.
授权页

授权页,首先使用系统默认的授权页,当用户拒绝时,指导用户手动设置,当用户再次操作失败后,返回继续提示.用户手动退出授权页时,给使用页发送授权失败的通知.


注意isRequireCheck参数的使用,
防止和系统提示框重叠.
系统授权提示:ActivityCompat.requestPermissions,ActivityCompat兼容低版本.


效果



关键部分就这些了,
动态权限授权虽然给程序员带来了一些麻烦,但是对用户还是很有必要的,我们也应该欢迎,毕竟每个程序员都是半个产品经理.

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: