6

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

1 回答 1

20

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


Notification您可以通过 on 之类的方法 将自定义铃声放在 asetSound()NotificationCompat.Builder。这需要Uri, 并且会导致 Android 7.0 出现问题,正如 Stack Overflow的一些人所报告的那样。

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

但是,如果您尝试使用content: Urifrom,例如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的那个在哪里)UrisetSound()

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

断头台:不再有用户文件

android.resource作为一个方案适用UrisetSound(). 您不能允许用户从文件中选择自己的铃声,而是只允许他们选择您在应用程序中作为原始资源提供的几种铃声之一。但是,如果这代表应用程序功能的丢失,您的用户可能会不以为然。

斧头:使用自定义ContentProvider

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

最终,我将为此添加选项到 myStreamProvider中,作为一些“只读”提供程序功能的一部分。

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

电锯:禁止禁令

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

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

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

这允许您在file: Uri任何地方使用值。谷歌禁止file: Uri.

Nuke:使用较低的targetSdkVersion

这也取消了对file: Uri价值观的禁令,以及 24 岁以上的 a 选择的所有其他行为targetSdkVersion。值得注意的是,Toast 如果用户进入分屏多窗口模式,这将导致您的应用显示“可能不适用于分屏”。

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

NotificationManager应该呼唤grantUriPermissions() 我们,或者应该有其他方式让我们 FLAG_GRANT_READ_URI_PERMISSIONUri我们用于自定义 Notification声音 的相关联。请继续关注进一步的发展

于 2016-09-07T17:11:29.693 回答