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

Android 7.0 Notification Sound from File Provider Uri not playing

我正在更改我的应用程序代码以支持 Android 7,但是在我的 NotificationCompat.Builder.setSound(Uri) 从 FileProvider 传递 Uri 时,通知不播放任何声音,在 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>

以下内容来自a blog post,我刚刚发表,转载于此,因为,嘿,为什么不呢?


您可以通过以下方法将自定义铃声放在 NotificationsetSound()NotificationCompat.Builder 上。这需要 Uri,并且 这会导致 Android 7.0 出现问题,据报道 a few peopleStack 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(Android7.0)的是:

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

(其中 sound 是您与 setSound() 一起使用的 Uri

这是否适用于所有设备和所有 Android OS 版本, 我不能说。

The Guillotine:没有更多的用户文件

android.resource 作为一种方案适用于 setSound()Uri 值。 不再允许用户从文件中选择自己的铃声, 您只允许他们选择您提供的几种铃声之一 作为您应用中的原始资源。如果这表示应用丢失 功能,但是,您的用户可能不为所动。

斧头:使用自定义 ContentProvider

FileProvider 导出时无法使用 - 它会崩溃 启动。但是,对于这种情况,唯一的 content: Uri 没有其他问题的工作是提供者 exported 和 没有读取访问权限(或恰好需要一些权限 com.android.systemui 或等价物正好成立)。

最后,我会为此添加选项 my StreamProvider, 作为 "read only" 提供程序功能的一部分。

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

The Chainsaw: Ban the Ban

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

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

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

这允许您在任何地方使用 file: Uri 值。有好的 Google 禁止 file: Uri 并试图避免的原因 从长远来看,该禁令可能会在不幸的 body 部分咬到你。

The Nuke:使用较低的 targetSdkVersion

这也删除了对 file: Uri 值以及所有其他值的禁令 24 岁以上的 targetSdkVersion 选择加入的行为。值得注意的是,这将 让您的应用显示 "may not work with split-screen" Toast 如果用户进入 split-screen multi-window 模式。

真正的解决方案:Android

中的修复

NotificationManager 应该调用 grantUriPermissions() 对我们来说,或者应该有一些其他的方式让我们联系 FLAG_GRANT_READ_URI_PERMISSION 和我们用于自定义的 Uri Notification 声音。 Stay tuned for further developments.