Ema*_*lin 288 android android-permissions android-6.0-marshmallow
根据这个:http://developer.android.com/preview/features/runtime-permissions.html#coding应用程序可以检查运行时权限和请求权限(如果尚未授予它).然后将显示以下对话框:

如果用户拒绝重要权限,则应用程序应显示解释为何需要权限以及拒绝具有何种影响的解释.该对话框有两个选项:
Never ask again但是,如果用户检查,则不应显示带有解释的第二个对话框,尤其是如果用户之前已经拒绝过一次.现在的问题是:我的应用程序如何知道用户是否已检查过Never ask again?IMO onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)并没有给我这些信息.
第二个问题是:Google是否计划在权限对话框中添加自定义消息,以解释应用程序需要权限的原因?那样就永远不会有第二个对话框,肯定会有更好的ux.
Ema*_*lin 325
开发人员预览版2对应用程序请求权限的方式进行了一些更改(另请参阅http://developer.android.com/preview/support.html#preview2-notes).
第一个对话框现在看起来像这样:
没有"Never again again"复选框(与开发者预览1不同).如果用户拒绝该权限,并且该权限对于该应用程序至关重要,则可以提供另一个对话框来解释该应用程序要求该权限的原因,例如:
如果用户再次拒绝该应用程序应该关闭,如果它绝对需要该权限或继续运行有限的功能.如果用户重新考虑(并选择重试),则再次请求权限.这次提示符如下所示:
第二次显示"永不再询问"复选框.如果用户再次拒绝并且勾选了复选框,则不会再发生任何事情.是否勾选了复选框可以使用Activity.shouldShowRequestPermissionRationale(String)来确定,例如:
if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {...
Run Code Online (Sandbox Code Playgroud)
这就是Android文档所说的内容(https://developer.android.com/training/permissions/requesting.html):
为了帮助您找到需要提供额外说明的情况,系统提供了Activity.shouldShowRequestPermissionRationale(String)方法.如果应用先前已请求此权限且用户拒绝该请求,则此方法返回true.这表明您应该向用户解释为什么需要该权限.
如果用户过去拒绝了权限请求并在权限请求系统对话框中选择了"不再询问"选项,则此方法返回false.如果设备策略禁止应用程序具有该权限,则该方法也返回false.
要知道用户是否拒绝"永不再询问",您可以在用户未授予权限时再次检查onRequestPermissionsResult中的shouldShowRequestPermissionRationale方法.
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == REQUEST_PERMISSION) {
// for each permission check if the user granted/denied them
// you may want to group the rationale in a single dialog,
// this is just an example
for (int i = 0, len = permissions.length; i < len; i++) {
String permission = permissions[i];
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
// user rejected the permission
boolean showRationale = shouldShowRequestPermissionRationale( permission );
if (! showRationale) {
// user also CHECKED "never ask again"
// you can either enable some fall back,
// disable features of your app
// or open another dialog explaining
// again the permission and directing to
// the app setting
} else if (Manifest.permission.WRITE_CONTACTS.equals(permission)) {
showRationale(permission, R.string.permission_denied_contacts);
// user did NOT check "never ask again"
// this is a good place to explain the user
// why you need the permission and ask if he wants
// to accept it (the rationale)
} else if ( /* possibly check more permissions...*/ ) {
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以使用以下代码打开您的应用设置:
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, REQUEST_PERMISSION_SETTING);
Run Code Online (Sandbox Code Playgroud)
无法将用户直接发送到"授权"页面.
Abh*_*han 90
您可以检查shouldShowRequestPermissionRationale()你的onRequestPermissionsResult().
https://youtu.be/C8lUdPVSzDk?t=2m23s
检查是否授予了权限onRequestPermissionsResult().如果没有,那么检查shouldShowRequestPermissionRationale().
true则显示为何需要此特定权限的说明.然后再次根据用户的选择requestPermissions().false则显示一条错误消息,表明未授予权限,app无法继续进行或禁用某项特定功能.以下是示例代码.
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case STORAGE_PERMISSION_REQUEST:
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted :)
downloadFile();
} else {
// permission was not granted
if (getActivity() == null) {
return;
}
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
showStoragePermissionRationale();
} else {
Snackbar snackbar = Snackbar.make(getView(), getResources().getString(R.string.message_no_storage_permission_snackbar), Snackbar.LENGTH_LONG);
snackbar.setAction(getResources().getString(R.string.settings), new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getActivity() == null) {
return;
}
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getActivity().getPackageName(), null);
intent.setData(uri);
OrderDetailFragment.this.startActivity(intent);
}
});
snackbar.show();
}
}
break;
}
}
Run Code Online (Sandbox Code Playgroud)
显然,谷歌地图正是这样做的位置许可.
pat*_*ckf 37
这是检查当前权限状态的一种简单方法:
@Retention(RetentionPolicy.SOURCE)
@IntDef({GRANTED, DENIED, BLOCKED_OR_NEVER_ASKED })
public @interface PermissionStatus {}
public static final int GRANTED = 0;
public static final int DENIED = 1;
public static final int BLOCKED_OR_NEVER_ASKED = 2;
@PermissionStatus
public static int getPermissionStatus(Activity activity, String androidPermissionName) {
if(ContextCompat.checkSelfPermission(activity, androidPermissionName) != PackageManager.PERMISSION_GRANTED) {
if(!ActivityCompat.shouldShowRequestPermissionRationale(activity, androidPermissionName)){
return BLOCKED_OR_NEVER_ASKED;
}
return DENIED;
}
return GRANTED;
}
Run Code Online (Sandbox Code Playgroud)
警告:在用户通过用户提示接受/拒绝权限之前(在sdk 23+设备上),在第一个应用程序启动之前返回BLOCKED_OR_NEVER_ASKED
更新:
Android支持库现在似乎也有一个非常相似的类android.support.v4.content.PermissionChecker,其中包含一个checkSelfPermission()返回:
public static final int PERMISSION_GRANTED = 0;
public static final int PERMISSION_DENIED = -1;
public static final int PERMISSION_DENIED_APP_OP = -2;
Run Code Online (Sandbox Code Playgroud)
Nab*_*ari 25
您可以通过检查是否要在回调方法中显示权限基本原理来确定它onRequestPermissionsResult().如果您发现任何权限设置为永不再询问,您可以请求用户从设置中授予权限.
我的完整实现如下.它适用于单个或多个权限请求.使用以下或直接使用我的库.
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if(permissions.length == 0){
return;
}
boolean allPermissionsGranted = true;
if(grantResults.length>0){
for(int grantResult: grantResults){
if(grantResult != PackageManager.PERMISSION_GRANTED){
allPermissionsGranted = false;
break;
}
}
}
if(!allPermissionsGranted){
boolean somePermissionsForeverDenied = false;
for(String permission: permissions){
if(ActivityCompat.shouldShowRequestPermissionRationale(this, permission)){
//denied
Log.e("denied", permission);
}else{
if(ActivityCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED){
//allowed
Log.e("allowed", permission);
} else{
//set to never ask again
Log.e("set to never ask again", permission);
somePermissionsForeverDenied = true;
}
}
}
if(somePermissionsForeverDenied){
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setTitle("Permissions Required")
.setMessage("You have forcefully denied some of the required permissions " +
"for this action. Please open settings, go to permissions and allow them.")
.setPositiveButton("Settings", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", getPackageName(), null));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setCancelable(false)
.create()
.show();
}
} else {
switch (requestCode) {
//act according to the request code used while requesting the permission(s).
}
}
}
Run Code Online (Sandbox Code Playgroud)
רות*_*כטר 24
一旦用户标记为"不再询问",则无法再次显示该问题.但是可以向用户解释他之前拒绝了许可,并且必须在设置中授予权限.并使用以下代码引用他的设置:
@Override
public void onRequestPermissionsResult(int permsRequestCode, String[] permissions, int[] grantResults) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// now, you have permission go ahead
// TODO: something
} else {
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
Manifest.permission.READ_CALL_LOG)) {
// now, user has denied permission (but not permanently!)
} else {
// now, user has denied permission permanently!
Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), "You have previously declined this permission.\n" +
"You must approve this permission in \"Permissions\" in the app settings on your device.", Snackbar.LENGTH_LONG).setAction("Settings", new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + BuildConfig.APPLICATION_ID)));
}
});
View snackbarView = snackbar.getView();
TextView textView = (TextView) snackbarView.findViewById(android.support.design.R.id.snackbar_text);
textView.setMaxLines(5); //Or as much as you need
snackbar.show();
}
}
return;
}
Run Code Online (Sandbox Code Playgroud)
mVc*_*Vck 13
如果您想要检测所有"状态"(第一次被拒绝,被拒绝,被拒绝"永不再问"或被永久拒绝),您可以执行以下操作:
创建2个布尔值
private boolean beforeClickPermissionRat;
private boolean afterClickPermissionRat;
Run Code Online (Sandbox Code Playgroud)
在请求许可之前设置第一个:
beforeClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);
Run Code Online (Sandbox Code Playgroud)
在onRequestPermissionsResult方法中设置第二个:
afterClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);
Run Code Online (Sandbox Code Playgroud)
使用以下"表"在onRequestPermissionsResult()中执行您需要的任何操作(在检查您仍然没有权限之后):
// before after
// FALSE FALSE = Was denied permanently, still denied permanently --> App Settings
// FALSE TRUE = First time deny, not denied permanently yet --> Nothing
// TRUE FALSE = Just been permanently denied --> Changing my caption to "Go to app settings to edit permissions"
// TRUE TRUE = Wasn't denied permanently, still not denied permanently --> Nothing
Run Code Online (Sandbox Code Playgroud)
我有同样的问题,我想出来了.为了简化生活,我编写了一个util类来处理运行时权限.
public class PermissionUtil {
/*
* Check if version is marshmallow and above.
* Used in deciding to ask runtime permission
* */
public static boolean shouldAskPermission() {
return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M);
}
private static boolean shouldAskPermission(Context context, String permission){
if (shouldAskPermission()) {
int permissionResult = ActivityCompat.checkSelfPermission(context, permission);
if (permissionResult != PackageManager.PERMISSION_GRANTED) {
return true;
}
}
return false;
}
public static void checkPermission(Context context, String permission, PermissionAskListener listener){
/*
* If permission is not granted
* */
if (shouldAskPermission(context, permission)){
/*
* If permission denied previously
* */
if (((Activity)context).shouldShowRequestPermissionRationale(permission)) {
listener.onPermissionPreviouslyDenied();
} else {
/*
* Permission denied or first time requested
* */
if (PreferencesUtil.isFirstTimeAskingPermission(context, permission)) {
PreferencesUtil.firstTimeAskingPermission(context, permission, false);
listener.onPermissionAsk();
} else {
/*
* Handle the feature without permission or ask user to manually allow permission
* */
listener.onPermissionDisabled();
}
}
} else {
listener.onPermissionGranted();
}
}
/*
* Callback on various cases on checking permission
*
* 1. Below M, runtime permission not needed. In that case onPermissionGranted() would be called.
* If permission is already granted, onPermissionGranted() would be called.
*
* 2. Above M, if the permission is being asked first time onPermissionAsk() would be called.
*
* 3. Above M, if the permission is previously asked but not granted, onPermissionPreviouslyDenied()
* would be called.
*
* 4. Above M, if the permission is disabled by device policy or the user checked "Never ask again"
* check box on previous request permission, onPermissionDisabled() would be called.
* */
public interface PermissionAskListener {
/*
* Callback to ask permission
* */
void onPermissionAsk();
/*
* Callback on permission denied
* */
void onPermissionPreviouslyDenied();
/*
* Callback on permission "Never show again" checked and denied
* */
void onPermissionDisabled();
/*
* Callback on permission granted
* */
void onPermissionGranted();
}
}
Run Code Online (Sandbox Code Playgroud)
而PreferenceUtil方法如下.
public static void firstTimeAskingPermission(Context context, String permission, boolean isFirstTime){
SharedPreferences sharedPreference = context.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE;
sharedPreference.edit().putBoolean(permission, isFirstTime).apply();
}
public static boolean isFirstTimeAskingPermission(Context context, String permission){
return context.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE).getBoolean(permission, true);
}
Run Code Online (Sandbox Code Playgroud)
现在,您只需要使用方法*checkPermission*和适当的参数.
这是一个例子,
PermissionUtil.checkPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE,
new PermissionUtil.PermissionAskListener() {
@Override
public void onPermissionAsk() {
ActivityCompat.requestPermissions(
thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
REQUEST_EXTERNAL_STORAGE
);
}
@Override
public void onPermissionPreviouslyDenied() {
//show a dialog explaining permission and then request permission
}
@Override
public void onPermissionDisabled() {
Toast.makeText(context, "Permission Disabled.", Toast.LENGTH_SHORT).show();
}
@Override
public void onPermissionGranted() {
readContacts();
}
});
Run Code Online (Sandbox Code Playgroud)
我的应用程序如何知道用户是否已选中"永不再问"?
如果用户选中" 永不再问",您将获得onPermissionDisabled的回调.
快乐编码:)
shouldShowRequestPermissionRationale()方法可用于检查用户是否选择了“不再询问”选项并拒绝了权限。有很多代码示例,所以我宁愿解释如何将它用于这样的目的,因为我认为它的名称和实现使得它比实际情况更复杂。
如运行时请求权限中所述,如果“不再询问”选项可见,则该方法返回 true,否则返回 false;因此,第一次显示对话框时它返回 false,然后从第二次开始它返回 true,并且只有当用户拒绝选择该选项的权限时,它才会再次返回 false。
要检测这种情况,您可以检测序列 false-true-false,或者(更简单)您可以使用一个标记来跟踪对话框的初始显示时间。之后,该方法返回 true 或 false,其中 false 将允许您检测何时选择该选项。
shouldShowRequestPermissionRationale根据先前权限请求中的用户首选项返回 true 或 false。
如果用户刚刚拒绝许可(不是永远)shouldShowRequestPermissionRationale将返回true。如果永远拒绝许可,则返回false。诀窍是,即使用户允许许可,也会shouldShowRequestPermissionRationale返回false。
因此,我们可以结合这两个条件来决定是否选择“不再询问”。
因此,如果用户未获得许可并shouldShowRequestPermissionRationale返回false,则意味着用户选择不再请求许可。
| 归档时间: |
|
| 查看次数: |
152138 次 |
| 最近记录: |