【问题标题】:Calendar Provider: Permission Denial on Android 8日历提供程序:Android 8 上的权限拒绝
【发布时间】:2017-12-17 12:18:04
【问题描述】:

在使用日历提供程序时,我在 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()

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

在我的 AndroidManifest 中:

<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 开始发生?

【问题讨论】:

    标签: java android android-permissions android-calendar android-8.0-oreo


    【解决方案1】:

    为什么会这样

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

    为什么它似乎从 Android 版本 8 开始出现?

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

    在 Android 8.0(API 级别 26)之前,如果应用在运行时请求权限并且该权限被授予,系统也会错误地授予该应用属于同一权限组的其余权限,并且在清单中注册。

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

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

    【讨论】:

    • 谢谢。这完全有道理。我确实假设,和以前一样,写权限包括读权限。有很多关于 API 23 更改的信息,所以我一定是不知何故错过了这些信息。我会尝试相应地更新我的应用,然后让你知道(接受答案)。
    • @jerry:“我确实假设,和以前一样,写权限包括读权限”——在 Android 6.0 和切换到运行时权限模型 AFAIK 之前,写 did i> 暗示阅读。 Android 6.0 打破了这一点……但由于他们将权限放在同一个组中,因此您最终得到的代码仍然有效。现在,我们必须更具体地了解我们想要的权限。用户体验没有改变——用户没有得到更多的权限确认对话框。
    【解决方案2】:

    同样的权限我有同样的例外,但我不明白解决方案。

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

    我有这个例外:

    java.lang.SecurityException: Permission Denial: 读取 com.android.providers.calendar.CalendarProvider2 uri 内容://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);
    

    (最后一行的异常)

    【讨论】:

    • 我不知道为什么,但是在尝试了几次清理和重建之后,我的应用程序又可以正常工作了。所以这对我来说很神秘......
    • 很高兴你解决了它。我建议您将后续问题或澄清请求作为新问题或作为对您所指答案的评论发布。这样更有可能得到回应。
    猜你喜欢
    • 2018-10-28
    • 2015-11-17
    • 1970-01-01
    • 1970-01-01
    • 2014-08-19
    • 2019-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多