根据这个:http://developer.android.com/preview/features/runtime-permissions.html#coding一个应用程序可以检查运行时权限和请求权限,如果它还没有被授予。弹出如下对话框:

如果用户拒绝一个重要的权限,在我看来,应用程序应该显示一个解释为什么需要权限和什么影响拒绝。该对话框有两个选项:

重试(再次请求许可) 拒绝(应用程序将工作没有该许可)。

但是,如果用户选中“Never ask again”,则不应该显示带有解释的第二个对话框,特别是如果用户之前已经拒绝了一次。 现在的问题是:我的应用程序如何知道用户是否选中了Never ask again?IMO onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)没有给我这个信息。

第二个问题是:谷歌是否计划在权限对话框中包含一个自定义消息,以解释为什么应用程序需要权限?这样就不会出现第二个对话框,这肯定会带来更好的用户体验。


当前回答

这里有一个很好的和简单的方法来检查当前的权限状态:

    @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;
    }

警告:在用户通过用户提示接受/拒绝权限之前,在第一个应用程序启动时返回BLOCKED_OR_NEVER_ASKED(在sdk 23+设备上)

更新:

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;

其他回答

我发现这个问题的方法对我来说有点新鲜。我必须保留一个参考,如果用户曾经选择了一个决定。通过这种方式,如果权限没有被授予,我可以告诉用户是第一次在那里,并且应该提示看到权限弹出,或者用户暂时或永久地拒绝它。

psudocode:

if( granted ) {
 // you are set
} else if( requiresRationale() ) {
 // in the ui let the user know he has to tap and launch permission
 button.onSetClickListener { requestPermission() }
} else if( sharedPreferences.getBoolean("permission", false) ) {
  // so user has already decided to deny permission, then it is permanent
  launchAppSettings()
} else {
  // user's first encounter, request permission
  requestPermission()
}

演示文件以GIF格式附在自述文件中。 https://github.com/juanmendez/android-sdk-updates/tree/api/android-permissions/single

试试这个简单的权限库。它将在3个简单的步骤中处理与权限相关的所有操作。这节省了我的时间。您可以在15分钟内完成所有权限相关的工作。

它可以处理拒绝,它可以处理永不再请求,它可以调用应用程序设置的权限,它可以给出一个Rational消息,它可以给出一个拒绝消息,它可以给出一个接受的权限列表,它可以给出一个拒绝的权限列表,等等。

https://github.com/ParkSangGwon/TedPermission

步骤1:添加依赖项

dependencies {
     compile 'gun0912.ted:tedpermission:2.1.1'
     //check the above link for latest libraries
}

步骤2:征求许可

TedPermission.with(this)
    .setPermissionListener(permissionlistener)
    .setDeniedMessage("If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]")
    .setPermissions(Manifest.permission.READ_CONTACTS, Manifest.permission.ACCESS_FINE_LOCATION)
    .check();

步骤3:处理权限响应

PermissionListener permissionlistener = new PermissionListener() {
    @Override
    public void onPermissionGranted() {
        Toast.makeText(MainActivity.this, "Permission Granted", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onPermissionDenied(ArrayList<String> deniedPermissions) {
        Toast.makeText(MainActivity.this, "Permission Denied\n" + deniedPermissions.toString(), Toast.LENGTH_SHORT).show();
    }
};

shouldShowRequestPermissionRationale根据之前权限请求中的用户首选项返回true或false。

如果用户只是拒绝权限(不是永远)shouldShowRequestPermissionRationale将返回true。如果永远拒绝许可,则返回false。窍门是即使用户允许了权限shouldShowRequestPermissionRationale也会返回false。

因此,我们可以结合这两个条件来得到永不再问的选择与否。

因此,如果用户不允许权限,并且shouldShowRequestPermissionRationale返回false,那么这意味着用户选择永远不会再次请求权限。

https://stackoverflow.com/a/58114769/5151336

shouldShowRequestPermissionRationale()方法可以用来检查用户是否选择了“never asked again”选项并拒绝了权限。 有很多代码示例,所以我宁愿解释如何将它用于这样的目的,因为我认为它的名称和实现使它比实际情况更加复杂。

正如在运行时请求权限中解释的那样,如果选项“never ask again”可见,该方法返回true,否则返回false;因此,它在第一次显示对话框时返回false,然后从第二次开始返回true,只有当用户拒绝选择该选项的权限时,它才会再次返回false。

要检测这种情况,您可以检测序列false-true-false,或者(更简单)您可以使用一个标记来跟踪对话框显示的初始时间。在此之后,该方法返回true或false,其中false将允许您检测何时选择该选项。

我也遇到过同样的问题,但我解决了。为了简化工作,我编写了一个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();
    }
}

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);
}

现在,您所需要的就是使用带有适当参数的方法* 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();
                        }
                    });

我的应用程序如何知道用户是否选中了“永不再问”?

如果用户勾选“永不再问”,你将得到onPermissionDisabled上的回调。

快乐编码:)