来自File Provider Uri的Android 7.0 Notification Sound无法播放

我正在更改我的应用程序代码以支持Android 7,但是在我的NotificationCompat.Builder.setSound(Uri)中,从FileProvider传递Uri,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_paths.xml:

     

以下是我刚刚发表的一篇博文 ,转载于此,因为,嘿,为什么不呢?


您可以通过Notification上的setSound()等方法在NotificationCompat.Builder上添加自定义铃声。 这需要一个Uri ,这会导致Android 7.0出现问题,正如Stack Overflow上的一些人所报告的那样。

如果您使用的是file: Uri值,如果您的targetSdkVersion为24或更高,它们将不再适用于Android 7.0,因为检查声音Uri是否符合禁止file: Uri值 。

但是,如果您尝试content:来自FileProvider Uri ,您的声音将无法播放…因为Android没有对该内容的读取权限。

以下是解决此问题的一些选项。

手术刀: grantUriPermissions()

您始终可以通过grantUriPermissions() Context提供的方法grantUriPermissions()内容权限授予其他应用程序。 挑战在于知道授予的权限。

适用于Nexus 6P(Android 6.0 ……仍然……)和Nexus 9(Android 7.0)的是:

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

sound是你使用setSound()Uri

这是否能够支持所有设备和所有Android OS版本,我不能说。

断头台:没有更多的用户文件

android.resource作为一个方案适用于setSound() Uri值。 您只允许用户从应用程序中选择作为原始资源提供的多个铃声之一,而不是允许用户从文件中选择自己的铃声。 但是,如果这代表了应用function的丢失,那么您的用户可能会感到不满意。

Ax:使用自定义ContentProvider

FileProvider时无法使用FileProvider – 它在启动时崩溃。 但是,对于这种情况,唯一的content: Uri将在没有其他问题的情况下工作,其中提供者被exported并且没有读取访问权限(或者恰好需要com.android.systemui或等效的一些权限) 。

最后,我将向我的StreamProvider添加选项,作为一些“只读”提供程序function的一部分。

但是,您可以为此推出自己的提供商。

电锯:禁止禁令

以下代码片段阻止与VM行为相关的所有StrictMode检查(即主应用程序线程行为以外的其他内容),包括禁止file: Uri值:

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

或者,您可以使用您想要的任何规则配置自己的VmPolicy ,而无需调用detectFileUriExposure()

这允许您在任何地方使用file: Uri值。 谷歌禁止使用该file:有很好的理由file: Uri ,所以试图避免禁令可能会让你长期处于不幸的身体部位。

Nuke:使用较低的targetSdkVersion

这也删除了file:禁令file: Uri值,以及24+的targetSdkVersion选择进入的所有其他行为。 值得注意的是,如果用户进入分屏多窗口模式,这将导致您的应用程序显示“可能无法使用分屏” Toast

真正的解决方案:Android中的修复

NotificationManager应该为我们调用grantUriPermissions() ,或者我们应该有其他方式将FLAG_GRANT_READ_URI_PERMISSION与我们用于自定义Notification声音的Uri相关联。 请继续关注进一步的发展 。