【问题标题】:checkSelfPermission 方法在 targetSdkVersion 22 中不起作用
【发布时间】:2016-01-29 04:23:03
【问题描述】:

CheckSelfPermission 方法没有按预期工作,它在 android 6.0(Marshmallow) 中总是返回零。因为目标 sdk 是 22 并且我使用 http Client 进行网络连接。以下是代码sn-p。

private void insertDummyContactWrapper() {
    List<String> permissionsNeeded = new ArrayList<String>();

    final List<String> permissionsList = new ArrayList<String>();
    if (!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION))
        permissionsNeeded.add("GPS");
    if (!addPermission(permissionsList, Manifest.permission.READ_CONTACTS))
        permissionsNeeded.add("Read Contacts");
    if (!addPermission(permissionsList, Manifest.permission.WRITE_CONTACTS))
        permissionsNeeded.add("Write Contacts");

    if (permissionsList.size() > 0) {
        if (permissionsNeeded.size() > 0) {
            // Need Rationale
            String message = "You need to grant access to " + permissionsNeeded.get(0);
            for (int i = 1; i < permissionsNeeded.size(); i++)
                message = message + ", " + permissionsNeeded.get(i);
            showMessageOKCancel(message,
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                                    REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
                        }
                    });
            return;
        }
        requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
        return;
    }

    insertDummyContact();
}

@TargetApi(Build.VERSION_CODES.M)
private boolean addPermission(List<String> permissionsList, String permission) {
    if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
        permissionsList.add(permission);
        // Check for Rationale Option
        if (!shouldShowRequestPermissionRationale(permission)) return false;
    }
    return true;
}

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

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS: {
            Map<String, Integer> perms = new HashMap<String, Integer>();
            // Initial
            perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
            perms.put(Manifest.permission.READ_CONTACTS, PackageManager.PERMISSION_GRANTED);
            perms.put(Manifest.permission.WRITE_CONTACTS, PackageManager.PERMISSION_GRANTED);
            // Fill with results
            for (int i = 0; i < permissions.length; i++)
                perms.put(permissions[i], grantResults[i]);
            // Check for ACCESS_FINE_LOCATION
            if (perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && perms.get(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED && perms.get(Manifest.permission.WRITE_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
                // All Permissions Granted
                insertDummyContact();
            } else {
                // Permission Denied
                Toast.makeText(MainActivity.this, "Some Permission is Denied", Toast.LENGTH_SHORT)
                        .show();
            }
        }
        break;
        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}"

【问题讨论】:

标签: android android-permissions


【解决方案1】:
  1. 如果您的应用程序的目标是 API 级别早于 23 (Android M),那么两者都: ContextCompat#checkSelfPermissionContext#checkSelfPermission 将不起作用并始终返回 0 (PERMISSION_GRANTED)。即使您在 Android 6.0 (API 23) 上运行应用程序。

  2. 如果您以 23 之前的 API 级别为目标,那么您不必处理权限,这并不完全正确。如果您的应用针对 23 之前的 API 级别并且目标设备 Android 版本是:

    • Android 一切都会好的。
    • Android 6.0:默认会授予应用程序的运行时权限(兼容模式适用),用户可以在Android设置中更改运行时权限,那么你可能有问题。
  3. 正如我在第一点所说,如果您在 Android 6.0 上针对 23 之前的 API 级别,那么 ContextCompat#checkSelfPermissionContext#checkSelfPermission 将不起作用。 幸运的是,您可以使用PermissionChecker#checkSelfPermission 来检查运行时权限。

示例代码:

    public boolean selfPermissionGranted(String permission) {
        // For Android < Android M, self permissions are always granted.
        boolean result = true;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            
            if (targetSdkVersion >= Build.VERSION_CODES.M) {
                // targetSdkVersion >= Android M, we can
                // use Context#checkSelfPermission
                result = context.checkSelfPermission(permission)
                        == PackageManager.PERMISSION_GRANTED;
            } else {
                // targetSdkVersion < Android M, we have to use PermissionChecker
                result = PermissionChecker.checkSelfPermission(context, permission)
                        == PermissionChecker.PERMISSION_GRANTED;
            }
        }

        return result;
    }

