版本的Android M - 检查运行许可 - 如何确定用户选中“以后不要再询问”?版本的Andr

2019-05-10 12:57发布

根据这样的: http://developer.android.com/preview/features/runtime-permissions.html#coding一个应用程序可以检查运行时权限,并要求权限,如果它没有被已发。 将显示下面的对话框,则:

如果用户拒绝一个重要的权限,IMO为什么需要该权限的应用程序应该显示的解释,有什么样的影响下降。 该对话框中有两个选项:

  1. 再重试(许可请求再次)
  2. 否认(应用程序将没有这个权限的工作)。

如果用户检查Never ask again然而,与解释第二个对话框不应显示,特别是如果用户已经过一次下降。 现在的问题是:如何我的应用程序知道用户是否已经检查了Never ask again ? IMO的onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)不给我的信息。

第二个问题是:谷歌确实有计划将在权限对话框,可以解释为什么应用程序需要的权限的自定义消息? 这样,永远不会有第二个对话框,肯定会做出一个更好的UX。

Answer 1:

开发人员预览版2带来了一些改变,权限是如何被应用要求(见http://developer.android.com/preview/support.html#preview2-notes )。

第一个对话框现在看起来是这样的:

有没有“不再显示”复选框(不同于开发者预览版1)。 如果用户拒绝许可,如果允许对应用程序必不可少可能出现另一个对话框来解释应用程序请求该权限,例如像这样的原因:

如果用户再次拒绝的应用程序要么关闭,如果它绝对需要该权限或保留具有有限功能的运行。 如果用户重新考虑(并选择重试),允许再次请求。 这一次,提示如下:

显示在“不再询问”复选框第二次。 如果用户再次否认与复选框被选中罢了应该发生。 是否将复选框被选中可以通过使用Activity.shouldShowRequestPermissionRationale(字符串),例如像这样确定:

if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {...

这是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...*/ ) {
                }
            }
        }
    }
}

你可以打开你的应用程序使用此代码设置:

Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, REQUEST_PERMISSION_SETTING);

有没有直接发送到用户授权页面的方式。



Answer 2:

您可以检查shouldShowRequestPermissionRationale()在你的onRequestPermissionsResult()

https://youtu.be/C8lUdPVSzDk?t=2m23s

检查许可是否在授予或不onRequestPermissionsResult() 如果没有 ,那么检查shouldShowRequestPermissionRationale()

  1. 如果这个方法返回true然后显示一个解释,即为什么需要这种特殊的权限。 然后,根据用户的选择再次requestPermissions()
  2. 如果返回false则表明未授予该权限的错误信息和应用程序无法继续进行或特定功能将被禁用。

下面是示例代码。

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

显然,谷歌地图正是这一点为位置的权限。



Answer 3:

这里是一个很好的和简单的方法来检查当前许可状态:

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


Answer 4:

可以通过检查确定 ,如果许可的理由是里面显示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).
        }
    }
}


Answer 5:

可能是有用的人: -

我已经注意到,如果我们在检查shouldShowRequestPermissionRationale()标志onRequestPermissionsResult()回调方法,它显示了只有两个状态

国家1:-return真: - 任何时候用户点击拒绝权限(包括第一次)。

状态2: - 返回错误: - 如果用户选择“永不再询问”。

具体工作示例的链接



Answer 6:

一旦用户标记为“不要再问,”不能再次显示的问题。 但可以解释说,他以前曾否认权限,并且必须在设置授予权限的用户。 并引用他的设置,用下面的代码:

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


Answer 7:

如果要检测所有的“国家”(第一次否认,只是被剥夺了,刚刚被否认与“不再询问”或永久拒绝),你可以做到以下几点:

创建2个布尔

private boolean beforeClickPermissionRat;
private boolean afterClickPermissionRat;

要求许可之前设置的第一个:

beforeClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);

设置你的onRequestPermissionsResult方法里面的第二个:

afterClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);

