В рамках нашей цели по постоянному улучшению нашего приложения мы решили пересмотреть разрешения и постараться уменьшить количество элементов, которые мы просим наших пользователей одобрить.
Android не помог делу благодаря своей старой модели разрешений. То, что было введено в M aka Marshmallow, является значительным улучшением для пользователей и разработчиков. Он предлагает разработчикам возможность объяснить пользователям, почему и что мы просим от них в отношении доступа к их устройствам и / или данным.
Но хватит обсуждения Android и модели разрешений. Давайте посмотрим на проблему. Мы добавили FileProvider в наше приложение, чтобы контролировать доступ к файлам в наше приложение и из него.
Проблема заключалась в том, что при завершении действия по фотосъемке приложение «Камера / Галерея» вылетало из строя и вызывалась функция onActivityResult.
java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{423c0ad0 13416:com.google.android.gallery3d/u0a10020} (pid=13416, uid=10020) that is not exported from uid 10079
Пример определения Support v4 FileProvider выглядит следующим образом:
<manifest> ... <application> ... <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.mydomain.fileprovider" android:exported="false" android:grantUriPermissions="true"> ... </provider> ... </application> </manifest>
Наивным подходом было бы просто обновить определение FileProvider и установить для атрибута XML export значение true. Это приведет к другому SecurityException.
В конце концов, после долгих размышлений и поисков души я решил попробовать следующий метод, который предоставляется в объекте Context grantUriPermission и revokeUriPermission. .
Решение: предоставьте возможным приложениям разрешение на URI, чтобы завершить действие. В следующем фрагменте кода показано использование PackageManager для поиска действий, которые будут отвечать на ACTION_IMAGE_CAPTURE
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); List<ResolveInfo> resolvedIntentActivities = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); for (ResolveInfo resolvedIntentInfo : resolvedIntentActivities) { String packageName = resolvedIntentInfo.activityInfo.packageName; context.grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); }
Точно так же необходимо отозвать доступ после того, как вы закончите полагаться на URI.
context.revokeUriPermissionfileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
Я надеюсь, что следующее поможет другим, кто чешет голову и задается вопросом, что же, черт возьми, происходит.
Я приветствую отзывы о формате и моем сообщении о проблеме, я всегда стремлюсь усовершенствовать искусство обмена знаниями.