Звук уведомления 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
звуки. Следите за новостями.