使用下面的“表格”做任何你需要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


Answer 8:

我有同样的问题,我想它了。 为了让生活更简单,我写了一个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得到回调。

编码愉快:)



Answer 9:

许可的情况下,每一个完整的解释

/**
 *    Case 1: User doesn't have permission
 *    Case 2: User has permission
 *
 *    Case 3: User has never seen the permission Dialog
 *    Case 4: User has denied permission once but he din't clicked on "Never Show again" check box
 *    Case 5: User denied the permission and also clicked on the "Never Show again" check box.
 *    Case 6: User has allowed the permission
 *
 */
public void handlePermission() {
    if (ContextCompat.checkSelfPermission(MainActivity.this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {
        // This is Case 1. Now we need to check further if permission was shown before or not

        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

            // This is Case 4.
        } else {
            // This is Case 3. Request for permission here
        }

    } else {
        // This is Case 2. You have permission now you can do anything related to it
    }
}

public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        // This is Case 2 (Permission is now granted)
    } else {
        // This is Case 1 again as Permission is not granted by user

        //Now further we check if used denied permanently or not
        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            // case 4 User has denied permission but not permanently

        } else {
            // case 5. Permission denied permanently.
            // You can open Permission setting's page from here now.
        }

    }
}


Answer 10:

我写了许可请求的Android M.此代码还处理向后兼容较旧的Android版本的简写。

所有的丑陋的代码被提取成连接和断开本身到请求permissions.You可以使用活性的片段PermissionRequestManager如下:

new PermissionRequestManager()
        // We need a AppCompatActivity here, if you are not using support libraries you will have to slightly change 
        // the PermissionReuqestManager class
        .withActivity(this)

        // List all permissions you need
        .withPermissions(android.Manifest.permission.CALL_PHONE, android.Manifest.permission.READ_CALENDAR)

        // This Runnable is called whenever the request was successfull
        .withSuccessHandler(new Runnable() {
            @Override
            public void run() {
                // Do something with your permissions!
                // This is called after the user has granted all 
                // permissions, we are one a older platform where 
                // the user does not need to grant permissions 
                // manually, or all permissions are already granted

            }
        })

        // Optional, called when the user did not grant all permissions
        .withFailureHandler(new Runnable() {
            @Override
            public void run() {
                // This is called if the user has rejected one or all of the requested permissions
                L.e(this.getClass().getSimpleName(), "Unable to request permission");

            }
        })

        // After calling this, the user is prompted to grant the rights
        .request();

请看: https://gist.github.com/crysxd/385b57d74045a8bd67c4110c34ab74aa



Answer 11:

该方法shouldShowRequestPermissionRationale()可以是用户检查用户是否选择了“不会再问”选项,并否认的权限。 有大量的代码示例,所以我宁愿解释如何使用它的这样一个目的,因为我觉得它的名字和它的实施,使得这更复杂,它实际上是。

正如上文在运行时请求权限 ,如果选择“不再询问”是可见的,否则为false该方法返回true; 因此它返回false的第一次会弹出一个对话框,然后从它返回true,并且仅当用户拒绝许可选择的选项,在这一点上再次返回false第二次。

为了检测这样的情况下,或者可以检测序列假真 - 假,或(更简单)可以具有跟踪被显示的对话框的初始时间的标志。 在此之后,该方法返回true或false,其中假将使选择了该选项,当您察觉。



Answer 12:

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

它可以处理拒绝,它可以处理以后不要再询问,它可以调用的许可应用程序设置,它可以给一个合理的消息,它可以给一个拒绝的消息,它可以给接受权限的列表,它可以给出否定列表权限等。

https://github.com/ParkSangGwon/TedPermission

第1步:添加你的依赖

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

第二步:问权限

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


Answer 13:

一个有用的功能,以确定是否任意的许可已被从请求(在科特林)阻止:

