Android shouldshowRequestPermission基本原理和requestPermissions之间的区别是什么?

Android shouldshowRequestPermission基本原理和requestPermissions之间的区别是什么?,android,android-permissions,android-location,Android,Android Permissions,Android Location,我正在构建一个需要用户位置的应用程序。我正在关注Android培训文档,其中说明: shouldshowRequestPermissionRegulation返回布尔值,指示我们是否应显示具有请求权限理由的UI(危险权限、访问位置) 现在在这段代码中(取自文档本身): [我的疑问]这部分代码不应该(如下)吗 在这里处于“如果”状态 if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,

我正在构建一个需要用户位置的应用程序。我正在关注Android培训文档,其中说明:

shouldshowRequestPermissionRegulation
返回布尔值,指示我们是否应显示具有请求权限理由的UI(危险权限、访问位置)

现在在这段代码中(取自文档本身):

[我的疑问]这部分代码不应该(如下)吗

在这里处于“如果”状态

 if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.READ_CONTACTS)) {
    //HERE .....

}
我是说,如果

ActivityCompat.shouldShowRequestPermissionRationale(thisActivity, Manifest.permission.READ_CONTACTS)   
是真的,那么我们需要显示UI,我们将通过

ActivityCompat.requestPermissions(thisActivity,
    newString[{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS);
请解释我错在哪里。我被困在这里了。提前谢谢。 请举个例子


注意:当然,我是在安卓M上运行我的应用程序,我的目标sdk>=23。

请求权限分为两个阶段——说明理由,然后实际请求权限

它们通常显示为两个单独的对话框,按顺序显示:

  • 仅包含文本的对话框,该文本向用户提供需要权限的原因(基本原理)
  • 实际请求权限的对话框。如下图所示:
  • 因此,文档中的代码是正确的。逻辑是:

    if we need to show a rationale:
        show the rationale dialog
    otherwise:
        just ask for permissions to be granted without showing the rationale dialog
    

    根据文件

    shouldshowRequestPermissionRegulation
    返回布尔值,指示是否应显示带有请求权限理由的UI

    此UI是我们的自定义UI(例如,我们可以显示alertdialog),而不是我们的设备显示的对话框(见下文):

    考虑到这一点,现在

    shouldshowRequestPermissionPrinciple
    的返回值如流程图所示

    还注意到

    When that user "denies"  your permission by CHECKING "never ask again", ``shouldShowRequestPermissionRationale`` would still return ``false``. 
    
    综上所述,

    • shouldshowRequestPermissionRegulation
      仅当应用程序较早启动且用户未选中“永不再次请求”而“拒绝”权限时才会返回true
    • 在其他情况下(首次启动的应用程序,或较早启动的应用程序,用户通过选中“永不再次询问”来拒绝许可),返回值为false
    实施

    让我们创建一个
    PermissionUtils.java
    文件,它为我们处理不同的情况

    public class PermissionUtils {
    
        private static final String TAG = "PermissionUtils";
    
        /*
            Inside this shared_preference file, we will just store information
            about whether the user had visited our app earlier or not.
        */
    
        private static final String PREFS_FILE_NAME = "preference_permission";
        private static final String PREFS_FIRST_TIME_KEY = "is_app_launched_first_time";
    
    
        //an interface containing 5 methods
        //...the scenario in which these callback will be called is written below each method declaration.
        public interface PermissionAskListener {
    
    
            void onPermissionGranted();
            /*
                User has already granted this permission
                The app must had been launched earlier and the user must had "allowed" that permission
             */
    
    
            void onPermissionRequest();
            /*
                The app is launched FIRST TIME..
                We don't need to show additional dialog, we just request for the permission..
    
             */
    
    
            void onPermissionPreviouslyDenied();
            /*
                The app was launched earlier and the user simply "denied" the permission..
                The user had NOT clicked "DO NOT SHOW AGAIN"
                We need to show additional dialog in this case explaining how "allowing this permission" would be useful to the user
             */
    
    
            void onPermissionDisabled();
            /*
                The app had launched earlier and the user "denied" the permission..
                AND ALSO had clicked "DO NOT ASK AGAIN"
                We need to show Toask/alertdialog/.. to indicate that the user had denied the permission by checking do not disturb too...
                So, you might want to take the user to setting>app>permission page where the user can allow the permission..
    
    
             */
    
        }
    
        // preference utility methods
        private static boolean getApplicationLaunchedFirstTime(Activity activity) {
            SharedPreferences sharedPreferences = activity.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE);
            return sharedPreferences.getBoolean(PREFS_FIRST_TIME_KEY, true);
        }
    
        private static void setApplicationLaunchedFirstTime(Activity activity) {
            SharedPreferences sharedPreferences = activity.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE);
            SharedPreferences.Editor editor = sharedPreferences.edit();
            editor.putBoolean(PREFS_FIRST_TIME_KEY, false);
            editor.commit();
        }
    
    
        private static boolean isRuntimePermissionRequired() {
            return (Build.VERSION.SDK_INT >= 23);
        }
    
        public static void checkPermission(Activity activity, String permission, PermissionAskListener permissionAskListener) {
    
            Log.d(TAG, "checkPermission");
    
    
            if (!isRuntimePermissionRequired()) {
                /*
                    Runtime permission not required,
                    THE DEVICE IS RUNNING ON < 23, So, no runtime permission required..
                    Simply call **** permissionAskListener.onPermissionGranted() ****
                 */
    
    
                permissionAskListener.onPermissionGranted();
            } else {
                //runtime permission required here...
    
                //check if the permission is already granted, i.e the application was launched earlier too, and the user had "allowed" the permission then.
                if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
                    /* We don't have permission, two cases arise:
                         1. App launched first time, 
                         2. App launched earlier too, and the user had denied the permission is last launch
                               2A. The user denied permission earlier WITHOUT checking "Never ask again"
                               2B. The user denied permission earlier WITH checking "Never ask again"
                    */
    
                    if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
    
                        /* 
                           shouldShowRequestPermissionRationale returned true
                           this means Case: 2A
                           see the flowchart, the only case when shouldShowRequestPermissionRationale returns "true", is when the application was launched earlier too and the user had "denied" the permission in last launch WITHOUT checking "never show again"
                        */
    
                        permissionAskListener.onPermissionPreviouslyDenied();
                    } else {
                        /*  
                             this means, either - 
                             Case: 1 or Case 2B
                             See Flowchart, shouldShowRequestPermissionRationale returns false, only when app is launched first time (Case: 1) or app was launched earlier too and user HAD checked "Never show again" then (Case: 2B)
                        */
                        if (getApplicationLaunchedFirstTime(activity)) {
    
                            //Case: 1
                            Log.d(TAG, "ApplicationLaunchedFirstTime");
    
                            setApplicationLaunchedFirstTime(activity);  //  ** DON'T FORGET THIS **
                            permissionAskListener.onPermissionRequest();
    
                        } else {
                            //Case: 2B
                            Log.d(TAG, "onPermissionDisabled");
    
                            permissionAskListener.onPermissionDisabled();
                        }
                    }
    
    
                } else {
                    Log.d(TAG, "Permission already granted");
    
                    permissionAskListener.onPermissionGranted();
                }
            }
        }
    }
    
  • 如果我们确实需要运行时权限,那么我们会检查之前是否已经获得了该权限

    ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED)
    
  • 如果我们没有许可,那么我们需要处理两种情况:

    1. App launched first time, 
    2. App launched earlier too, and the user had denied the permission is last launch                  
        2A. The user denied permission earlier WITHOUT checking "Never ask again".
        2B. The user denied permission earlier WITH checking "Never ask again".
    
  • 因此,底线是:

    在我们的
    PermissionUtils.java
    中,我们定义了一个包含5个抽象方法的接口。这些方法是回调,将在上述不同情况下调用

    最后,在我们的活动中,我们通过实现侦听器的回调来处理所有这些情况

        PermissionUtils.checkPermission(MainActivity.this,
                Manifest.permission.ACCESS_FINE_LOCATION,
                new PermissionUtils.PermissionAskListener() {
                    @Override
                    public void onPermissionGranted() {
                        updateUI();
    
                    }
    
                    @Override
                    public void onPermissionRequest() {
    
                        ActivityCompat.requestPermissions(MainActivity.this,
                                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                                My_PERMISSION_ACCESS_FINE_LOCATION);
    
    
                    }
    
                    @Override
                    public void onPermissionPreviouslyDenied() {
    
                        //Show an alert message and "request the permission" in its "setPositiveButton"
                        //...and in "setOnNegativeButton", just cancel the dialog and do not run the
                        //...functionality that requires this permission (here, ACCESS_FINE_LOCATION)
                        new AlertDialog.Builder(MainActivity.this)
                                .setTitle("Permission required")
                                .setMessage("Location is required for this application to work ! ")
                                .setPositiveButton("Allow", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        ActivityCompat.requestPermissions(MainActivity.this,
                                                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                                                My_PERMISSION_ACCESS_FINE_LOCATION);
    
    
                                    }
    
                                })
                                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        dialog.cancel();
                                        finish();
                                    }
                                })
                                .show();
    
    
                    }
    
                    @Override
                    public void onPermissionDisabled() {
    
    
    
                        new AlertDialog.Builder(MainActivity.this)
                                .setTitle("Permission Disabled")
                                .setMessage("Please enable the permission in \n  Settings>Uber>Permission \n and check 'location' permission")
                                .setPositiveButton("Go to settings", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        startActivity(new Intent(Settings.ACTION_SETTINGS));
    
    
                                    }
    
                                })
                                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        dialog.cancel();
                                        finish();
                                    }
                                })
                                .show();
    
    
                    }
                });
    
    
    }
    

    希望这能有所帮助。

    另一个选择是使用谷歌自己提供的,如前所述,“简化安卓M系统权限”。这样您就不必直接调用
    shouldshowRequestPermissionRegulation


    这样,您就不必调用
    shouldshowRequestPermissionRegulation
    或直接处理其返回值。

    +1:回答得好!然而,作为一项改进建议,在每个许可的基础上跟踪“首次启动的应用程序”可能是有用的。这可以通过基于
    PREFS\u first\u time\u键+权限创建“first time”键轻松实现。这还意味着更改
    getApplicationLaunchedFirstTime
    方法以接受
    permission
    键作为参数。如果我有多个权限怎么办?
    if (!isRuntimePermissionRequired()) {...}
    
    ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED)
    
    1. App launched first time, 
    2. App launched earlier too, and the user had denied the permission is last launch                  
        2A. The user denied permission earlier WITHOUT checking "Never ask again".
        2B. The user denied permission earlier WITH checking "Never ask again".
    
        PermissionUtils.checkPermission(MainActivity.this,
                Manifest.permission.ACCESS_FINE_LOCATION,
                new PermissionUtils.PermissionAskListener() {
                    @Override
                    public void onPermissionGranted() {
                        updateUI();
    
                    }
    
                    @Override
                    public void onPermissionRequest() {
    
                        ActivityCompat.requestPermissions(MainActivity.this,
                                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                                My_PERMISSION_ACCESS_FINE_LOCATION);
    
    
                    }
    
                    @Override
                    public void onPermissionPreviouslyDenied() {
    
                        //Show an alert message and "request the permission" in its "setPositiveButton"
                        //...and in "setOnNegativeButton", just cancel the dialog and do not run the
                        //...functionality that requires this permission (here, ACCESS_FINE_LOCATION)
                        new AlertDialog.Builder(MainActivity.this)
                                .setTitle("Permission required")
                                .setMessage("Location is required for this application to work ! ")
                                .setPositiveButton("Allow", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        ActivityCompat.requestPermissions(MainActivity.this,
                                                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                                                My_PERMISSION_ACCESS_FINE_LOCATION);
    
    
                                    }
    
                                })
                                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        dialog.cancel();
                                        finish();
                                    }
                                })
                                .show();
    
    
                    }
    
                    @Override
                    public void onPermissionDisabled() {
    
    
    
                        new AlertDialog.Builder(MainActivity.this)
                                .setTitle("Permission Disabled")
                                .setMessage("Please enable the permission in \n  Settings>Uber>Permission \n and check 'location' permission")
                                .setPositiveButton("Go to settings", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        startActivity(new Intent(Settings.ACTION_SETTINGS));
    
    
                                    }
    
                                })
                                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        dialog.cancel();
                                        finish();
                                    }
                                })
                                .show();
    
    
                    }
                });
    
    
    }