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一起发生?
为什么会这样呢?
您正在检查错误的权限.错误说你需要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,系统会立即授予该权限,而不会提示用户.