private fun isPermissionBlockedFromAsking(activity: Activity, permission: String): Boolean {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        return ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED
            && !activity.shouldShowRequestPermissionRationale(permission)
            && PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(permission, false)
    }
    return false
}

这种使用需要用您想要的权限(如名称设置共享偏好布尔android.Manifest.permission.READ_PHONE_STATE ),以true当你第一次请求的权限。


说明:

Build.VERSION.SDK_INT >= Build.VERSION_CODES.M作为一些代码可以仅在API级别23+运行。

ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED检查,我们还没有权限。

!activity.shouldShowRequestPermissionRationale(permission) ,以检查用户是否已拒绝该应用程序再次询问。 由于该功能的怪癖 ,还需要以下行。

PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(permission, false)这是用来(与值设置为true第一许可请求一起)之间的“不要问”和“不再询问”状态,与前行没有按区分“T返回此信息。



Answer 14:

请不要扔我石头这种解决方案。

这工作,但有点“哈克”。

当你调用requestPermissions ,注册当前时间。

        mAskedPermissionTime = System.currentTimeMillis();

然后在onRequestPermissionsResult

如果结果不批,再次检查的时间。

 if (System.currentTimeMillis() - mAskedPermissionTime < 100)

由于用户没有不可能点击这么快就拒绝按钮,我们知道,他选择了“不再询问”,因为回调是即时的。

使用您自己的风险。



Answer 15:

您可以使用

shouldShowRequestPermissionRationale()

onRequestPermissionsResult()

看下面的例子:

检查是否有权限,当用户点击该按钮:

@Override
public void onClick(View v) {
    if (v.getId() == R.id.appCompatBtn_changeProfileCoverPhoto) {
        if (Build.VERSION.SDK_INT < 23) { // API < 23 don't need to ask permission
            navigateTo(MainActivity.class); // Navigate to activity to change photos
        } else {
            if (ContextCompat.checkSelfPermission(SettingsActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    != PackageManager.PERMISSION_GRANTED) {
                // Permission is not granted yet. Ask for permission...
                requestWriteExternalPermission();
            } else {
                // Permission is already granted, good to go :)
                navigateTo(MainActivity.class);
            }
        } 
    }
}

当用户接听权限对话框,我们会去onRequestPermissionResult:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    if (requestCode == WRITE_EXTERNAL_PERMISSION_REQUEST_CODE) {
        // Case 1. Permission is granted.  
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {  
            if (ContextCompat.checkSelfPermission(SettingsActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    == PackageManager.PERMISSION_GRANTED) {
                // Before navigating, I still check one more time the permission for good practice.
                navigateTo(MainActivity.class);
            }
        } else { // Case 2. Permission was refused
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                // Case 2.1. shouldShowRequest... returns true because the
                // permission was denied before. If it is the first time the app is running we will 
                // end up in this part of the code. Because he need to deny at least once to get 
                // to onRequestPermissionsResult. 
                Snackbar snackbar = Snackbar.make(findViewById(R.id.relLayout_container), R.string.you_must_verify_permissions_to_send_media, Snackbar.LENGTH_LONG);
                snackbar.setAction("VERIFY", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        ActivityCompat.requestPermissions(SettingsActivity.this
                                , new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}
                                , WRITE_EXTERNAL_PERMISSION_REQUEST_CODE);
                    }
                });
                snackbar.show();
            } else {
                // Case 2.2. Permission was already denied and the user checked "Never ask again". 
                // Navigate user to settings if he choose to allow this time.
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setMessage(R.string.instructions_to_turn_on_storage_permission)
                        .setPositiveButton(getString(R.string.settings), new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                Intent settingsIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                                Uri uri = Uri.fromParts("package", getPackageName(), null);
                                settingsIntent.setData(uri);
                                startActivityForResult(settingsIntent, 7);
                            }
                        })
                        .setNegativeButton(getString(R.string.not_now), null);
                Dialog dialog = builder.create();
                dialog.show();
            }
        }
    }

}


