一尘不染

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

java

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

mp3文件位于:

/ Animeflv /缓存/.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>

阅读 203

收藏
2020-12-03

共1个答案

一尘不染

以下是我刚刚发表的博客文章,此处转载是因为,为什么呢?


您可以Notification通过on之类的方法
setSound()在上添加自定义铃声NotificationCompat.BuilderUri正如Stack
Overflow

的一些人所报道的那样,这需要一个,并在Android
7.0上引起问题 。

如果您使用file: Uri的价值观,他们不再在Android
7.0的工作,如果你targetSdkVersion是24或更高,因为声音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);

(这里soundUri你使用的是带有setSound()

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

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

android.resource作为一种方案,对于的Uri值可以很好地工作setSound()。与其允许用户从文件中选择自己的铃声,不如让他们选择您作为应用程序中的原始资源提供的几种铃声之一。但是,如果这表示丧失了应用程序功能,则您的用户可能会不满意。

轴:使用自定义ContentProvider

FileProvider导出时无法使用-启动时崩溃。但是,在这种情况下,唯一content:
Uri不会出现其他问题的方法就是提供者所在的位置exported,并且没有读取访问权限(或者恰好需要某种权限,com.android.systemui或者恰好持有该权限
)。

最后,我会为这个选项添加到 我的StreamProvider,因为一些“只读”提供功能的一部分。

但是,您可以为此选择自己的提供商。

电锯:禁止禁令

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

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

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

这使您可以file: Uri在任何地方使用值。Google禁止使用的理由很充分file:
Uri,因此从长远来看,尝试避免使用该禁止措施可能会咬伤不幸的身体部位。

核弹:低一点targetSdkVersion

这也消除了对file:
Uri价值的禁止,以及targetSdkVersion24岁以上的孩子选择参加的所有其他行为。值得注意的是,Toast
如果用户进入分屏多窗口模式,这将导致您的应用显示“可能无法使用分屏” 。

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

NotificationManager应呼吁grantUriPermissions() 对我们来说,还是应该给我们一些其他的方式,以联想
FLAG_GRANT_READ_URI_PERMISSIONUri我们使用自定义 Notification声音。
敬请期待进一步的发展

2020-12-03