Воспроизведение звука в didReceiveRemoteNotification, в то время как в фоновом режиме, используя функцию преобразования текста в речь
Поэтому сейчас я пытаюсь воспроизвести сообщение, когда приложение получает удаленное уведомление, находясь в фоновом режиме (или, вероятно, проснувшись из приостановленного состояния).
Звук не воспроизводится вообще после выхода приложения из режима ожидания.
Когда приложение находится на переднем плане, звук воспроизводится сразу после didReceiveRemoteNotification:
метод называется.
Что было бы подходящим способом, чтобы звуки воспроизводились немедленно, когда didReceiveRemoteNotification:
метод вызывается, когда приложение просыпается из приостановленного режима?
Вот некоторый код (класс менеджера речи):
-(void)textToSpeechWithMessage:(NSString*)message andLanguageCode:(NSString*)languageCode{
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
DLog(@"Activating audio session");
if (![audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionMixWithOthers error:&error]) {
DLog(@"Unable to set audio session category: %@", error);
}
BOOL result = [audioSession setActive:YES error:&error];
if (!result) {
DLog(@"Error activating audio session: %@", error);
}else{
AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:message];
[utterance setRate:0.5f];
[utterance setVolume:0.8f];
utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:languageCode];
[self.synthesizer speakUtterance:utterance];
}
}
-(void)textToSpeechWithMessage:(NSString*)message{
[self textToSpeechWithMessage:message andLanguageCode:[[NSLocale preferredLanguages] objectAtIndex:0]];
}
И позже в AppDelegate
:
[[MCSpeechManager sharedInstance] textToSpeechWithMessage:messageText];
Я включил аудио,AirPlay и изображение в картинке в разделе Возможности-> Фоновые режимы.
РЕДАКТИРОВАТЬ:
Может быть, я должен запустить фоновую задачу и запустить обработчик истечения срока действия, если это необходимо? Я думаю, это может сработать, но я также хотел бы услышать общий способ решения подобных ситуаций.
Также с этим кодом я получаю следующую ошибку, когда получаю уведомление в фоновом режиме:
Ошибка активации аудиосеанса: Ошибка Domain=NSOSStatusErrorDomain Code=561015905 "(null)"
Код 561015905 относится к:
AVAudioSessionErrorCodeCannotStartPlaying = '! Pla', /* 0x21706C61, 561015905
И это описано как:
Этот тип ошибки может возникать, если список свойств информации приложения не позволяет использовать аудио, или если приложение находится в фоновом режиме и использует категорию, которая не допускает фоновое аудио.
но я получаю ту же ошибку с другими категориями (AVAudioSessionCategoryAmbient
а также AVAudioSessionCategorySoloAmbient
)
2 ответа
Поскольку я не могу воспроизвести ошибку, которую вы описываете, позвольте мне предложить несколько указателей и некоторый код.
- Вы собираете / тестируете / работаете с последним SDK? Там были значительные изменения вокруг механизма уведомлений в iOS X
- Я должен предположить, что обращение к
didReceiveRemoteNotification
должно произойти в ответ на действие пользователя из указанного уведомления, например, при нажатии на сообщение уведомления. - Нет необходимости устанавливать какие-либо фоновые режимы. Приложение загружает контент в ответ на push-уведомления.
Если все вышеприведенные утверждения верны, настоящий ответ будет сосредоточен на том, что происходит при получении уведомления.
- Устройство получает уведомление
- Пользователь нажимает на сообщение
- Приложение запускается
didReceiveRemoteNotification
вызывается
На шаге 4 textToSpeechWithMessage
работает как положено:
func application(_ application: UIApplication,
didReceiveRemoteNotification
userInfo: [AnyHashable : Any],
fetchCompletionHandler completionHandler:
@escaping (UIBackgroundFetchResult) -> Void) {
textToSpeechWithMessage(message: "Speak up", "en-US")
}
Для простоты я использую OneSignal для подключения уведомлений:
import OneSignal
...
_ = OneSignal.init(launchOptions: launchOptions,
appId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
// or
_ = OneSignal.init(launchOptions: launchOptions,
appId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
{
(s:String?, t:[AnyHashable : Any]?, u:Bool) in
self.textToSpeechWithMessage(message: "OneDignal", "en-US")
}
textToSpeechWithMessage
в основном нетронутый, вот он в Swift 3 для полноты:
import AVFoundation
...
let synthesizer = AVSpeechSynthesizer()
func textToSpeechWithMessage(message:String, _ languageCode:String)
{
let audioSession = AVAudioSession.sharedInstance()
print("Activating audio session")
do {
try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord,
with: [AVAudioSessionCategoryOptions.defaultToSpeaker,
AVAudioSessionCategoryOptions.mixWithOthers]
)
try audioSession.setActive(true)
let utterance = AVSpeechUtterance(string:message)
utterance.rate = 0.5
utterance.volume = 0.8
utterance.voice = AVSpeechSynthesisVoice(language: languageCode)
self.synthesizer.speak(utterance)
} catch {
print("Unable to set audio session category: %@", error);
}
}
Пожалуйста, реализуйте
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;
метод. Вы получите обратный вызов в фоновом режиме для воспроизведения аудио.