Answer 16:

你可以听者漂亮。

倾听者

interface PermissionListener {
    fun onNeedPermission()
    fun onPermissionPreviouslyDenied(numberDenyPermission: Int)
    fun onPermissionDisabledPermanently(numberDenyPermission: Int)
    fun onPermissionGranted()
}

MainClass许可

class PermissionUtil {

    private val PREFS_FILENAME = "permission"
    private val TAG = "PermissionUtil"

    private fun shouldAskPermission(context: Context, permission: String): Boolean {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val permissionResult = ActivityCompat.checkSelfPermission(context, permission)
            if (permissionResult != PackageManager.PERMISSION_GRANTED) {
                return true
            }
        }
        return false
    }

    fun checkPermission(context: Context, permission: String, listener: PermissionListener) {

        Log.i(TAG, "CheckPermission for $permission")

        if (shouldAskPermission(context, permission)) {

            // Load history permission
            val sharedPreference = context.getSharedPreferences(PREFS_FILENAME, 0)
            val numberShowPermissionDialog = sharedPreference.getInt(permission, 0)

            if (numberShowPermissionDialog == 0) {

                (context as? Activity)?.let {
                    if (ActivityCompat.shouldShowRequestPermissionRationale(it, permission)) {
                        Log.e(TAG, "User has denied permission but not permanently")
                        listener.onPermissionPreviouslyDenied(numberShowPermissionDialog)
                    } else {
                        Log.e(TAG, "Permission denied permanently.")
                        listener.onPermissionDisabledPermanently(numberShowPermissionDialog)
                    }
                } ?: kotlin.run {
                    listener.onNeedPermission()
                }

            } else {
                // Is FirstTime
                listener.onNeedPermission()
            }


            // Save history permission
            sharedPreference.edit().putInt(permission, numberShowPermissionDialog + 1).apply()


        } else {
            listener.onPermissionGranted()
        }

    }
}

通过这种方式使用

      PermissionUtil().checkPermission(this, Manifest.permission.ACCESS_FINE_LOCATION,
                object : PermissionListener {
                    override fun onNeedPermission() {
                        log("---------------------->onNeedPermission")

//                            ActivityCompat.requestPermissions(this@SplashActivity,
//                                    Array(1) { Manifest.permission.ACCESS_FINE_LOCATION },
//                                    118)

                    }

                    override fun onPermissionPreviouslyDenied(numberDenyPermission: Int) {
                        log("---------------------->onPermissionPreviouslyDenied")
                    }

                    override fun onPermissionDisabledPermanently(numberDenyPermission: Int) {
                        log("---------------------->onPermissionDisabled")
                    }

                    override fun onPermissionGranted() {
                        log("---------------------->onPermissionGranted")
                    }

                })

覆盖onRequestPermissionsResult在活动或fragmnet

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
 if (requestCode == 118) {
        if (permissions[0] == Manifest.permission.ACCESS_FINE_LOCATION && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            getLastLocationInMap()
        }
        }
    }


Answer 17:

我也想获得用户是否已经选择了“不再询问”的信息。 我已经实现了“几乎解决方案”有难看的标志,但在此之前,我告诉你怎么样,我会告诉你我的动力:

我想提出首先参照功能的权限。 如果用户使用它,也没有权利,他/她会从上方或两个第二和第三的任1号对话框。 当用户选择“不再询问”我想禁用功能,并以不同的方式显示。 - 我的动作是由一个旋转文本输入引发的,我也想“(撤销准许)”添加到显示的标签文本。 这显示给用户:“有功能,但我不能使用它,因为我的权限设置。” 然而,这似乎并不可能,因为我不能确认有无“不再询问”已被选定。

