Xamarin.Android 如何使“wav”文件成为应用程序的默认推送通知声音?

Posted

技术标签:

【中文标题】Xamarin.Android 如何使“wav”文件成为应用程序的默认推送通知声音?【英文标题】:Xamarin.Android How to make a 'wav' file the default push notification sound for the app? 【发布时间】:2019-01-08 22:22:10 【问题描述】:

目标:将自定义 wav 设置为应用的默认推送通知声音。

我有一个 Wave 文件,它位于 android 上的“FilesDir”中。我使用 Xamarin.Essentials FileSystem helper 在 FileSystem.AppDataDirectory 中创建文件,它实际上是一个录音。

在 Debug 中检查 wav 文件的确切位置是:

/data/user/o/com.company.appname/files/fileName.Wav

我需要将此文件设置为我的应用程序的默认推送通知声音。 目前我设置了一个通知通道,但使用的通知声音(并且按预期工作)驻留在 res/raw 中。

我怎样才能做到这一点?

似乎我无法将其设为当前位置的默认推送通知声音。我必须将它复制到 Ringtone 文件夹或 res/raw 文件夹,但是我该如何在应用程序运行时动态地执行此操作(将文件复制到可以用作通知声音的相应位置)?是否可以在 APK 内进行文件传输?

这是我在创建推送通知通道时尝试过的,但没有成功:

//Create two notif channels, the urgent channel 
// should use a custom wav as notification sound
private void createNotificationChannels()
    
        try
        
            // the urgent channel
            var urgentChannelName = GetString(Resource.String.noti_chan_urgent);
            var urgentChannelDescription = GetString(Resource.String.noti_chan_urgent_description);

            // the informational channel
            var infoChannelName = GetString(Resource.String.noti_chan_info);
            var infoChannelDescrption = GetString(Resource.String.noti_chan_info_description);

            // set the vibration patterns for the channels
            long[] urgentVibrationPattern =  100, 30, 100, 30, 100, 200, 200, 30, 200, 30, 200, 200, 100, 30, 100, 30, 100, 100, 30, 100, 30, 100, 200, 200, 30, 200, 30, 200, 200, 100, 30, 100, 30, 100 ;
            long[] infoVibrationPattern =  100, 200, 300, 400, 500, 400, 300, 200, 400 ;

            // Creating common Audio Attributes for both channels
            var alarmAttributes = new AudioAttributes.Builder()
                .SetContentType(AudioContentType.Sonification)
                .SetUsage(AudioUsageKind.Notification).Build();

            // get path of custom sound recording to use as push notification
            var recordingFileDestinationPath = System.IO.Path.Combine(FileSystem.AppDataDirectory, AppConstants.CUSTOM_ALERT_FILENAME);

            //**This is where I am trying to create the URI for the custom wav file for notification, which resides in FilesDir**
            Android.Net.Uri urgentAlarmUri = Android.Net.Uri.Parse(recordingFileDestinationPath);

            Android.Net.Uri infoAlarmUri = RingtoneManager.GetDefaultUri(RingtoneType.Notification);


            var chan1 = new NotificationChannel(PRIMARY_CHANNEL_ID, urgentChannelName, NotificationImportance.High)
            
                Description = urgentChannelDescription
            ;

            var chan2 = new NotificationChannel(SECONDARY_CHANNEL_ID, infoChannelName, NotificationImportance.Default)
            
                Description = infoChannelDescrption
            ;


            // set the urgent channel properties
            chan1.EnableLights(true);
            chan1.LightColor = Color.Red;
            chan1.SetSound(urgentAlarmUri, alarmAttributes);
            chan1.EnableVibration(true);
            chan1.SetVibrationPattern(urgentVibrationPattern);               
            chan1.SetBypassDnd(true);
            chan1.LockscreenVisibility = NotificationVisibility.Public;

            // set the info channel properties
            chan2.EnableLights(true);
            chan2.LightColor = Color.Red;
            chan2.SetSound(infoAlarmUri, alarmAttributes);
            chan2.EnableVibration(true);
            chan2.SetVibrationPattern(infoVibrationPattern);
            chan2.SetBypassDnd(false);
            chan2.LockscreenVisibility = NotificationVisibility.Public;


            var manager = (NotificationManager)GetSystemService(NotificationService);

            // create chan1  which is the urgent notifications channel
            manager.CreateNotificationChannel(chan1);
            manager.CreateNotificationChannel(chan2);


        
        catch (Exception ex)
        
            Console.WriteLine(ex.Message);
        
    

使用上述代码的紧急频道没有声音。 如果我从 res/raw 加载声音,它工作正常。如果我事先将录音放在 res/raw 中,它可能会起作用,但声音是在运行时自定义录制的......

【问题讨论】:

【参考方案1】:

查看适用于 Android 的 FileSystem.AppDataDirectory 的 Xamarin Essentials 源代码,

