日历提供商:Android 8 上的权限被拒绝

Calendar Provider: Permission Denial on Android 8

我在 Oreo Android 8.0/8.1 设备上使用日历提供程序时遇到应用崩溃问题。我的设备 运行 Nougat 及以下设备没有显示该问题。

Permission Denial: reading com.android.providers.calendar.CalendarProvider2 uri content://com.android.calendar/calendars from pid=8522, uid=10197 requires android.permission.READ_CALENDAR, or grantUriPermission()

让我疑惑的是,即使系统在运行时请求权限,用户确认,并且可以在系统设置中验证,也会发生崩溃。即使在访问前检查权限(请参阅下面的代码)也无济于事。访问被确认 - 然后被拒绝。

在我的Android清单中:

<manifest ...>
    <uses-permission android:name="android.permission.READ_CALENDAR" />
    <uses-permission android:name="android.permission.WRITE_CALENDAR" />
    <application>
        ...
    </application>
</manifest>

举个例子(其他查询也会出现这个问题),我用这个方法创建了一个日历:

public static void createCalendarIfNotExists(android.app.Activity activity) throws SecurityException {

    ContentResolver contentResolver = activity.getContentResolver();

    // Check if calendar already exists.
    String[] projection = new String[]{
                    CalendarContract.Calendars._ID,
                    CalendarContract.Calendars.CALENDAR_DISPLAY_NAME};

    if (ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_CALENDAR) == PackageManager.PERMISSION_GRANTED) {
        Cursor cursor = contentResolver.query(CalendarContract.Calendars.CONTENT_URI,
                projection,
                CalendarContract.Calendars.CALENDAR_DISPLAY_NAME + " = ?",
                new String[]{CALENDAR_NAME},
                null);

        if (cursor != null) {
            if (cursor.getCount() == 0) {
                final ContentValues cv = buildNewCalContentValues(activity);
                Uri calUri = buildCalUri();
                // Insert the calendar into the database.
                contentResolver.insert(calUri, cv);
            }
            if (!cursor.isClosed()) {
                cursor.close();
            }
        }
    }
}

尽管检查结果为 GRANTED 的日历权限,但由于缺少权限,查询失败(权限请求在此函数之外完成,但在 运行 查询之前在此验证权限)。

为什么会发生这种情况,为什么它似乎从 Android 版本 8 开始发生?

Why is this happening

您检查的权限有误。错误说你需要 READ_CALENDAR;您正在检查 WRITE_CALENDAR。虽然您没有显示 requestPermissions() 调用,但我猜您只是在请求 WRITE_CALENDAR.

why does it seem to start happening with Android Version 8?

他们加强了安全措施。引用 the documentation:

Prior to Android 8.0 (API level 26), if an app requested a permission at runtime and the permission was granted, the system also incorrectly granted the app the rest of the permissions that belonged to the same permission group, and that were registered in the manifest.

For apps targeting Android 8.0, this behavior has been corrected. The app is granted only the permissions it has explicitly requested. However, once the user grants a permission to the app, all subsequent requests for permissions in that permission group are automatically granted.

For example, suppose an app lists both READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE in its manifest. The app requests READ_EXTERNAL_STORAGE and the user grants it. If the app targets API level 25 or lower, the system also grants WRITE_EXTERNAL_STORAGE at the same time, because it belongs to the same STORAGE permission group and is also registered in the manifest. If the app targets Android 8.0 (API level 26), the system grants only READ_EXTERNAL_STORAGE at that time; however, if the app later requests WRITE_EXTERNAL_STORAGE, the system immediately grants that privilege without prompting the user.

同样的权限我也有同样的异常,但是我不明白解决方法

我的应用程序在清单中请求 READ_CALENDAR 权限,我在第一次启动应用程序时授予了权限。

我有这个例外:

java.lang.SecurityException: Permission Denial: reading com.android.providers.calendar.CalendarProvider2 uri content://com.android.calendar/calendars

我错过了什么?

在我的清单中,我有:

    <uses-permission android:name="android.permission.READ_CALENDAR" />
    <uses-permission android:name="android.permission.WRITE_CALENDAR" />

执行时出现异常:

        Cursor cur;
        ContentResolver cr = getContentResolver();
        Uri uri = Calendars.CONTENT_URI;
        cur = cr.query(uri, EVENT_PROJECTION, null, null, null);

(最后一行例外)