Xamarin. Android не может использовать записанный пользовательский звук для push-уведомлений в Android 10 (Q) - PullRequest
0 голосов
/ 08 октября 2019

Используется для записи звука для использования в качестве пользовательского звука для канала push-уведомлений. Теперь этого больше нет. Что изменилось, пожалуйста, почему бы это больше не работало, нет звука, когда приходит уведомление?

Чтобы использовать записанный звук для push-уведомлений, я использовал его для копирования на внешнее хранилище, откуда он может бытьдоступ во время выполнения был следующим:

путь к внешнему пути был таким:

/ storage / emulated / 0 / customNotificationSoundRecording.wav

Вот полный код, сначала запишите звук:

private async Task RecordAudio()
        {
            buttonSave.IsEnabled = false;
            try
            {
                if (!recorder.IsRecording)
                {                
                    buttonRecord.IsEnabled = false;
                    buttonPlay.IsEnabled = false;               

                    // only if ios
                    if (Device.RuntimePlatform == Device.iOS)
                        DependencyService.Get<IAudioService>().PrepareRecording();


                    Increment = 1 / (double)AppConstants.MAX_RECORD_TIME;
                    Set_Timer();

                    var recordTask = await recorder.StartRecording();

                    buttonRecord.Text = "Stop";
                    buttonRecord.IsEnabled = true;

                    // get the recorded file
                    var recordedAudioFile = await recordTask;
                    // isRecording = false;                  

                    if (recordedAudioFile != null)
                    {
                        // first save the file from cache to AppData
                        var recordingFileDestinationPath = Path.Combine(FileSystem.AppDataDirectory, AppConstants.CUSTOM_ALERT_FILENAME);                     

                        //if (File.Exists(recordingFileDestinationPath))
                        if (CustomAlertSoundExists(recordingFileDestinationPath))
                        {
                            File.Delete(recordingFileDestinationPath);
                        }

                        File.Copy(recordedAudioFile, recordingFileDestinationPath);                     

                        Preferences.Set(AppConstants.CUSTOM_RECORDING_EXISTS_KEY, true);

                        if (Device.RuntimePlatform == Device.iOS)
                        {
                            DependencyService.Get<IGroupUserPrefs>().SetBoolValueForKey("isCustomAlert", true);
                        }

                        buttonSave.IsEnabled = true;
                    }

                    if (secondsElapsed >= AppConstants.MAX_RECORD_TIME)
                    {
                        Preferences.Set(AppConstants.RECORDING_LENGTH_SECONDS_KEY, secondsElapsed);
                        secondsElapsed = 0;
                        Reset_Timer();
                    }

                    buttonRecord.Text = "Record";
                    buttonPlay.IsEnabled = true;

                }
                else // stop button clicked
                {                                  

                    buttonRecord.IsEnabled = false;

                    await recorder.StopRecording();
                    buttonSave.IsEnabled = true;

                    // isRecording = false;

                    Reset_Timer();

                    // save last recording length in seconds
                    Preferences.Set(AppConstants.RECORDING_LENGTH_SECONDS_KEY, secondsElapsed);

                    //reset seconds elapsed 
                    secondsElapsed = 0;

                    buttonRecord.IsEnabled = true;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

А затем скопируйте запись на внешнее хранилище, которое раньше было единственным местом, откуда ее можно использовать для звука push-уведомлений:

public async void CopyRecordingToExternalStorage(string filePath)
        {
            var recordingFileExternalPath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path, AppConstants.CUSTOM_ALERT_FILENAME);

             // made some other attempts with different paths.
            // var recordingFileExternalPath = Path.Combine(FileSystem.AppDataDirectory, AppConstants.CUSTOM_ALERT_FILENAME);
            //var recordingFileExternalPath = Path.Combine(Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryAlarms).AbsolutePath, AppConstants.CUSTOM_ALERT_FILENAME);

            var storageStatus = await CrossPermissions.Current.CheckPermissionStatusAsync(Plugin.Permissions.Abstractions.Permission.Storage);

            if (storageStatus != Plugin.Permissions.Abstractions.PermissionStatus.Granted)
            {
                var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] { Plugin.Permissions.Abstractions.Permission.Storage });
                storageStatus = results[Plugin.Permissions.Abstractions.Permission.Storage];
            }

            if (storageStatus == Plugin.Permissions.Abstractions.PermissionStatus.Granted)
            {
                try
                {
                    if (File.Exists(recordingFileExternalPath))  // if file exists already in external storage
                    {
                        File.Delete(recordingFileExternalPath); // erase the file
                    }

                    File.Copy(filePath, recordingFileExternalPath); // and overwrite with new one
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
            else
            {
                UserDialogs.Instance.Alert("Permission to write to External Storage denied, cannot save settings.", "Permission Denied", "Ok");
            }             
        }

И тогда я бы создал канал с таким звуком, как этот:

private void createCustomNotificationChannel()
        {
            try
            {
                // the custom channel
                var urgentChannelName = GetString(Resource.String.noti_chan_custom);
                var customChannelDescription = GetString(Resource.String.noti_chan_custom_description);

                long[] customVibrationPattern = { 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.Sonification)
                    .SetUsage(AudioUsageKind.Notification).Build();

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

                 // also tried here with other paths
                // var alarmSourcePath = Path.Combine(FileSystem.AppDataDirectory, AppConstants.CUSTOM_ALERT_FILENAME);
                // var alarmSourcePath = System.IO.Path.Combine(Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryAlarms).AbsolutePath, AppConstants.CUSTOM_ALERT_FILENAME);

                var urgentAlarmUri = Android.Net.Uri.Parse(alarmSourcePath);

                // checking here if file exists after voice recording and
                //  the bool is true
                bool soundFileExists = File.Exists(alarmSourcePath);

                var chan3 = new NotificationChannel(TERTIARY_CHANNEL_ID, urgentChannelName, NotificationImportance.High)
                {
                    Description = customChannelDescription
                };

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

                var manager = (NotificationManager)GetSystemService(NotificationService);

                // create chan1  which is the urgent notifications channel
                manager.CreateNotificationChannel(chan3);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

1 Ответ

1 голос
/ 08 октября 2019

Чтобы предоставить пользователям больший контроль над своими файлами и ограничить помехи в файлах, приложениям, ориентированным на Android 10 (уровень API 29) и выше, по умолчанию предоставляется доступ с ограничениями на внешнее устройство хранения или хранилище с областями действия. Такие приложения могут видеть только свой каталог приложений, доступ к которому осуществляется с помощью Context.getExternalFilesDir(), и определенные типы носителей. Рекомендуется использовать хранилище с областью действия, если вашему приложению не требуется доступ к файлу, который не находится ни в каталоге приложения, ни в MediaStore. Вы можете сослаться на Управление доступом к внешней области хранения с областью действия .

если вы не хотите изменений, вы хотите придерживаться того, что работало раньше.

Для Android Q вы можете попробовать добавить android:requestLegacyExternalStorage="true" к вашему элементу <application> в манифесте. ,

...