ChatGPT解决这个技术问题 Extra ChatGPT

我们如何区分 Android M 的运行时权限中的从不询问和停止询问?

根据 Google,谈到 M Developer Preview 运行时权限时:

如果您之前从未请求过某个权限,只需请求它需要权限,然后再继续请求权限(例如,禁用需要权限的 UI)

然而,我们只有一个方法,shouldShowRequestPermissionRationale(),返回一个 boolean,我们有三个状态。我们需要一种方法来区分从未询问状态和停止询问状态,因为我们从 shouldShowRequestPermissionRationale() 中得到 false

对于第一次运行应用程序时请求的权限,这不是一个大问题。有很多方法可以确定这可能是您的应用程序的第一次运行(例如,SharedPreferences 中的 boolean 值),因此您假设如果这是您的应用程序的第一次运行,那么您永远不会-问状态。

但是,运行时权限的部分愿景是您可能不会预先要求所有这些权限。当用户点击需要该权限的东西时,您可能只会在以后请求与边缘功能相关的权限。在这里,应用程序可能已经运行了好几个月,然后我们突然需要请求另一个权限。

在这些情况下,我们是否应该跟踪我们是否自己请求了许可?还是我缺少的 Android M API 中的某些内容可以告诉我们之前是否询问过?

这是我得到的所有信息,与您刚刚发布的信息相同plus.google.com/+BenjaminWeiss/posts/PFSd7wau4n8
示例应用程序是如此琐碎和不完整,它可能不存在。
所以最好的猜测是在 SharedPreferences 每个权限或任何类似的工件中存储一个布尔值,这是谷歌在 IO 的推荐。
我担心 SharedPreferences 可能与 Android 自己存储的权限信息不同步。 Android 是关于运行时权限的“记录系统”。它显然有信息,否则它永远无法从 shouldShowRequestPermissionRationale() 返回 true。我只是看看是否有一些我缺少的方法被添加了,仅此而已。
了解 Google,他们将在 6.1 中弃用 shouldShowRequestPermissionRationale() 并添加一个返回 int 的新方法。

N
Nicks

我知道我发布得很晚,但是详细的示例可能对某人有所帮助。

我注意到的是,如果我们将 shouldShowRequestPermissionRationale() 标志检查到 onRequestPermissionsResult() 回调方法中,它只显示两种状态。

状态1:-返回真:--任何时候用户点击拒绝权限(包括第一次。

状态 2:- 返回 false :- 如果用户选择 s,则不再询问。

这是一个具有多个权限请求的示例:-

该应用程序在启动时需要 2 个权限。 SEND_SMS 和 ACCESS_FINE_LOCATION(都在 manifest.xml 中提到)。

应用程序启动后,它会一起请求多个权限。如果两个权限都被授予,则正常流程进行。

https://i.stack.imgur.com/TmOCS.png

public static final int REQUEST_ID_MULTIPLE_PERMISSIONS = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if(checkAndRequestPermissions()) {
        // carry on the normal flow, as the case of  permissions  granted.
    }
}

private  boolean checkAndRequestPermissions() {
    int permissionSendMessage = ContextCompat.checkSelfPermission(this,
            Manifest.permission.SEND_SMS);
    int locationPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
    List<String> listPermissionsNeeded = new ArrayList<>();
    if (locationPermission != PackageManager.PERMISSION_GRANTED) {
        listPermissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
    }
    if (permissionSendMessage != PackageManager.PERMISSION_GRANTED) {
        listPermissionsNeeded.add(Manifest.permission.SEND_SMS);
    }
    if (!listPermissionsNeeded.isEmpty()) {
        ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]),REQUEST_ID_MULTIPLE_PERMISSIONS);
        return false;
    }
    return true;
}

如果一个或多个权限没有被授予,activityCompat.requestPermissions() 将请求权限并且控制转到 onRequestPermissionsResult() 回调方法。

您应该检查 onRequestPermissionsResult() 回调方法中 shouldShowRequestPermissionRationale() 标志的值。

只有两种情况:--

案例1:-任何时候用户点击拒绝权限(包括第一次),它都会返回true。所以当用户拒绝的时候,我们可以给出更多的解释并继续询问。

案例 2:- 只有当用户选择“不再询问”时,它才会返回 false。在这种情况下,我们可以继续使用有限的功能,并引导用户从设置中激活权限以获得更多功能,或者如果权限对应用程序来说是微不足道的,我们可以完成设置。

情况1

https://i.stack.imgur.com/nbTo6.png

案例- 2

https://i.stack.imgur.com/rQqYp.png

@Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        Log.d(TAG, "Permission callback called-------");
        switch (requestCode) {
            case REQUEST_ID_MULTIPLE_PERMISSIONS: {

                Map<String, Integer> perms = new HashMap<>();
                // Initialize the map with both permissions
                perms.put(Manifest.permission.SEND_SMS, PackageManager.PERMISSION_GRANTED);
                perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
                // Fill with actual results from user
                if (grantResults.length > 0) {
                    for (int i = 0; i < permissions.length; i++)
                        perms.put(permissions[i], grantResults[i]);
                    // Check for both permissions
                    if (perms.get(Manifest.permission.SEND_SMS) == PackageManager.PERMISSION_GRANTED
                            && perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                        Log.d(TAG, "sms & location services permission granted");
                        // process the normal flow
                        //else any one or both the permissions are not granted
                    } else {
                            Log.d(TAG, "Some permissions are not granted ask again ");
                            //permission is denied (this is the first time, when "never ask again" is not checked) so ask again explaining the usage of permission
//                        // shouldShowRequestPermissionRationale will return true
                            //show the dialog or snackbar saying its necessary and try again otherwise proceed with setup.
                            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.SEND_SMS) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
                                showDialogOK("SMS and Location Services Permission 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.
                                                        break;
                                                }
                                            }
                                        });
                            }
                            //permission is denied (and never ask again is  checked)
                            //shouldShowRequestPermissionRationale will return false
                            else {
                                Toast.makeText(this, "Go to settings and enable permissions", Toast.LENGTH_LONG)
                                        .show();
    //                            //proceed with logic by disabling the related features or quit the app.
                            }
                    }
                }
            }
        }

    }

    private void showDialogOK(String message, DialogInterface.OnClickListener okListener) {
        new AlertDialog.Builder(this)
                .setMessage(message)
                .setPositiveButton("OK", okListener)
                .setNegativeButton("Cancel", okListener)
                .create()
                .show();
    }

问题是 shouldShowRequestPermissionRationale 如果他们检查了“不再询问”或者他们以前从未拒绝过,则返回 false。所以检查这个方法的返回值并不足以知道我们是否应该预先教育。
我们如何使用这个解决方案? shouldShowRequestPermissionRationale() 需要 minSdkVersion 23
@NaPro 此功能(运行时权限)仅在 API23 中提供。并且支持向后兼容性,所以 minSdkVersion ,所以除非你有 compileSDK 版本 23 或更高版本,否则对你来说不是一个问题。
非常好。拯救了我的一天。
嘿@Nicks你能告诉我那个for循环在那里做什么这个for (int i = 0; i < permissions.length; i++)有什么用
M
MLProgrammer-CiM

根据当前示例:https://github.com/googlesamples/android-RuntimePermissions/blob/master/Application/src/main/java/com/example/android/system/runtimepermissions/MainActivity.java#L195

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
        int[] grantResults) {
    if (requestCode == REQUEST_CAMERA) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            doThing();
            //STORE FALSE IN SHAREDPREFERENCES
        } else {
            //STORE TRUE IN SHAREDPREFERENCES
        }
    }

在 SharedPreferences 中存储一个布尔值,其中键作为您的权限代码和值,如上所示,以指示该首选项之前是否已被拒绝。

遗憾的是,您可能无法检查在您的应用程序运行时已被接受但后来被拒绝的首选项。最终规范不可用,但您的应用有可能会重新启动或获取模拟值,直到下一次启动。


“您可能无法检查在您的应用程序运行时已被接受但后来被拒绝的首选项” - 我的印象是设置中权限的更改会导致您的应用程序进程被终止,从而实际上迫使您检查您是否再次拥有权限。正如对该问题的评论中所指出的,我希望在 Android 中有一些适当的机制,以避免数据重复和不同步的风险。谢谢!
我相信针对目标 < M 和 > M 编译的应用程序之间存在不同的行为。您将获得旧版本的模拟值,以及其他版本的 SecurityExceptions。
我尝试了这种机制,但可惜它并没有涵盖所有场景。如果您在应用程序中允许权限,然后转到权限设置并拒绝它,则存储在共享首选项中的布尔值仍然为真(从之前),您需要它为假。 shouldShowRequestPermissionRationale 如果您不打算预先进行教育,那很好,但如果您这样做,那就不好了。应该有一个“shouldEducateUpFront”方法来确定用户之前没有拒绝权限的情况。特别是因为 Google 建议在某些情况下这样做:youtube.com/watch?v=iZqDdvhTZj0
e
ed9er

不,您不需要跟踪您是否请求了许可,也不需要区分 Never-Asked 和 Stop-Asking。

