我正在更改应用程序代码以支持Android 7,但是在我的NotificationCompat.Builder.setSound(Uri)中,从FileProvider传递Uri时,通知没有播放声音,在Android 6中,使用Uri.fromFile()可以正常工作。
mp3文件位于:
/ Animeflv /缓存/.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>
以下是我刚刚发表的博客文章,此处转载是因为,为什么呢?
您可以Notification通过on之类的方法 setSound()在上添加自定义铃声NotificationCompat.Builder。Uri正如Stack Overflow上 的一些人所报道的那样,这需要一个,并在Android 7.0上引起问题 。
Notification
setSound()
NotificationCompat.Builder
Uri
如果您使用file: Uri的价值观,他们不再在Android 7.0的工作,如果你targetSdkVersion是24或更高,因为声音Uri是检查是否符合在禁令file: Uri值。
file:
targetSdkVersion
但是,如果您尝试使用content: Urifrom等功能FileProvider,则您的声音将无法播放…,因为Android没有对该内容的读取权限。
content:
FileProvider
以下是解决此问题的一些选项。
手术刀:grantUriPermissions()
grantUriPermissions()
您始终可以通过上grantUriPermissions()的方法向其他应用授予内容权限Context。挑战在于知道要向 谁 授予权限。
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())
sound
我不能说这是否适用于所有设备和所有Android OS版本。
断头台:没有更多的用户文件
android.resource作为一种方案,对于的Uri值可以很好地工作setSound()。与其允许用户从文件中选择自己的铃声,不如让他们选择您作为应用程序中的原始资源提供的几种铃声之一。但是,如果这表示丧失了应用程序功能,则您的用户可能会不满意。
android.resource
轴:使用自定义ContentProvider
ContentProvider
FileProvider导出时无法使用-启动时崩溃。但是,在这种情况下,唯一content: Uri不会出现其他问题的方法就是提供者所在的位置exported,并且没有读取访问权限(或者恰好需要某种权限,com.android.systemui或者恰好持有该权限 )。
exported
com.android.systemui
最后,我会为这个选项添加到 我的StreamProvider,因为一些“只读”提供功能的一部分。
StreamProvider
但是,您可以为此选择自己的提供商。
电锯:禁止禁令
以下代码段阻止了所有StrictMode与VM行为有关的检查(即,除主应用程序线程行为外的其他检查),包括对file: Uri值的禁止:
StrictMode
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().build());
另外,您可以使用自己VmPolicy想要的任何规则来配置自己,而无需调用detectFileUriExposure()。
VmPolicy
detectFileUriExposure()
这使您可以file: Uri在任何地方使用值。Google禁止使用的理由很充分file: Uri,因此从长远来看,尝试避免使用该禁止措施可能会咬伤不幸的身体部位。
核弹:低一点targetSdkVersion
这也消除了对file: Uri价值的禁止,以及targetSdkVersion24岁以上的孩子选择参加的所有其他行为。值得注意的是,Toast 如果用户进入分屏多窗口模式,这将导致您的应用显示“可能无法使用分屏” 。
Toast
真正的解决方案:Android中的修复程序
本NotificationManager应呼吁grantUriPermissions() 对我们来说,还是应该给我们一些其他的方式,以联想 FLAG_GRANT_READ_URI_PERMISSION与Uri我们使用自定义 Notification声音。 敬请期待进一步的发展。
NotificationManager
FLAG_GRANT_READ_URI_PERMISSION