来自文件提供程序Uri的Android 7.0通知声音无法播放

时间:2016-09-07 00:02:28

标签: java android android-studio android-fileprovider android-7.0-nougat

我正在更改我的应用程序代码以支持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
    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 个答案:

答案 0 :(得分:17)

以下是我刚刚发表的a blog post,在此转载,因为,嘿,为什么不呢?

您可以通过以下方法在Notification上添加自定义铃声 setSound()上的NotificationCompat.Builder。这需要Uri和 据报道,这会导致Android 7.0出现问题 a few people Stack Overflow

如果您使用的是file: Uri个值,则它们将不再适用于Android 7.0 如果targetSdkVersion为24或更高,则会检查声音Uri 符合the ban on file: Uri values

但是,如果您尝试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的{​​{1}}值。 而不是允许用户从文件中选择自己的铃声, 你只允许他们选择你发送的几个铃声之一 作为您应用中的原始资源。如果这表示应用程序丢失 但是,您的用户可能会对此感到不满意。

斧头:使用自定义setSound()

导出时无法使用

ContentProvider - 它崩溃了 启动。但是,对于这种情况,唯一会FileProvider content: 没有其他问题的工作是提供者Uri和。{ 没有读访问权限(或者恰好需要一些权限) exported或等价物碰巧持有)。

最后,我会为此添加选项 my StreamProvider,如 部分&#34;只读&#34;提供商功能。

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

电锯:禁止禁令

以下代码段会阻止与之相关的所有com.android.systemui项检查 VM行为(即主应用程序线程行为以外的东西), 包括禁止StrictMode file:值:

Uri

或者,您可以随意配置自己的StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().build()); 您想要的规则,只需不调用VmPolicy

这允许您在任何地方使用detectFileUriExposure() file:值。有好处 谷歌禁止Uri file:的原因,并试图避免 从长远来看,禁令可能会让你陷入不幸的身体部位。

The Nuke:使用较低的Uri

这也取消了对targetSdkVersion file:值以及所有其他值的禁令 一个Uri的24+选择进入的行为。值得注意的是,这会 导致您的应用显示&#34;可能无法使用分屏&#34; targetSdkVersion 如果用户进入分屏多窗口模式。

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

Toast应致电NotificationManager 对我们来说,还是应该有其他方式让我们联想 grantUriPermissions()我们使用FLAG_GRANT_READ_URI_PERMISSION进行自定义 Uri听起来。 Stay tuned for further developments