我来到了一个解决方案,我可以通过让我的功能总是以积极的权限检查启用生活。 我显示onRequestPermissionsResult()举杯消息的负面反应的情况下,但只有当我还没有表现出我的自定义理由弹出。 因此,如果用户选择“不再询问”他只得到一个敬酒的消息。 如果用户不愿意选择“不再询问”,他只获得了自定义的理由和操作系统的许可要求弹出,但不敬酒,三个通知,连续将太多的痛苦。



Answer 18:

相反,你将收到回调上onRequestPermissionsResult()作为PERMISSION_DENIED当你再次申请许可而在假条件下降shouldShowRequestPermissionRationale()

从Android的文档:

当系统要求用户授予权限,用户告知系统不要再问了该权限的选项。 在这种情况下,任何时候应用程序使用requestPermissions()再次要求该权限,系统会立即拒绝该请求。 该系统调用您onRequestPermissionsResult()回调方法,并将PERMISSION_DENIED ,以同样的方式,将如果用户已明确再次拒绝您的请求。 这意味着,当你调用requestPermissions()你不能假设与用户进行任何直接的互动已经发生。



Answer 19:

我要实现对相机的动态许可。 其中3可能情况会发生:1.允许,拒绝2,3,不要再问。

 @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

    for (String permission : permissions) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), permission)) {
            //denied
            Log.e("denied", permission);
        } else {
            if (ActivityCompat.checkSelfPermission(getActivity(), permission) == PackageManager.PERMISSION_GRANTED) {
                //allowed
                Log.e("allowed", permission);
            } else {
                //set to never ask again
                Log.e("set to never ask again", permission);
                //do something here.
            }
        }
    }
    if (requestCode != MaterialBarcodeScanner.RC_HANDLE_CAMERA_PERM) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        return;
    }
    if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        mScannerView.setResultHandler(this);
        mScannerView.startCamera(mCameraId);
        mScannerView.setFlash(mFlash);
        mScannerView.setAutoFocus(mAutoFocus);
        return;
    } else {
        //set to never ask again
        Log.e("set to never ask again", permissions[0]);
    }
    DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            dialog.cancel();
        }
    };
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    builder.setTitle("Error")
            .setMessage(R.string.no_camera_permission)
            .setPositiveButton(android.R.string.ok, listener)
            .show();


}

private void insertDummyContactWrapper() {
        int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.CAMERA);
        if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.CAMERA},
                    REQUEST_CODE_ASK_PERMISSIONS);
            return;
        }
        mScannerView.setResultHandler(this);
        mScannerView.startCamera(mCameraId);
        mScannerView.setFlash(mFlash);
        mScannerView.setAutoFocus(mAutoFocus);
    }

private int checkSelfPermission(String camera) {
    if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)
            != PackageManager.PERMISSION_GRANTED) {
        return REQUEST_CODE_ASK_PERMISSIONS;
    } else {
        return REQUEST_NOT_CODE_ASK_PERMISSIONS;
    }
}


Answer 20:

您可以使用if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)的方法来检测是否不问被选中与否。

欲了解更多参考: 选中此

要检查多个权限使用:

  if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)
                                || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                                || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)
                                || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
                            showDialogOK("Service Permissions are required for this app",
                                    new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            switch (which) {
                                                case DialogInterface.BUTTON_POSITIVE:
                                                    checkAndRequestPermissions();
                                                    break;
                                                case DialogInterface.BUTTON_NEGATIVE:
                                                    // proceed with logic by disabling the related features or quit the app.
                                                    finish();
                                                    break;
                                            }
                                        }
                                    });
                        }
                        //permission is denied (and never ask again is  checked)
                        //shouldShowRequestPermissionRationale will return false
                        else {
                            explain("You need to give some mandatory permissions to continue. Do you want to go to app settings?");
                            //                            //proceed with logic by disabling the related features or quit the app.
                        }

解释()方法

private void explain(String msg){
        final android.support.v7.app.AlertDialog.Builder dialog = new android.support.v7.app.AlertDialog.Builder(this);
        dialog.setMessage(msg)
                .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                        //  permissionsclass.requestPermission(type,code);
                        startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:com.exampledemo.parsaniahardik.marshmallowpermission")));
                    }
                })
                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                        finish();
                    }
                });
        dialog.show();
    }

