Я пытаюсь использовать FileProvider для совместного использования файла MP3, хранящегося в необработанной папке внутреннего хранилища моего приложения, и позволяю пользователю использовать приложение для прослушивания аудио по своему выбору, чтобы открыть общий файл MP3.
Однако с моим написанным кодом я получаю исключение FileNotFoundException, когда пытаюсь выполнить намерение с URI контента, прикрепленным в качестве данных. Это приводит к сбою всего остального в системе FileProvider.
Я создал MediaPlayer и без проблем открыл файл MP3, которым я хочу поделиться, поэтому я знаю, что файл существует и что мое приложение может получить к нему доступ.
При отладке я заметил, что путь URI содержимого, похоже, избавляется от каталога /files/, хотя он находится в файле, для которого я использую getUriFromFile:
Файл медитации: /data/user/0/com.example.selfcareapplication/files/raw/breathing_meditation.mp3
mediaFileContentUri: content://com.example.selfcareapplication.fileprovider/raw/breathing_meditation.mp3
Вот мой код в моем файле манифеста:
<provider
android:name = "android.support.v4.content.FileProvider"
android:authorities = "com.example.selfcareapplication.fileprovider"
android:exported = "false"
android:grantUriPermissions = "true">
<meta-data
android:name = "android.support.FILE_PROVIDER_PATHS"
android:resource = "@xml/file_paths" />
</provider>
Вот код, в котором я пытаюсь использовать FileProvider:
Intent openMeditationFileIntent = new Intent(Intent.ACTION_VIEW);
File meditationPath = new File(this.getFilesDir(), "raw");
File meditationFile = new File(meditationPath, "breathing_meditation.mp3");
Uri meditationFileContentUri = FileProvider.getUriForFile(this.getApplicationContext(), "com.example.selfcareapplication.fileprovider", meditationFile);
openMeditationFileIntent.setData(meditationFileContentUri);
openMeditationFileIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (openMeditationFileIntent.resolveActivity(getPackageManager()) != null) {
startActivity(openMeditationFileIntent);
} else {
Log.d(LOG_TAG, "Could not resolve activity");
}
Вот журнал, который я получаю, когда пытаюсь запустить намерение с прикрепленным URI контента:
2019-04-06 11:45:35.709 4972-4972/? D/MusicLifecycle: com.google.android.music.ui.playback.AudioPreviewActivity generated event: Activity created
2019-04-06 11:45:35.752 4972-4972/? W/MediaPlayer: Couldn't open content://com.example.selfcareapplication.fileprovider/raw/breathing_meditation.mp3: java.io.FileNotFoundException: open failed: ENOENT (No such file or directory)
2019-04-06 11:45:35.761 1844-2504/? W/ActivityManager: Permission Denial: opening provider android.support.v4.content.FileProvider from (null) (pid=1694, uid=1013) that is not exported from UID 10092
2019-04-06 11:45:35.766 1694-1776/? E/MediaPlayerService: Couldn't open fd for content://com.example.selfcareapplication.fileprovider/raw/breathing_meditation.mp3
2019-04-06 11:45:35.766 4972-4972/? E/MediaPlayerNative: Unable to create media player
2019-04-06 11:45:35.768 4972-4972/? D/AudioPreviewActivity: Failed to open file: java.io.IOException: setDataSource failed.: status=0x80000000
2019-04-06 11:45:35.810 1584-1626/? D/gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 376832
2019-04-06 11:45:35.818 1584-1626/? D/gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 376832
2019-04-06 11:45:35.820 1584-1626/? D/gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 376832
2019-04-06 11:45:35.847 4972-4999/? D/EGL_emulation: eglMakeCurrent: 0xea7c5e60: ver 2 0 (tinfo 0xea7b1a10)
2019-04-06 11:45:35.901 4972-4972/? D/MusicLifecycle: com.google.android.music.ui.MusicUrlHandlerActivity generated event: Activity stopped
2019-04-06 11:45:35.931 4972-4972/? D/MusicLifecycle: com.google.android.music.ui.MusicUrlHandlerActivity generated event: Activity destroyed
2019-04-06 11:45:35.939 1684-2170/? D/gralloc_ranchu: gralloc_unregister_buffer: exiting HostConnection (is buffer-handling thread)
2019-04-06 11:45:35.941 1684-2170/? D/gralloc_ranchu: gralloc_unregister_buffer: exiting HostConnection (is buffer-handling thread)
2019-04-06 11:45:35.943 1684-2170/? D/gralloc_ranchu: gralloc_unregister_buffer: exiting HostConnection (is buffer-handling thread)
2019-04-06 11:45:35.944 1684-2170/? D/gralloc_ranchu: gralloc_unregister_buffer: exiting HostConnection (is buffer-handling thread)
2019-04-06 11:45:35.968 1844-3656/? I/MediaFocusControl: abandonAudioFocus() from uid/pid 10069/4972 clientId=android.media.AudioManager@32b5d4dcom.google.android.music.ui.playback.AudioPreviewActivity@6726002
2019-04-06 11:45:35.969 4972-4972/? D/MusicLifecycle: com.google.android.music.ui.playback.AudioPreviewActivity generated event: Activity destroyed
2019-04-06 11:45:36.091 1844-2247/? I/GnssLocationProvider: WakeLock acquired by sendMessage(REPORT_SV_STATUS, 0, com.android.server.location.GnssLocationProvider$SvStatusInfo@9a951f4)
2019-04-06 11:45:36.092 1844-1857/? I/GnssLocationProvider: WakeLock released by handleMessage(REPORT_SV_STATUS, 0, com.android.server.location.GnssLocationProvider$SvStatusInfo@9a951f4)
2019-04-06 11:45:36.175 4775-4775/? E/GoogleTagManager: Invalid macro: _gtm.loadEventEnabled
2019-04-06 11:45:36.319 1844-1857/? E/memtrack: Couldn't load memtrack module
2019-04-06 11:45:36.319 1844-1857/? W/android.os.Debug: failed to get memory consumption info: -1
2019-04-06 11:45:36.419 4775-5006/? E/GoogleTagManager: Invalid macro: _gtm.loadEventEnabled
2019-04-06 11:45:36.487 4775-4829/? I/MediaStoreImporter: Update: incremental Success: true Added music: 0 Updated music: 0 Deleted music: 0 Created playlists: 0 Updated playlists: 0 Deleted playlists: 0 Inserted playlist items: 0 Deleted playlist items: 0 Removed orphaned playlist items: 0 Total item count: 0
2019-04-06 11:45:36.491 4775-4775/? D/MusicLifecycle: com.google.android.music.download.EncapsulatedBroadcastReceiver$1 generated event: Broadcast received with context com.google.android.music.ui.PhoneMusicApplication@a0c548d and intent Intent { act=com.google.android.music.IMPORT_COMPLETE flg=0x10 }
2019-04-06 11:45:36.609 4775-5008/? E/GoogleTagManager: Invalid macro: _gtm.loadEventEnabled
2019-04-06 11:45:36.637 4775-5000/? E/GoogleTagManager: Unsupported Value Escaping: 3
2019-04-06 11:45:36.752 1844-1955/? E/TaskPersister: File error accessing recents directory (directory doesn't exist?).
2019-04-06 11:45:36.684 4775-5000/? E/GoogleTagManager: Unsupported Value Escaping: 3
@CommonsWare, я создал каталог /raw в /res и скопировал туда файл .mp3. В чем именно разница между созданием каталога raw/ и созданием необработанного ресурса, если вы не возражаете против моего вопроса? Разве перемещение файла в папку /res/raw не превращает его в необработанный ресурс, на который можно ссылаться с помощью R.raw?
I created /raw directory in /res and copied the .mp3 file there
Это на вашей машине разработки.
What exactly is the difference between creating a raw/ directory and creating a raw resource if you don't mind my asking?
Разница в том, что getFilesDir()
относится к местоположению на устройстве Android. Каталог raw/
, который вы создали, находится на вашем компьютере для разработки.
Doesn't moving a file into the /res/raw folder turn it into a raw resource that you can reference with R.raw?
да. Однако это не то, что делает ваш код. Ваш код пытается сослаться на него с помощью File
. Необработанные ресурсы — это файлы на вашем компьютере для разработки. Это не файлы на устройстве.
Вам нужно скопировать необработанный ресурс (getResources().openRawResource()
и т. д.) в файл, которым затем можно поделиться с помощью FileProvider
.
Хорошо! Итак, чтобы поделиться необработанным ресурсом из каталога raw/ приложения, мне нужно открыть ресурс с помощью InputStream, а затем скопировать его в /sdcard с помощью чего-то вроде IOUtils.copy(), прежде чем я смогу поделиться им?
@ Rvby1: я рекомендую скопировать его в getCacheDir()
(метод на Context
) или в какой-нибудь его подкаталог. Хотя в остальном да.
Хорошо! Спасибо! Если вы не возражаете, я задам еще пару вопросов для моего понимания: в чем тогда смысл FileProvider? Просто создать Uri контента для файла, которым затем можно будет поделиться с другим приложением? Если да, то будет ли необходим FileProvider с точки зрения разрешений для приложения B, чтобы открыть файл, записанный где-то за пределами внутренней памяти приложения A, например /sdcard?
@Rvby1: «Просто создать Uri контента для файла, которым затем можно будет поделиться с другим приложением?» -- да. «Будет ли FileProvider необходим с точки зрения разрешений для приложения B, чтобы открыть файл, записанный где-то за пределами внутренней памяти приложения A, например / sdcard?» -- вы предполагаете, что у приложения B есть права на это местоположение. Это не всегда так, и на Android Q, скорее всего, будет нет. Считайте внешнее хранилище полезным для пользователя; используйте FileProvider
, когда ваше приложение запрашивает другое приложение для работы с данными.
Наконец-то нашел время написать код записи файла из папки сырых ресурсов во внутреннее хранилище. Однако я все еще получаю сообщение об ошибке FileNotFound, когда пытаюсь предоставить файл с помощью FileProvider. Я знаю, что файл существует на внутреннем диске (getFilesDir()), так как file.exists() возвращает true. Есть идеи? Я могу создать новый вопрос или отредактировать основной вопрос, если вам нужно больше контекста.
@ Rvby1: Новый вопрос со свежим минимальный воспроизводимый пример и трассировкой стека, показывающей FileNotFoundException
, вероятно, лучше всего на данный момент.
«хранится в необработанной папке внутреннего хранилища моего приложения» — вы создали каталог
raw/
и скопировали туда этот файл MP3? Или вы имеете в виду сырой ресурс?