Звук уведомления Android 7.0 от провайдера файлов Uri не воспроизводится

Я изменяю код моего приложения для поддержки Android 7, но в моем NotificationCompat.Builder.setSound(Uri), передавая Uri из FileProvider, Notification не воспроизводит звук, в Android 6 с использованием Uri.fromFile() работали правильно.

Файл mp3 находится в:

/Animeflv/cache/.sounds/

Это мой код уведомления:

knf.animeflv.RequestBackground

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_not_r)
.setContentTitle(NotTit)
.setContentText(mess);
...
mBuilder.setVibrate(new long[]{100, 200, 100, 500});
mBuilder.setSound(UtilSound.getSoundUri(not)); //int

Это мой UtilSound.getSoundUri(int)

public static Uri getSoundUri(int not) {
        switch (not) {
            case 0:
                return RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
            default:
                try {
                    File file=new File(Environment.getExternalStorageDirectory()+"/Animeflv/cache/.sounds",getSoundsFileName(not));
                    if (file.exists()) {
                        file.setReadable(true,false);
                        if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
                            return FileProvider.getUriForFile(context, "knf.animeflv.RequestsBackground",file);
                        }else {
                            return Uri.fromFile(file);
                        }
                    }else {
                        Log.d("Sound Uri","Not found");
                        return getSoundUri(0);
                    }
                }catch (Exception e){
                    e.printStackTrace();
                    return getSoundUri(0);
                }
        }
    }

В AndroidManifest.xml:

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="knf.animeflv.RequestsBackground"
    android:exported="false"
    android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths"/>
</provider>

provider_paths.xml:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="_.sounds" path="Animeflv/cache/.sounds/"/>
</paths>

1 ответ

Решение

Ниже приведено сообщение из блога, которое я только что опубликовал и воспроизведено здесь, потому что, эй, а почему бы и нет?


Вы можете поставить собственную мелодию на Notification через такие методы, как setSound() на NotificationCompat.Builder, Это требует Uri и это вызывает проблемы в Android 7.0, о чем сообщают несколько человек в Stack Overflow.

Если бы вы использовали file:Uri значения, они больше не работают на Android 7.0, если ваш targetSdkVersion 24 или выше, как звук Uri проверяется на соответствие запрету file:Uri ценности.

Однако, если вы попробуете content:Uri от, скажем, FileProvider Ваш звук не будет воспроизводиться... потому что Android не имеет доступа для чтения к этому контенту.

Вот несколько вариантов решения этой проблемы.

Скальпель: grantUriPermissions()

Вы всегда можете предоставить разрешения на контент другим приложениям через grantUriPermissions(), метод доступен на Context, Задача состоит в том , чтобы узнать, кому предоставить разрешения.

Что работает на Nexus 6P (Android 6.0... все еще...) и Nexus 9 (Android 7.0):

grantUriPermission("com.android.systemui", sound,
    Intent.FLAG_GRANT_READ_URI_PERMISSION);

(где sound это Uri что вы используете с setSound())

Будет ли это работать для всех устройств и всех версий ОС Android, я не могу сказать.

Гильотина: больше нет пользовательских файлов

android.resource как схема отлично работает для Uri значения для setSound(), Вместо того, чтобы разрешать пользователям выбирать свою собственную мелодию звонка из файла, вы позволяете им выбирать только одну из нескольких мелодий звонка, которые вы отправляете в качестве необработанных ресурсов в вашем приложении. Если это представляет собой потерю функциональности приложения, ваши пользователи могут быть не впечатлены.

Топор: использовать обычай ContentProvider

FileProvider не может быть использовано при экспорте - происходит сбой при запуске. Однако для этого случая единственным content:Uri это будет работать без других проблем, это тот, где провайдер exported и не имеет разрешений на чтение (или иногда требуется разрешение, которое com.android.systemui или эквивалент случается, чтобы держать).

Со временем я добавлю варианты для этого в мой StreamProvider, как часть некоторых функций "только для чтения" провайдера.

Но вы могли бы бросить свой собственный поставщик для этого.

Бензопила: запретить бан

Следующий фрагмент кода блокирует все StrictMode проверки, связанные с поведением виртуальной машины (т. е. вещи, отличные от поведения основного потока приложения), включая запрет на file:Uri ценности:

StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().build());

Кроме того, вы можете настроить свой собственный VmPolicy с любыми правилами, которые вы хотите, просто без звонка detectFileUriExposure(),

Это позволяет вам использовать file:Uri значения где угодно. Есть веские причины, почему Google запрещает file:Uri и поэтому попытка избежать запрета может укусить вас в неудачные части тела в долгосрочной перспективе.

Ядерное оружие: используйте более низкое targetSdkVersion

Это также снимает запрет на file:Uri ценности, наряду со всем другим поведением, которое targetSdkVersion из 24+ выбирает. Следует отметить, что это приведет к тому, что ваше приложение будет отображать сообщение "может не работать с разделенным экраном" Toast если пользователь входит в многоэкранный режим с разделенным экраном.

Реальное решение: исправление в Android

NotificationManager должен звонить grantUriPermissions() для нас, или должен быть какой-то другой способ для нас, чтобы связать FLAG_GRANT_READ_URI_PERMISSION с Uri что мы используем для пользовательских Notification звуки. Следите за новостями.

Другие вопросы по тегам