要获取目标 SDK 版本,您可以使用:

    try {
        final PackageInfo info = context.getPackageManager().getPackageInfo(
                context.getPackageName(), 0);
        targetSdkVersion = info.applicationInfo.targetSdkVersion;
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }

它适用于带有 Android M 的 Nexus 5。

【讨论】:

  • 如果您的目标不是至少 SDK 23,那么使用 PermissionChecker#checkSelfPermission 有什么意义?当面向 SDK 22 或更低版本时,即使在 SDK 23 设备上,也始终授予权限。
  • 安装后会自动授予权限,但用户可以在安装后关闭运行时权限。这就是我们要检查是否授予权限的原因。
  • @MikePtr 如果目标小于 23 并且在 23 上运行,请求权限是否安全?请求许可的正常方式会起作用吗?
  • 我不明白为什么我们必须在我们的代码中创建一个 fork 或者记得根据目标 SDK 从 PermissionChecker 更新到 ContextCompat,当您的应用针对 SDK 23 时 PermissionChecker 会停止正常工作吗?
  • 这应该是公认的答案,因为它更全面,也是处理 PermissionChecker 方案的唯一答案。谢谢!
【解决方案2】:

针对 23 之前的 API 级别时,将应用兼容模式。旧的权限行为正在运行,即使在运行 Android 6 的设备上也是如此。要使用新的权限系统,您必须以 API 23(或未来更高版本)为目标。

文档中指定了完整的行为:https://developer.android.com/training/permissions/requesting.html

【讨论】:

    【解决方案3】:

    Context#checkSelfPermission(String) 方法已添加到 API 23。同样在 API 23 以下,它是毫无意义的,因为总是授予权限。在处理权限之前检查 API 版本

    private void insertDummyContactWrapper() {
        // the only way we insert the dummy contact if if we are below M.
        // Else we continue on and prompt the user for permissions
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            insertDummyContact();
            return;
        }
    
        List<String> permissionsNeeded = new ArrayList<String>();
    
        final List<String> permissionsList = new ArrayList<String>();
        if (!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION))
            permissionsNeeded.add("GPS");
        if (!addPermission(permissionsList, Manifest.permission.READ_CONTACTS))
            permissionsNeeded.add("Read Contacts");
        if (!addPermission(permissionsList, Manifest.permission.WRITE_CONTACTS))
            permissionsNeeded.add("Write Contacts");
        if (permissionsList.size() > 0) {
            if (permissionsNeeded.size() > 0) {
                // Need Rationale
                String message = "You need to grant access to " + permissionsNeeded.get(0);
                for (int i = 1; i < permissionsNeeded.size(); i++)
                    message = message + ", " + permissionsNeeded.get(i);
                showMessageOKCancel(message,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                                        REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
                            }
                        });
                return;
            }
            requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                    REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
        }
    }
    

    参考:http://developer.android.com/reference/android/content/Context.html#checkSelfPermission(java.lang.String)

    【讨论】:

    • 好吧,您提供的链接根本没有指定它不应该在 API checkPermission (String permission, int pid, int uid)。
    • 该链接显示 checkSelfPermission 在 API 23 之前不存在。如果它链接,则无关紧要,因为该方法永远不会在 API 23 以下执行任何操作。无论您做什么,运行时权限都会在 23 以下不起作用。在进行任何权限处理之前检查至少 23 的 API。您永远不会获得运行时权限以在 23 岁以下工作。
    • 好吧,我刚刚重新阅读了我的评论,今天早上我确实没有醒来。实际上,该方法只会在 API checkSelfPermission (developer.android.com/reference/android/support/v4/content/…)。这个有效(并且总是在 API PERMISSION_GRANTED)。
    • @Kernald,啊,好吧,我不知道你在使用支持库。那么问题解决了吗?
    • 我不是发布问题的人,只是在早上太早阅读并评论了您的答案;-)
    猜你喜欢
    • 1970-01-01
    • 2020-04-23
    • 1970-01-01
    • 1970-01-01
    • 2021-01-20
    • 2016-07-20
    • 1970-01-01
    • 1970-01-01
    • 2022-08-03
    相关资源
    最近更新 更多