状态 1 和 3 对于应用开发者来说是一样的:你需要权限和 ActivityCompat.checkSelfPermission != PackageManager.PERMISSION_GRANTED,然后你只需通过 ActivityCompat.requestPermissions() 请求权限,每当用户点击需要权限的功能时,无论你有多少次请求。用户最终将“授予”它,或“拒绝”它并选中“不再询问”。该设计不会阻止您多次弹出权限请求对话框。

但是,该设计确实鼓励您在某些时候解释许可的目的 - 您的状态 2。shouldShowRequestPermissionRationale() 不用于确定您是否应该请求许可,它用于确定您是否应该在请求之前显示解释获得许可。

关于状态 3 的更多解释:

是的,我们应该通过停止显示解释来停止打扰用户,而不是停止请求。这就是他们提供 shouldShowRequestPermissionRationale() 的原因。保留许可请求并不麻烦。用户选择“不再询问”后,ActivityCompat.requestPermissions() 将不再弹出对话框。每次我们发现我们没有权限时,最好在单用户会话期间禁用相关的 UI。而不是在 shouldShowRequestPermissionRationale() 返回 false 之后禁用 UI。


“每次我们发现我们没有权限时,最好在单用户会话期间禁用相关 UI。而不是在 shouldShowRequestPermissionRationale() return false 之后禁用 UI”——这是我们分歧的核心。如果我们使用 Google 不禁用 UI 而是显示引导用户进入设置的快餐栏的方法,我们就会遇到类似的问题。不知何故,我们需要知道显示该小吃吧,而直接的解决方案需要我们区分状态 3 和状态 1。
好消息是 shouldShowRequestPermissionRationale() 似乎已经在 onRequestPermissionsResult() 中返回了预期值,因此如果用户以 don't-ask-again 拒绝,shouldShowRequestPermissionRationale() 确实返回 false。因此,如果您想要获得相同的响应(例如,显示一个小吃店),无论用户是再次拒绝还是之前这样做,您都不需要状态 1。如果您想要不同的响应(例如,仅当用户在一段时间前(而不是现在)再次拒绝时才显示小吃栏),您仍然需要状态 1。
@CommonsWare 这绝对有很大帮助!尽管这似乎有点骇人听闻。希望这在未来的版本中仍然有效。
请注意,如果您以前从未显示过权限对话框,则 shouldShowRequestPermissionRationale() 将返回 false,即使用户以前从未拒绝过该权限。所以第一次你应该强制权限对话框,然后你可以依赖它。考虑到这种行为将来可能会改变。
J
Joacer

我有一种方法可以解决您的问题,它似乎对我来说效果很好。

我使用 SharedPreferences 区分 Never-Asked 和 Stop-Asking,我会给你一个我如何使用它的例子。

private void requestAccountPermission() {

        SharedPreferences mPreferences = getSharedPreferences("configuration", MODE_PRIVATE);
        boolean firstTimeAccount = mPreferences.getBoolean("firstTimeAccount", true);

        if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.GET_ACCOUNTS)) {
            // 2. Asked before, and the user said "no"
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.GET_ACCOUNTS}, REQUEST_CODE_ACCOUNTS);
        }else {
            if(firstTimeAccount) { 
                // 1. first time, never asked 
                SharedPreferences.Editor editor = mPreferences.edit();
                editor.putBoolean("firstTimeAccount", false);
                editor.commit();

                // Account permission has not been granted, request it directly.
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.GET_ACCOUNTS},REQUEST_CODE_ACCOUNTS);
            }else{
                // 3. If you asked a couple of times before, and the user has said "no, and stop asking"

                // Your code
            }
        }
    }

ActivityCompat.requestPermissions 不显示点击后不再询问?它进入 else 条件。有没有办法让它再次显示?就像脸书一样。
Y
Yogesh Pareek

这是跟踪第一次显示权限对话框时的方法,当用户检查时不再询问,当权限在用户检查后直接被拒绝时不再询问,我们需要保留一个标志,以便在获取之前是否已显示权限理由对话框导致 onRequestPermissionsResult。需要时调用方法 checkPermission()。

public boolean mPermissionRationaleDialogShown = false;

public void checkPermission() {
    if (ContextCompat.checkSelfPermission(this, "PermissionName")
            != PackageManager.PERMISSION_GRANTED) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, "PermissionName")) {
            showPermissionRequiredDialog();
        } else {
            askPermission();
        }
    } else {
       // Permission Granted
    }
}

public void askPermission() {
    ActivityCompat.requestPermissions(this,
            new String[]{"PermissionName"}, permissionRequestCode);
}

