Получение FileNotFoundException при попытке поделиться MP3 через неявное намерение с использованием FileProvider - PullRequest
1 голос
/ 13 апреля 2019

Я пытаюсь поделиться файлом MP3 из внутренних файлов моего андроида (корень которого getFilesDir()) в другое приложение с неявным намерением ACTION_VIEW.Файл MP3 изначально хранился в папке /raw моего приложения, но я скопировал его во внутренние файлы моего приложения.

Я подтвердил, что файл существует, используя file.exists().Однако когда я использую FileProvider для создания URI контента для файла и использую этот URI контента в качестве данных в неявном намерении, я получаю FileNotFoundException: open failed: ENOTDIR, когда пытаюсь запустить неявное намерение.

Я попытался изменить полномочия FileProvider, и я изучил спецификации Android для совместного использования медиа-файла с помощью намерений и убедился, что мое неявное намерение соответствует стандартам.

Вот вывод из окна журнала при возникновении ошибки:

23349-23349/? D/MusicLifecycle: com.google.android.music.ui.playback.AudioPreviewActivity generated event: Activity created
23349-23349/? W/MediaPlayer: Couldn't open content://com.example.selfcareapplication.fileprovider/meditation-files/breathing-meditation.mp3: java.io.FileNotFoundException: open failed: ENOTDIR (Not a directory)
1844-2784/? W/ActivityManager: Permission Denial: opening provider android.support.v4.content.FileProvider from (null) (pid=1694, uid=1013) that is not exported from UID 10099
1694-2151/? E/MediaPlayerService: Couldn't open fd for content://com.example.selfcareapplication.fileprovider/meditation-files/breathing-meditation.mp3
23349-23349/? E/MediaPlayerNative: Unable to create media player
23349-23349/? D/AudioPreviewActivity: Failed to open file: java.io.IOException: setDataSource failed.: status=0x80000000

Вот код, который мне нужен, чтобы получить файл, создать FileProvider и запустить намерение:

Intent openMeditationFileIntent = new Intent(Intent.ACTION_VIEW);
File testFile = new File(this.getFilesDir(), "meditation-files\\breathing-meditation.mp3");

//check if file was written to internal memory. It prints "FILE WAS OUTPUT!"
if(testFile.exists()) {
     Log.d(LOG_TAG, "FILE WAS OUTPUT!");
} else {
     Log.d(LOG_TAG, "FILE WAS NOT OUTPUT!!!");
}

//create content URI using FileProvider and the testFile
Uri meditationFileContentUri = FileProvider.getUriForFile(this.getApplicationContext(), "com.example.selfcareapplication.fileprovider", testFile);
openMeditationFileIntent.setDataAndType(meditationFileContentUri, "audio/*"); 
openMeditationFileIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

//try to open implicit intent using content URI as its data: 
if(openMeditationFileIntent.resolveActivity(getPackageManager()) != null) {
     startActivity(openMeditationFileIntent);
} else {
     Log.d(LOG_TAG, "Could not resolve activity");
}

Это мой манифест:

        <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>

А это мой файл file_paths.xml:

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="meditation-files" path="meditation-files/"/>
</paths>

РЕДАКТИРОВАТЬ:

Мне удалось заставить это работать!По предложению @CommonsWare я изменил тип MIME на «audio / mpeg», который является типом MIME для MP3.

Я также вынул гипс в названиях путей.Похоже, что из-за этого было невозможно правильно записать MP3-файл в getFilesDir () + «meditationPaths», поскольку проверка «file.exists ()» на пути к MP3 вернула бы false.Изменение '\' в путях к '/' решило эту проблему.

Тем не менее, когда я провел дальнейшее тестирование позже, я обнаружил, что и '\', и '/' позволили правильно записать MP3 ... так что я не совсем уверен, что пошло не так в первый разчерез.Я бы просто порекомендовал использовать File.separator, чтобы убедиться, что вы автоматически используете правильный разделитель для среды, в которой работает ваша программа.

Вот окончательный код для получения файла, создания FileProvider и запусканамерение:

Intent openMeditationFileIntent = new Intent(Intent.ACTION_VIEW);
File testFile = new File(this.getFilesDir(), "meditationFiles" + Path.separator + "breathingMeditation.mp3");

//check if file was written to internal memory. It prints "FILE WAS OUTPUT!"
if(testFile.exists()) {
     Log.d(LOG_TAG, "FILE WAS OUTPUT!");
} else {
     Log.d(LOG_TAG, "FILE WAS NOT OUTPUT!!!");
}

//create content URI using FileProvider and the testFile
Uri meditationFileContentUri = FileProvider.getUriForFile(this.getApplicationContext(), "com.example.selfcareapplication.fileprovider", testFile);
openMeditationFileIntent.setDataAndType(meditationFileContentUri, "audio/mpeg"); 
openMeditationFileIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

//try to open implicit intent using content URI as its data: 
if(openMeditationFileIntent.resolveActivity(getPackageManager()) != null) {
     startActivity(openMeditationFileIntent);
} else {
     Log.d(LOG_TAG, "Could not resolve activity");
}

Мне также пришлось изменить свой файл file-paths.xml, чтобы отразить изменение в имени папки:

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="meditationFiles" path ="meditationFiles"/>
</paths>
...