https://github.com/xamarin/Essentials/blob/master/Xamarin.Essentials/FileSystem/FileSystem.android.cs#L14

您正在将录制的声音文件保存到内部存储(文件目录)。 Files 目录是一个私有目录,只能由您的应用程序访问。用户或操作系统都无法访问此文件。您必须将文件保存在Public External Storage 或Private External Storage 中。这取决于您是否希望 MediaStore 内容提供商可以访问您录制的声音文件。

【讨论】:

你说得对,谢谢你的提示。我有一个可行的解决方案并将其发布在下面。【参考方案2】:

我想出了如何做到这一点,并且可能会帮助尝试这样做的人。这是解决方案:

正如@SharpMoibileCode 所述,在使用 Xamarin Essentials 文件系统帮助程序时,特别是在使用路径 FileSystem.AppDataDirectory 保存录制文件时,它会将其保存在 Internal Storage 中。这有一个这样的路径:

/data/user/0/com.company.appname/files/customsoundfilename.wav

为了在运行时自定义频道的推送通知声音,声音文件必须保存到公共外部存储,即Android.OS.Environment.ExternalStorageDirectory 有这样的路径:

/storage/emulated/0/.../

现在需要写入外部存储的权限才能写入/读取外部存储。因此需要将这些添加到清单中:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

但这还不够。必须在像这样访问外部存储之前询问权限(在此处使用 NuGet 插件 Current Activity for Android 项目来获取当前活动):

var currentActivity = CrossCurrentActivity.Current.Activity;
            int requestCode=1;

            ActivityCompat.RequestPermissions(currentActivity, new string[] 
                Manifest.Permission.ReadExternalStorage,
                Manifest.Permission.WriteExternalStorage
            , requestCode);

如果授予权限,则继续并将文件复制到外部存储:

var recordingFileExternalPath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path, AppConstants.CUSTOM_ALERT_FILENAME);

            if (ContextCompat.CheckSelfPermission(Android.App.Application.Context, Manifest.Permission.WriteExternalStorage) == (int)Permission.Granted)
            
                try
                
                    if (File.Exists(recordingFileExternalPath))
                    
                        File.Delete(recordingFileExternalPath);
                    

                    File.Copy(filePath, recordingFileExternalPath);
                
                catch (Exception ex)
                
                    Console.WriteLine(ex.Message);
                
            
            else
            
                UserDialogs.Instance.Alert("Permission to write to External Storage not approved, cannot save settings.", "Permission Denied", "Ok");
            

现在终于将上面复制的声音设置为频道的通知:

try
            
                // the urgent channel
                var urgentChannelName = GetString(Resource.String.noti_chan_urgent);
                var urgentChannelDescription = GetString(Resource.String.noti_chan_urgent_description);


                // set the vibration patterns for the channels
                long[] urgentVibrationPattern =  100, 30, 100, 30, 100, 200, 200, 30, 200, 30, 200, 200, 100, 30, 100, 30, 100, 100, 30, 100, 30, 100, 200, 200, 30, 200, 30, 200, 200, 100, 30, 100, 30, 100 ;

                // Creating an Audio Attribute
                var alarmAttributes = new AudioAttributes.Builder()
                    .SetContentType(AudioContentType.Speech)
                    .SetUsage(AudioUsageKind.Notification).Build();

                // Create the uri for the alarm file

                var recordingFileDestinationPath = System.IO.Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path, AppConstants.CUSTOM_ALERT_FILENAME);

                Android.Net.Uri urgentAlarmUri = Android.Net.Uri.Parse(recordingFileDestinationPath);



                var chan1 = new NotificationChannel(PRIMARY_CHANNEL_ID, urgentChannelName, NotificationImportance.High)
                
                    Description = urgentChannelDescription
                ;


                // set the urgent channel properties
                chan1.EnableLights(true);
                chan1.LightColor = Color.Red;
                chan1.SetSound(urgentAlarmUri, alarmAttributes);
                chan1.EnableVibration(true);
                chan1.SetVibrationPattern(urgentVibrationPattern);               
                chan1.SetBypassDnd(true);
                chan1.LockscreenVisibility = NotificationVisibility.Public;



                var manager = (NotificationManager)GetSystemService(NotificationService);

                // create chan1  which is the urgent notifications channel
                manager.CreateNotificationChannel(chan1);

            
            catch (Exception ex)
            
                Console.WriteLine(ex.Message);
            
        

【讨论】:

以上是关于Xamarin.Android 如何使“wav”文件成为应用程序的默认推送通知声音?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法将 NAudio.Lame 与 Xamarin (Android/iOS) 应用程序一起使用?

启用 PROGUARD - Xamarin.Android

如何使为 API 22 设计的 Android 应用程序与 API21 兼容

我可以在不使用gradle的情况下使用Xamarin.Android中的Android数据绑定库吗?不是MVVM for dotnet

xamarin,android如何读写文件?给一下仔细步骤。

在 Xamarin Android 中访问 UI 线程