public void showPermissionRequiredDialog() {
    mPermissionRationaleDialogShown = true;
    // Dialog to show why permission is required
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == PERMISSION_REQUEST_CODE) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // Permission Granted
        } else {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, "PermissionName")
                    && !mPermissionRationaleDialogShown) {
                // Permission dialog was shown for first time
            } else if (ActivityCompat.shouldShowRequestPermissionRationale(this, "PermissionName")
                    && mPermissionRationaleDialogShown){
                // User deny permission without Never ask again checked
            } else if (!ActivityCompat.shouldShowRequestPermissionRationale(this, PERMISSION_READ_EXTERNAL)
                    && mPermissionRationaleDialogShown) {
                // User has checked Never ask again during this permission request
            } else {
                // No permission dialog shown to user has user has previously checked Never ask again. Here we can show dialog to open setting screen to change permission
            }
        }
    } else {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

N
Natwar Singh

在尝试了这里的所有答案和互联网上的其他一些帖子之后。我开始知道我必须使用 sharedPreference isLocationPermissionDialogShown(默认为 false),并且每件事都按预期工作。

如果第一次请求许可。在这种情况下 shouldShowRequestPermissionRationale 返回 false 并且 isLocationPermissionDialogShown 也返回 false 第二次 shouldShowRequestPermissionRationale 返回 true 并且在显示对话框时我们将 isLocationPermissionDialogShown 设置为 true。当我们检查条件时,每次都为真,直到不再询问再次勾选 shouldShowRequestPermissionRationale 返回 true 并且 isLocationPermissionDialogShown 返回 true 如果不再询问再次勾选 shouldShowRequestPermissionRationale 返回 false 并且 isLocationPermissionDialogShown 返回 true。这就是我们需要的。

请检查工作示例。

public class MainActivity extends AppCompatActivity {
    SharedPreferences sharedPreferences;
    String locationPermission;
    String prefLocationPermissionKey = "isLocationPermissionDialogShown";
    private final int PERMISSION_REQUEST_CODE_LOCATION = 1001;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        locationPermission = Manifest.permission.ACCESS_FINE_LOCATION;
        sharedPreferences = getSharedPreferences("configuration", MODE_PRIVATE);

        //check for android version
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //Check for permission
            if (checkSelfPermission(locationPermission) != PackageManager.PERMISSION_GRANTED) {
                //check if clarification dialog should be shown.
                if (shouldShowRequestPermissionRationale(locationPermission)) {
                    showClarificationDialog(locationPermission, PERMISSION_REQUEST_CODE_LOCATION);
                } else  {
                    requestPermissions(new String[] { locationPermission}, PERMISSION_REQUEST_CODE_LOCATION);
                }
            } else {
                Log.d("nets-debug", "permission already grranted");
            }
        }

    }

    @Override
    @TargetApi(Build.VERSION_CODES.M)
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

        if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
            //for location permission
            if (requestCode == PERMISSION_REQUEST_CODE_LOCATION) {
                boolean isLocationPermissionDialogShown = sharedPreferences.getBoolean(prefLocationPermissionKey, false);

                if (!shouldShowRequestPermissionRationale(locationPermission) && isLocationPermissionDialogShown) {
                    // user selected Never Ask Again. do something
                    Log.d("nets-debug", "never ask again");
                } else {
                    // all other conditions like first time asked, previously denied etc are captured here and can be extended if required.
                    Log.d("nets-debug", "all other cases");
                }
            }

        }

    }

    @TargetApi(Build.VERSION_CODES.M)
    public void showClarificationDialog(final String permission, final int requestCode) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Permission Required");
        builder.setMessage("Please grant Location permission to use all features of this app");
        builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                SharedPreferences.Editor editor = sharedPreferences.edit();
                editor.putBoolean(prefLocationPermissionKey, true);
                editor.apply();
                requestPermissions(new String[] {permission}, requestCode);
            }
        });
        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(getApplicationContext(), "This permission required", Toast.LENGTH_LONG).show();
            }
        });
        builder.create().show();
    }

}

希望这会有所帮助。


S
Shlomi

关于 MLProgrammer-CiM 的回答,我知道如何解决存储在 SharedPrefrences 中的布尔值已经为真后用户撤销权限的场景,

只需创建另一个常量布尔值,如果第一个调用例如:Constant.FIRST_TIME_REQUEST(其默认状态将为 true),第二个将调用 Constant.PERMISSION_ALREADY_GRANTED(默认为 false)

如果在 onRequestPermissionsResult 上授予权限,您当然可以将其值更改为 true。

