来自文件提供程序 Uri 的 Android 7.0 通知声音未播放 [英] Android 7.0 Notification Sound from File Provider Uri not playing

查看:46
本文介绍了来自文件提供程序 Uri 的 Android 7.0 通知声音未播放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在更改我的应用程序代码以支持 Android 7,但在我的 NotificationCompat.Builder.setSound(Uri) 中从 FileProvider 传递 Uri 中,通知不播放任何声音,在 Android 6 中使用 Uri.fromFile()工作正常.

I'm changing my app code for supporting Android 7, but in my NotificationCompat.Builder.setSound(Uri) passing the Uri from FileProvider the Notification don't play any sound, in Android 6 using the Uri.fromFile() worked properly.

mp3 文件在:

/Animeflv/cache/.sounds/

/Animeflv/cache/.sounds/

这是我的通知代码:

knf.animeflv.RequestBackground

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)

This is my 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 中:

In 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:

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>

推荐答案

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

The following is from a blog post that I just published, reproduced here because, hey, why not?

您可以在 Notification 上放置自定义铃声,方法如NotificationCompat.Builder 上的 setSound().这需要一个 Uri,并且正如所报告的那样,这会导致 Android 7.0 出现问题一些人堆栈溢出.

You can put a custom ringtone on a Notification, via methods like setSound() on NotificationCompat.Builder. This requires a Uri, and that causes problems on Android 7.0, as is reported by a few people on Stack Overflow.

如果您使用 file: Uri 值,它们将不再适用于 Android 7.0如果您的 targetSdkVersion 是 24 或更高,则检查声音 Uri遵守禁止<代码>文件: Uri.

If you were using file: Uri values, they no longer work on Android 7.0 if your targetSdkVersion is 24 or higher, as the sound Uri is checked for compliance with the ban on file: Uri values.

但是,如果您尝试 content: Uri 来自,例如,FileProvider,您的声音将不会播放...因为 Android 没有读取权限内容.

However, if you try a content: Uri from, say, FileProvider, your sound will not be played... because Android does not have read access to that content.

这里有一些解决这个问题的选项.

Here are some options for addressing this.

手术刀:grantUriPermissions()

您始终可以通过 grantUriPermissions() 向其他应用授予内容权限,Context 上可用的方法.挑战在于了解授予权限.

You can always grant permissions for content to other apps via grantUriPermissions(), a method available on Context. The challenge is in knowing who to grant the permissions to.

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

What works on a Nexus 6P (Android 6.0... still...) and a Nexus 9 (Android 7.0) is:

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

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

(where sound is the Uri that you are using with setSound())

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

Whether this will hold up for all devices and all Android OS versions, I cannot say.

断头台:不再有用户文件

android.resource 作为一种方案适用于 setSound()Uri 值.而不是允许用户从文件中选择自己的铃声,您只允许他们选择您发送的几种铃声中的一种作为应用程序中的原始资源.如果这代表应用程序丢失不过,您的用户可能对这些功能不感兴趣.

android.resource as a scheme works fine for Uri values for setSound(). Instead of allowing users to choose their own ringtone from a file, you only allow them to choose one of several ringtones that you ship as raw resources in your app. If this represents a loss of app functionality, though, your users may be unimpressed.

The Axe:使用自定义ContentProvider

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

FileProvider cannot be used when it is exported — it crashes on startup. However, for this case, the only content: Uri that will work without other issues is one where the provider is exported and has no read access permissions (or happens to require some permission that com.android.systemui or the equivalent happens to hold).

最终,我会为此添加选项我的StreamProvider,如某些只读"提供程序功能的一部分.

Eventually, I'll add options for this to my StreamProvider, as part of some "read only" provider functionality.

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

But, you could roll your own provider for this.

电锯:禁止禁止

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

The following code snippet blocks all StrictMode checks related to VM behavior (i.e., stuff other than main application thread behavior), including the ban on file: Uri values:

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

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

Alternatively, you could configure your own VmPolicy with whatever rules you want, just without calling detectFileUriExposure().

这允许您在任何地方使用 file: Uri 值.有好的Google 禁止 file: Uri 的原因,因此试图避免从长远来看,这项禁令可能会咬你不幸的身体部位.

This allows you to use file: Uri values anywhere. There are good reasons why Google is banning the file: Uri, and so trying to avoid the ban may bite you in unfortunate body parts in the long term.

The Nuke:使用较低的 targetSdkVersion

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

This also removes the ban on file: Uri values, along with all other behavior that a targetSdkVersion of 24+ opts into. Of note, this will cause your app to display a "may not work with split-screen" Toast if the user enters split-screen multi-window mode.

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

NotificationManager 应该调用 grantUriPermissions()对我们来说,或者应该有其他方式让我们联系FLAG_GRANT_READ_URI_PERMISSION 带有我们用于自定义的 Uri通知 声音.敬请期待进一步的发展.

The NotificationManager should be calling grantUriPermissions() for us, or there should be some other way for us to associate FLAG_GRANT_READ_URI_PERMISSION with the Uri that we use for custom Notification sounds. Stay tuned for further developments.

这篇关于来自文件提供程序 Uri 的 Android 7.0 通知声音未播放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