To go to the new company to take over the project need to do voice broadcast, similar to "Alipay to the account 100 yuan", the last developer just did the front desk broadcast, relatively simple, after receiving the push, in the func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) uses AVSpeechSynthesizer for speech synthesis broadcast
- New requirements after taking over the project: background programs need to do voice reporting after a kill, but because the kill has to be done by the user in order to do so, it is definitely not possible to do this in appdelegate, baidu has taken a look at ios 10's unnotification service extension to fix the problem
Integrated unnotificationservice extension
Step 2: Click Next
发现我们工程中多了 NotificationService.swift 文件,根据苹果官方文档,NotificationService.swift是为了丰富推送,给程序员修改推送内容的一次机会,相当于推送过来 我们会在NotificationService.swift中提前拿到通知,然后才会到推送弹框展示在用户眼前
iOS12.1之前语音播报
Since we can get the notification in advance, we make a push judgment in the NotificationService .swift to see if it is a voice broadcast or an ordinary push
We see that there is a method in the NotificationService .swift:
if let content = request.content.userInfo as? Dictionary<String,Any>,
let aps = content["aps"] as? Dictionary<String,Any>,
let alert = aps["alert"] as? Dictionary<String,Any>,
let str = alert["subtitle"] as? String{
}
Here add the str attribute we got is the content we want to broadcast, for example, str = "a card receives 100 yuan", and then we will broadcast by speech synthesis, the code is as follows:
let speaker = AVSpeechSynthesizer()
let utterance = AVSpeechUtterance(string: str)
utterance.rate = 0.5
et voice = AVSpeechSynthesisVoice(language: "zh-CN")
utterance.volume = 1
utterance.voice = voice
speaker.speak(utterance)
Writing here, tried, OK, perfect solution, front desk, backstage, program kill voice broadcast perfect, but after the line, sad, customer report voice broadcast no sound, I immediately tested, no problem, AH, then I tried my colleague's cell phone. It was silent. I looked it up on the internet and found that after 12.1, notificationservice. In Swift, Apple doesn't allow voice-synced broadcasts, and the official document reads something like this: “I'm notificationservice.”. Swift is to enrich the notice, but you used to do a voice broadcast, I am not happy, do not use. Finished, since in the program background, killing the case of voice broadcast, not to write here, no place to go. I tried a lot of things, but I couldn't figure it out, so I went back to the notificationservice. Swift, since you won't let me do voice synthesis, I'll have to play the voice file using local notifications.
iOS12.1以后语音播报
1. First of all we need to record voice files, you can use Baidu, Iflytek, etc. , here I use Baidu Voice, using Python script to generate files, do not want to run Python files directly to my code to copy, the Pyhton file is as follows:
# -*- coding: utf-8 -*-
import os
from aip import AipSpeech
APP_ID = '15977485'
API_KEY = '9pQMw3sDbsjlc88PupjK63g8'
SECRET_KEY = '6pYLyuxadNvBTpRoRuAssOrbIxBwoK9G'
client = AipSpeech(APP_ID,API_KEY,SECRET_KEY)
def functionNum(num):
if(num == 0):
return "0"
elif(num == 1):
return "1"
elif (num == 2):
return "2"
elif (num == 3):
return "3"
elif (num == 4):
return "4"
elif (num == 5):
return "5"
elif (num == 6):
return "6"
elif (num == 7):
return "7"
elif (num == 8):
return "8"
elif (num == 9):
return "9"
elif (num == 10):
return "十"
elif (num == 11):
return "百"
elif (num == 12):
return "千"
elif (num == 13):
return "万"
elif (num == 14):
return "点"
elif (num == 15):
return "元"
elif (num == 16):
return "一卡通到账"
elif (num == 17):
return "一卡通收款一笔"
for i in range(0, 18):
print(os.getcwd())
filePath = '/Users/wang/Desktop/Sound/'
text = functionNum(i)
result = client.synthesis(text,'zh',1,None)
sound = text
if not isinstance(result,dict):
with open(sound+'.mp3','wb') as f:
f.write(result)
print(sound)
When you get the voice file and add it to your project, be sure to check your own project and the unnotificationservice extension project
Start at notificationservice. exe. Write Code in Swift
- 首先还是判断过来的通知是否为语音播报通知(和上面一样)
- Determine the current version number, and then do different processing
if #available(iOS 12.1, *){//判断是否是12.1以上的系统
bestAttemptContent.sound = nil
play_registerNotification(str: str)
}else{ //12.1以下的系统 直接执行语音合成播报
bestAttemptContent.sound = UNNotificationSound.default
playVoiceWithContent(str: str)
contentHandler(bestAttemptContent)
}
-
If this is a pre-ios 12.1 release, broadcast directly (same as above)
-
如果是iOS12.1以后的版本
To withdraw the amount of registered local notice
// MARK: - 使用本地通知12.1以上系统
func play_registerNotification(str:String){
if !str.hasPrefix("一卡通到账"){ //通知内容不是金额播报类型
bestAttemptContent?.sound = UNNotificationSound.default
contentHandler!(bestAttemptContent!)
return
}
if (str as NSString).length <= 10{ //长度问题
bestAttemptContent?.sound = UNNotificationSound.default
contentHandler!(bestAttemptContent!)
return
}
let strCount = (str as NSString).substring(with: NSMakeRange(5, (str as NSString).length-5-1))
print(strCount)
if let countStr = Float(strCount) {
if countStr > 10000.0{
//大于10000播放收款一笔
bestAttemptContent?.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "一卡通收款一笔.mp3"))
contentHandler!(bestAttemptContent!)
return
}else{ //小于10000的播放金额
if let array = stringToArray("\(countStr)") {
print(array)
pushLocalNotification(array, 0)
}
}
}else{
bestAttemptContent?.sound = UNNotificationSound.default
contentHandler!(bestAttemptContent!)
}
}
利用递归一个一个播放
//Mark:-Func Play (Str: String){ if! Str. Hasprefix {//notification content is not the amount broadcast type bestAttemptContent? . sound = UNNotificationSound . Default contentHandler ! (bestAttemptContent!) Return } if (STR a s NSString) . Length & LT; = 10{//the length problem bestAttemptContent ?. Sound = unnotification sound. Default Contenthandler! (bestAttemptContent!) Return } Let strCount = (STR a s NSString) . Substring (with: NSMakeRange (5, (STR a s NSString) . Length-5-1)) print (strCount) I F let countStr = Float (strCount){ if COUNTSTR & GT; 10000.0{//> 10000 play a bestAttemptContent? . sound = UNNotificationSound (named: UNNotificationSoundName (rawValue: “One card pays one sum . MP3”) Contenthandler ! (bestAttemptContent!) Return } else {//play amount less than 10000 if let array = stringToArray (”(COUNTSTR)”){ print (array) pushLocalNotification (array, 0)}}} else { bestAttemptContent ?. Sound = unnotification sound. Default Contenthandler! (bestAttemptContent!)}
我的拆分金额的方法,我们服务器语音播报的消息格式:一卡通到账100.32元
// MARK: - 使用本地通知12.1以上系统
func play_registerNotification(str:String){
if !str.hasPrefix("一卡通到账"){ //通知内容不是金额播报类型
bestAttemptContent?.sound = UNNotificationSound.default
contentHandler!(bestAttemptContent!)
return
}
if (str as NSString).length <= 10{ //长度问题
bestAttemptContent?.sound = UNNotificationSound.default
contentHandler!(bestAttemptContent!)
return
}
let strCount = (str as NSString).substring(with: NSMakeRange(5, (str as NSString).length-5-1))
print(strCount)
if let countStr = Float(strCount) {
if countStr > 10000.0{
//大于10000播放收款一笔
bestAttemptContent?.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "一卡通收款一笔.mp3"))
contentHandler!(bestAttemptContent!)
return
}else{ //小于10000的播放金额
if let array = stringToArray("\(countStr)") {
print(array)
pushLocalNotification(array, 0)
}
}
}else{
bestAttemptContent?.sound = UNNotificationSound.default
contentHandler!(bestAttemptContent!)
}
}
At present, this scheme can solve the problem of voice broadcast, but there are drawbacks, the local push push a voice file will vibrate once, so you can guide users to turn off the vibration. Or multi-recorded voice files, such as 123.06 yuan, can be divided into “One hundred and twenty-three points” and “06 yuan,” with a prefix of more than 1,000 voice files, in the split amount when the method changes according to the actual situation, so that three or four vibration can solve the problem of voice broadcast, but the package will be larger.