现在,在你想通过预先解释请求许可的部分,写下这样的内容:

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
   SharedPreferences sp = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE);
   boolean isPermissionGranted = sp.getBoolean(Constant.PERMISSION_ALREADY_GRANTED, false);
   if (isPermissionGranted) {
      sp.putBoolean(Constant.PERMISSION_ALREADY_GRANTED, false);
      sp.putBoolean(Constant.FIRST_TIME_REQUEST, true);
   }

   if (ActivityCompat.shouldShowRequestPermissionRationale(activity, androidPermissionName) || sp.getBoolean(Constant.FIRST_TIME_REQUEST, true) ) {
   showDialogExplanation();
}
}

这样,即使用户将删除权限,布尔值也会再次设置为 false。

祝你好运,我希望它会有所帮助。

什洛


d
debo.stackoverflow

所以我终于有时间回答来自 COMMONSWARE 的问题了

业务流程:-

1. 当用户第一次点击“拒绝权限”时,我会显示理由对话框来解释权限的必要性。然后,如果用户单击基本原理对话框上的“取消”按钮,我将显示一个 toast 显示消息“请授予获取位置的权限”。

2. 之后,当用户在权限对话框中点击拒绝权限(不要再询问)时,我会显示一条消息“请从应用设置中授予位置权限”。请注意,我添加了“来自应用程序设置”的字样,因为用户已选中“不再询问”框。

3. 所以从现在开始,权限对话框将不再显示。基本原理对话框也不会显示。

所以这里的关键是,如果权限对话框和理由对话框都没有显示,那么这意味着用户已经选中了“不再询问”复选框。

编码:-

        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            if(ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.ACCESS_FINE_LOCATION)){
                AlertDialogHelper.showDialogWithYesNoCallback(mContext, getString(R.string.confirm), getString(R.string.please_give_permission_to_get_location), new onItemClickReturnBoolean() {
                    @Override
                    public void onItemClick(Boolean status) {
                        if(status){
                            ActivityCompat.requestPermissions(SplashScreenActivity.this,permissions,AppConfig.FINE_LOCATION_PERMISSION_REQUEST_CODE);
                        }
                        else{
                            ShowToast.showShortToast(SplashScreenActivity.this,getString(R.string.please_give_permission_to_get_location));
                            finish();
                        }
                    }
                });
            }
            else{
                ActivityCompat.requestPermissions(this,permissions,AppConfig.FINE_LOCATION_PERMISSION_REQUEST_CODE);
            }
        }
        else{
            gettingLocationAfterPermissionGranted();
        }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestCode == AppConfig.FINE_LOCATION_PERMISSION_REQUEST_CODE){
            if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
                gettingLocationAfterPermissionGranted();
            }
            else{
                if(ActivityCompat.shouldShowRequestPermissionRationale(SplashScreenActivity.this,Manifest.permission.ACCESS_FINE_LOCATION)){
                    ShowToast.showShortToast(this,getString(R.string.please_give_permission_to_get_location));
                }
                else{
                    ShowToast.showShortToast(this,getString(R.string.please_give_location_permission_from_app_settings));
                }
                finish();
            }
        }
    }

检查此存储库:https://github.com/debChowdhury/PermissionHelperEasy

十分简单


R
Ronnie

你可以看一下here——有一个流程图很好地解释了这个过程。它还解释了何时应调用 shouldShowRequestPermissionRationale() 以及何时返回 true。

基本上根据Android的文档,如果你没有权限,你应该总是请求权限(如果用户说永远不要再询问,Android会在回调中自动返回DENIED),如果用户已经拒绝,你应该显示一条短消息您过去曾有过一次,但未标记“不再询问”选项。


这并没有解决这个问题。
C
Community

无需为权限状态创建并行持久状态,您可以使用此方法随时返回当前权限状态:

@Retention(RetentionPolicy.SOURCE)
    @IntDef({GRANTED, DENIED, BLOCKED})
    public @interface PermissionStatus {}

    public static final int GRANTED = 0;
    public static final int DENIED = 1;
    public static final int BLOCKED = 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;
            }
            return DENIED;
        }
        return GRANTED;
    }

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

I also used this answered here.


这将在第一次用例中失败,如果您从未向用户请求权限,您的方法 getPermissionStatus 将错误地返回 BLOCKED,这实际上是不正确的。在这个设计中需要第 4 个状态,可能称为 HAVENT_ASKED,检测它的唯一方法是使用共享首选项或类似的东西。
是的,对于某些用例可能仍然有用;我真的不喜欢使用共享首选项跟踪并行状态