来自文件提供程序 Uri 的 Android 7.0 通知声音未播放 [英] Android 7.0 Notification Sound from File Provider Uri not playing
问题描述
我正在更改我的应用程序代码以支持 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屋!