上面的代码也将显示对话框,将用户从那里,他可以给予许可,如果已经检查不再询问按钮重定向到应用程序的设置画面。



Answer 21:

扩大对mVck的回答上面,下面的逻辑判断‘再不要问’已被检查给定的许可请求:

bool bStorage = grantResults[0] == Permission.Granted;
bool bNeverAskForStorage =
    !bStorage && (
        _bStorageRationaleBefore == true  && _bStorageRationaleAfter == false ||
        _bStorageRationaleBefore == false && _bStorageRationaleAfter == false
    );

这是从摘录如下(为全面例如看到这个答案 )

private bool _bStorageRationaleBefore;
private bool _bStorageRationaleAfter;        
private const int ANDROID_PERMISSION_REQUEST_CODE__SDCARD = 2;
//private const int ANDROID_PERMISSION_REQUEST_CODE__CAMERA = 1;
private const int ANDROID_PERMISSION_REQUEST_CODE__NONE = 0;

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
{
    base.OnRequestPermissionsResult(requestCode, permissions, grantResults);

    switch (requestCode)
    {
        case ANDROID_PERMISSION_REQUEST_CODE__SDCARD:               
            _bStorageRationaleAfter = ShouldShowRequestPermissionRationale(Android.Manifest.Permission.WriteExternalStorage);
            bool bStorage = grantResults[0] == Permission.Granted;
            bool bNeverAskForStorage =
                !bStorage && (
                    _bStorageRationaleBefore == true  && _bStorageRationaleAfter == false ||
                    _bStorageRationaleBefore == false && _bStorageRationaleAfter == false
                );      
            break;                
    }
}

private List<string> GetRequiredPermissions(out int requestCode)
{
    // Android v6 requires explicit permission granting from user at runtime for security reasons            
    requestCode = ANDROID_PERMISSION_REQUEST_CODE__NONE; // 0
    List<string> requiredPermissions = new List<string>();

    _bStorageRationaleBefore = ShouldShowRequestPermissionRationale(Android.Manifest.Permission.WriteExternalStorage);
    Permission writeExternalStoragePerm = ApplicationContext.CheckSelfPermission(Android.Manifest.Permission.WriteExternalStorage);
    //if(extStoragePerm == Permission.Denied)
    if (writeExternalStoragePerm != Permission.Granted)
    {
        requestCode |= ANDROID_PERMISSION_REQUEST_CODE__SDCARD;
        requiredPermissions.Add(Android.Manifest.Permission.WriteExternalStorage);
    }

    return requiredPermissions;
}

protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);

        // Android v6 requires explicit permission granting from user at runtime for security reasons
        int requestCode;
        List<string> requiredPermissions = GetRequiredPermissions(out requestCode);
        if (requiredPermissions != null && requiredPermissions.Count > 0)
        {
            if (requestCode >= ANDROID_PERMISSION_REQUEST_CODE__SDCARD)                    
            {
                _savedInstanceState = savedInstanceState;
                RequestPermissions(requiredPermissions.ToArray(), requestCode);
                return;
            }
        }
    }            

    OnCreate2(savedInstanceState);
}


Answer 22:

public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
    switch (requestCode) {
        case PERMISSIONS_REQUEST_EXTERNAL_STORAGE: {
            if (grantResults.length > 0) {
                if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                    // Denied
                } else {
                    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
                        // To what you want
                    } else {
                       // Bob never checked click
                    }
                }
            }
        }
    }
}


Answer 23:

你可以看到Android的正式文件请求的应用权限。

或者你可以在Github上找到许多流行的Android许可库

  • PermissionsDispatcher
  • RxPermissions
  • easypermissions


文章来源: Android M - check runtime permission - how to determine if the user checked “Never ask again”?