SAF — отправить файл по почте после создания с помощью ACTION_CREATE_DOCUMENT

Я обновил targetSdkVersion до 30, поэтому мне пришлось обновить файл создания с помощью SAF (инфраструктура доступа к хранилищу).

Я смог создать файл, выбрать местоположение, получить в результате Uri (он имеет форму содержимого://), но когда я пытаюсь отправить файл как вложение, файл не прикрепляется. Например, Gmail показывает мне сообщение «Невозможно прикрепить файл».

Я что-то упускаю?

Любая помощь будет оценена по достоинству. Спасибо всем

Вот мой код:


int WRITE_REQUEST_CODE = 336;

    private void createFile() {
        Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("application/pdf");
        intent.putExtra(Intent.EXTRA_TITLE, "dettaglio_utente.pdf");
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        startActivityForResult(intent, WRITE_REQUEST_CODE);
    }

    private void alterDocument(Uri uri) {
        try {
            ParcelFileDescriptor pfd = getContentResolver().
                    openFileDescriptor(uri, "w");
            FileOutputStream fileOutputStream =
                    new FileOutputStream(pfd.getFileDescriptor());
            byte[] pdfAsBytes = Base64.decode(pdfBase64, 0);
            fileOutputStream.write(pdfAsBytes);
            // Let the document provider know you're done by closing the stream.
            fileOutputStream.close();
            pfd.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if (resultCode == RESULT_OK && requestCode == WRITE_REQUEST_CODE) {
            try {

                if (data != null && data.getData() != null) {
                    Uri path = data.getData();
                    alterDocument(path);

                    Intent intent = new Intent(Intent.ACTION_SEND);
                    intent.setData(Uri.parse("mailto:")); // only email apps should handle this
                    intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.privacy_mail_subject));
                    intent.putExtra(Intent.EXTRA_TEXT, getString(R.string.privacy_mail_body));
                    intent.putExtra(Intent.EXTRA_STREAM, path);
                    if (intent.resolveActivity(getPackageManager()) != null) {
                        startActivity(intent);
                    }
                }
            } catch (Exception e) {
                Toast.makeText(this, "something went wrong" + e.getMessage(), Toast.LENGTH_SHORT).show();
                e.printStackTrace();
            }
        }
    }

Я также добавил DocumentProvider в манифест, как указано в документации Android StorageProvider.

<provider
            android:name=".MyDocumentProvider"
            android:authorities="${applicationId}.documents"
            android:enabled="true"
            android:exported="true"
            android:grantUriPermissions="true"
            android:permission="android.permission.MANAGE_DOCUMENTS">
            <intent-filter>
                <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
            </intent-filter>
        </provider>

person roccocullo    schedule 12.12.2020    source источник


Ответы (1)


Вы добавляете FLAG_GRANT_READ_URI_PERMISSION и/или FLAG_GRANT_READ_URI_PERMISSION, когда предоставляете Uri кому-то другому.

Итак, что касается вашего кода:

  • Вы можете удалить intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); из метода createFile(), так как хотите получить Uri

  • Вам нужно добавить intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); к вашему ACTION_SEND Intent, прежде чем использовать этот Intent, поскольку вы хотите предоставить Uri и хотите, чтобы получатель мог прочитать содержимое, указанное этим Uri

Также:

  • Удалите android:permission="android.permission.MANAGE_DOCUMENTS" из <provider>, так как другое приложение (например, Gmail), скорее всего, не будет иметь этого разрешения.

  • Обратите внимание, что resolveActivity() может не работать на Android 11+ без добавления элемента <queries> в ваш манифест — вы можете пропустить вызов resolveActivity() и просто обернуть вызов startActivity() в try/catch и разобраться с ActivityNotFoundException

person CommonsWare    schedule 12.12.2020
comment
Спасибо за ответ @CommonsWare. Я удалил android:permission="android.permission.MANAGE_DOCUMENTS", но при запуске выдал исключение SecurityException. Итак, я решил это следующим образом: я удалил весь узел <provider> из манифеста, затем я удалил следующую строку из намерения электронной почты intent.setData(Uri.parse("mailto:")); и заменил ее на intent.setType("message/rfc822"); Теперь это работает!! - person roccocullo; 12.12.2020