Борьба с разрешением WRITE_EXTERNAL_STORAGE для Android во время выполнения - PullRequest
0 голосов
/ 22 ноября 2018

У меня есть фрагмент.В этом фрагменте я использую onActivityResult () , чтобы поймать намерение, когда пользователь выбирает выбрать фотографию и импортировать эту фотографию в мое приложение:

Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CAMERA) {
        if (resultCode == Activity.RESULT_OK) {
            Uri takenPhotoUri = ImageUtils.getInstance().getPhotoFileUri(getContext(), imageFileName);
            actionsListener.onSignalPhotoSelected(takenPhotoUri.getPath());
        }
    }

    if (requestCode == REQUEST_GALLERY && resultCode == Activity.RESULT_OK && data != null && data.getData() != null) {

        Uri fileUri = data.getData();
        String path = null;
        File photoFile = new File(fileUri.toString());

        // Differentiate between SDK versions
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

            // Code for Android 6 and > goes here
            if(getActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                //showPermissionDialog(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE_FOR_CLOUDE);
                ActivityCompat.requestPermissions(getActivity(), new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE_FOR_CLOUDE);
            }
            try {
                ParcelFileDescriptor parcelFileDesc = getActivity().getContentResolver().openFileDescriptor(fileUri, "r");
                FileDescriptor fileDesc = parcelFileDesc.getFileDescriptor();
                Bitmap photo = BitmapFactory.decodeFileDescriptor(fileDesc);
                path = MediaStore.Images.Media.insertImage(getContext().getContentResolver(), photo, "temp", null);
                parcelFileDesc.close();

                // DRY!!
                photoFile = ImageUtils.getInstance().getFromMediaUri(getContext(), getContext().getContentResolver(), Uri.parse(path));

            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        else {
            // DRY!!
            photoFile = ImageUtils.getInstance().getFromMediaUri(getContext(), getContext().getContentResolver(), data.getData());
        }
        if(photoFile != null) {
            actionsListener.onSignalPhotoSelected(Uri.fromFile(photoFile).getPath());
        }
    }

    if (requestCode == REQUEST_SIGNAL_DETAILS) {
        if (resultCode == Activity.RESULT_OK) {
            Signal signal = data.getParcelableExtra("signal");
            if (signal != null) {
                actionsListener.onSignalStatusUpdated(signal);
            }
        }
    }
}

Моя проблема заключается в следующем: когдапользователь выбирает фотографию из Google Фото (фотография, которая существует только в облаке, и она не была загружена локально), мое приложение вылетает со следующей ошибкой:

