日历提供程序:Android 8上的权限拒绝

jer*_*rry 2 java android android-calendar android-permissions android-8.0-oreo

我在使用日历提供程序时遇到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()
Run Code Online (Sandbox Code Playgroud)

令我困惑的是,即使系统在运行时请求持久性,它们也会被用户确认,并且可以在系统设置中验证崩溃.甚至在访问之前检查权限(参见下面的代码)也无济于事.访问被确认 - 然后被拒绝.

在我的AndroidManifest中:

<manifest ...>
    <uses-permission android:name="android.permission.READ_CALENDAR" />
    <uses-permission android:name="android.permission.WRITE_CALENDAR" />
    <application>
        ...
    </application>
</manifest>
Run Code Online (Sandbox Code Playgroud)

作为示例(对于其他查询也会出现问题),我使用此方法创建日历:

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();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

Com*_*are 9

为什么会这样呢?

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

为什么它似乎开始发生在Android版本8?

他们加强了安全性.引用文档:

在Android 8.0(API级别26)之前,如果应用程序在运行时请求了权限并且授予了权限,则系统也会错误地授予应用程序其他属于同一权限组的权限,并且已在表现.

对于定位到Android 8.0的应用,此行为已得到纠正.该应用程序仅被授予其明确请求的权限.但是,一旦用户向应用程序授予权限,则会自动授予该权限组中所有后续权限请求.

例如,假设一个应用程序同时列出READ_EXTERNAL_STORAGE,并WRITE_EXTERNAL_STORAGE在其清单.应用程序请求READ_EXTERNAL_STORAGE和用户授予它.如果应用程序的目标是API级别25或更低,系统也会同时授予WRITE_EXTERNAL_STORAGE,因为它属于同一个STORAGE权限组,并且也在清单中注册.如果该应用针对Android 8.0(API级别26),则系统仅READ_EXTERNAL_STORAGE在此时授予; 但是,如果应用程序稍后请求WRITE_EXTERNAL_STORAGE,系统会立即授予该权限,而不会提示用户.