E / MediaStore: Не удалось вставить изображение java.lang.SecurityException: Отказ в разрешении: запись com.android.providers.media.MediaProvider uri content: // media / external / images / media из pid = 9851, uid = 10091 требует android.permission.WRITE_EXTERNAL_STORAGEили grantUriPermission () в android.os.Parcel.readException (Parcel.java:1943) в android.database.DatabaseUtils.readExceptionFromParcel (DatabaseUtils.java:183) в android.database.DatabaseUtils.readExceptionFromParcel (DatabaseUtils.java:135)на android.content.ContentProviderProxy.insert (ContentProviderNative.java:476) на android.content.ContentResolver.insОшибка.v4.app.FragmentActivity.onActivityResult (FragmentActivity.java:151) в android.app.Activity.dispatchActivityResult (Activity.java:7235) в android.app.ActivityThread.deliverResults (ActivityThread.java:4320) в android.app.ActivityThread.handleSendResult (ActivityThread.java:4367) на android.app.ActivityThread.-wrap19 (неизвестный источник: 0) на android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1649) на android.os.Handler.dispatchMessage(Handler.java:105) в android.os.Looper.loop (Looper.java:164) в android.app.ActivityThread.main (ActivityThread.java:6541) в java.lang.reflect.Method.invoke (собственный метод) на com.android.internal.os.Zygote $ MethodAndArgsCaller.run (Zygote.java:240) на com.android.internal.os.ZygoteInit.main (ZygoteInit.java:767) D / AndroidRuntime: Завершение работы виртуальной машины E / AndroidRuntime: ИСКЛЮЧИТЕЛЬНОЕ ИСКЛЮЧЕНИЕ: основной процесс: org.helpapaw.helpapaw, PID: 9851 java.lang.RuntimeException: сбой при доставке результата ResultInfo {who = null, request = 196611, result = -1, data = Intent{dat = content: //com.google.android.apps.photos.contentprovider/0/1/mediakey: / local% 3Aabc88a06-d518-4fae-b85d-73f727595a90 / ORIGINAL / NONE / 1144559444 flg = 0x1 clip = {text/ uri-list U: content: //com.google.android.apps.photos.contentprovider/0/1/mediakey%3A%2Flocal%253Aabc88a06-d518-4fae-b85d-73f727595a90/ORIGINAL/NONE/1144559444}}}к действию(ActivityThread.java:4367) в android.app.ActivityThread.-wrap19 (неизвестный источник: 0) в android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1649) в android.os.Handler.dispatchMessage (обработчик.Java: 105) в android.os.Looper.loop (Looper.java:164) в android.app.ActivityThread.main (ActivityThread.java:6541) в java.lang.reflect.Method.invoke (собственный метод) в com.android.internal.os.Zygote $ MethodAndArgsCaller.run (Zygote.java:240) в com.android.internal.os.ZygoteInit.main (ZygoteInit.java:767) Вызывается: java.lang.NullPointerException: uriString at android.net.Uri $ StringUri. (Uri.java:476) на android.net.Uri $ StringUri. (Неизвестный источник: 0) на android.net.Uri.parse (Uri.java:438) на org.helpapaw.helpapaw.signalsmap.SignalsMapFragment.onActivityResult (SignalsMapFragment.java:742)на android.support.v4.app.FragmentActivity.onActivityResult (FragmentActivity.java:151) на android.app.Activity.dispatchActivityResult (Activity.java:7235) на android.app.ActivityThread.deliverResults (ActivityThread.java:4320) наandroid.app.ActivityThread.handleSendResult (ActivityThread.java:4367) в android.app.ActivityThread.-wrap19 (неизвестный источник: 0) в android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1649) в android.os.Handler.dispatchMessage (Handler.java:105) на android.os.Looper.loop (Looper.java:164) на android.app.ActivityThread.main (ActivityThread.java:6541) на java.lang.reflect.Method.invoke (собственный метод) на com.android.internal.os.Zygote $ MethodAndArgsCaller.run (Zygote.java:240) на com.android.internal.os.ZygoteInit.main (ZygoteInit.java:767)

Первая строка этой ошибки заставляет меня думать об ошибке разрешения WRITE_TO_EXTERNAL:

E / MediaStore: Не удалось вставить изображение java.lang.SecurityException: Отказ в разрешении: запись com.android.providers.media.MediaProvider uri content: // media / external / images / media из pid = 9851, uid = 10091 требует android.permission.WRITE_EXTERNAL_STORAGE или grantUriPermission ()

Поэтому я проверяючтобы убедиться, что для этой версии API требуется разрешение «во время выполнения» (как вы можете видеть в приведенном выше коде), а строка:

ActivityCompat.requestPermissions(getActivity(), new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE_FOR_CLOUDE);

получает удар, но на экране не появляется диалоговое окно подтверждения.Еще один интересный факт: ошибка возникает только при первом запуске приложения (на API 8.0) и отлично работает на 5.1, 6.0, 7.1 и 8.1, но вылетает на 8.0 (эмулятор).Что мне не хватает?

1 Ответ

0 голосов
/ 11 декабря 2018

Для тех, кто борется с чем-то подобным;ключ в том, чтобы запросить все необходимые разрешения одновременно, используя (в моем случае) метод Fragment.requestPermissions(String[] permissions, int requestCode);.Этот метод позволяет передавать массив разрешений в свой первый параметр:

    String[] permissions = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};
        if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED &&
                ContextCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(permissions, READ_WRITE_EXTERNAL_STORAGE_FOR_GALLERY);
}
  • Что я хотел бы знать:

    после того, как новое действие вызвано намерением,будь то фотоаппарат или фотогалерея;попытка запросить у пользователя разрешения больше не работает;смысл: когда камера или фотогалерея открыты, мы теряем контекст нашего собственного приложения и поэтому не можем больше запрашивать у пользователя разрешения.Крайне важно, чтобы все разрешения запрашивались за до , когда пользователь покидает наше приложение (в моем случае использование массива было необходимо для запроса разрешений как на чтение, так и на запись во внешнее хранилище. Запросите все необходимые разрешения нав то же время, прежде чем пользователь покинет текущий контекст, а затем перенаправит на новую активность через намерение.

Надеюсь, это кому-нибудь поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...