問題描述:
業物需求,需要使用類似支付寶收款到賬的通知,之前采用iOS10.0的原線上ServiceExtension進行收到通知修改通知內容然后采用系統AVSpeechSynthesizer 進行播放,iOS10-12.1之前通知一切正常,當12.1一更新之后APP通知會只有通知欄沒有通知語音,因此查閱文檔采坑終于找到了解決方案 ,時間短任務重沒時間寫太多,寫文章半小時前剛搞定,所以暫時先附上代碼有需要的先解決,之后再修改詳細文章。
解決思想
1.先使用訊飛語音合成SDK將文字轉化為PCM格式文件(訊飛只支持這玩意)
2.然后用lame工具轉為MP3格式
3.使用AudioService進行MP3播放(試過其他播放方式不行。。。)
代碼(先湊合看后續更新)
// NotificationService.m
// JZServiceExtension
//
// Created by Jincang Lu on 2018/11/13.
// Copyright ? 2018年 shanghai KaoPush Network Technology Co., Ltd. All rights reserved.
//
#import "NotificationService.h"
#import <AVFoundation/AVFoundation.h>
#import <iflyMSC/iflyMSC.h>
#import "lame.h"
#define kTime 0.6
static SystemSoundID soundID = 10;
#define IF_APPID @"自己申請"
API_AVAILABLE(ios(10.0))
@interface NotificationService ()<AVSpeechSynthesizerDelegate,IFlySpeechSynthesizerDelegate>
@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
@property (nonatomic, strong) IFlySpeechSynthesizer *iFlySpeechSynthesizer;
@end
@implementation NotificationService
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler API_AVAILABLE(ios(10.0)){
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
NSString *initString = [[NSString alloc] initWithFormat:@"appid=%@", IF_APPID];
[IFlySpeechUtility createUtility:initString];
// Modify the notification content here...
self.bestAttemptContent.title = [NSString stringWithFormat:@"%@", self.bestAttemptContent.title];
self.bestAttemptContent.body = [NSString stringWithFormat:@"%@", self.bestAttemptContent.body];
self.bestAttemptContent.sound = nil;
[self syntheticVoice:[NSString stringWithFormat:@"%@",self.bestAttemptContent.body]];
// self.bestAttemptContent.sound = [UNNotificationSound soundNamed:@"xindong.caf"];
}
- (void)syntheticVoice:(NSString *)string {
//獲取語音合成單例
_iFlySpeechSynthesizer = [IFlySpeechSynthesizer sharedInstance];
//設置協議委托對象
_iFlySpeechSynthesizer.delegate = self;
//設置合成參數
//設置在線工作方式
[_iFlySpeechSynthesizer setParameter:[IFlySpeechConstant TYPE_CLOUD]
forKey:[IFlySpeechConstant ENGINE_TYPE]];
//設置音量,取值范圍 0~100
[_iFlySpeechSynthesizer setParameter:@"100"
forKey: [IFlySpeechConstant VOLUME]];
//發音人,默認為”xiaoyan”,可以設置的參數列表可參考“合成發音人列表”
[_iFlySpeechSynthesizer setParameter:@"xiaoyan"
forKey: [IFlySpeechConstant VOICE_NAME]];
//保存合成文件名,如不再需要,設置為nil或者為空表示取消,默認目錄位于library/cache下
[_iFlySpeechSynthesizer setParameter:@"xfffs.pcm"
forKey: [IFlySpeechConstant TTS_AUDIO_PATH]];
//啟動合成會話
// [_iFlySpeechSynthesizer startSpeaking: @"接著到賬111111111110元"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES);
NSString *path = [paths objectAtIndex:0];
NSLog(@"psth==%@",path);
[_iFlySpeechSynthesizer synthesize: string toUri:[NSString stringWithFormat:@"%@/xfffss.pcm",path]];
}
//合成結束
- (void) onCompleted:(IFlySpeechError *) error {
NSLog(@"合成完成--%@-%d",error.errorDesc,error.errorCode);
[self convertToMp3];
self.contentHandler(self.bestAttemptContent);
}
- (void)convertToMp3
{
NSString *fileName = [NSString stringWithFormat:@"/%@.mp3", @"yuyin"];
NSString *filePath = [[NSHomeDirectory() stringByAppendingFormat:@"/Documents/"] stringByAppendingPathComponent:fileName];
NSLog(@"%@",filePath);
// NSString *mp3Url = [NSURL URLWithString:filePath];
@try {
int read,write;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES);
NSString *path = [paths objectAtIndex:0];
//只讀方式打開被轉換音頻文件
FILE *pcm = fopen([[NSString stringWithFormat:@"%@/xfffss.pcm",path] cStringUsingEncoding:1], "rb");
fseek(pcm, 4 * 1024, SEEK_CUR);//刪除頭,否則在前一秒鐘會有雜音
//只寫方式打開生成的MP3文件
FILE *mp3 = fopen([filePath cStringUsingEncoding:1], "wb");
const int PCM_SIZE = 8192;
const int MP3_SIZE = 8192;
short int pcm_buffer[PCM_SIZE * 2];
unsigned char mp3_buffer[MP3_SIZE];
//這里要注意,lame的配置要跟AVAudioRecorder的配置一致,否則會造成轉換不成功
lame_t lame = lame_init();
lame_set_in_samplerate(lame, 11025.0);//采樣率
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
do {
//以二進制形式讀取文件中的數據
read = (int)fread(pcm_buffer, 2 * sizeof(short int), PCM_SIZE, pcm);
if (read == 0)
write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
else
write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
//二進制形式寫數據到文件中 mp3_buffer:數據輸出到文件的緩沖區首地址 write:一個數據塊的字節數 1:指定一次輸出數據塊的個數 mp3:文件指針
fwrite(mp3_buffer, write, 1, mp3);
} while (read != 0);
lame_close(lame);
fclose(mp3);
fclose(pcm);
} @catch (NSException *exception) {
NSLog(@"%@",[exception description]);
} @finally {
NSLog(@"MP3生成成功!!!");
// NSString *str = [_iFlySpeechSynthesizer parameterForKey:[IFlySpeechConstant TTS_AUDIO_PATH]];
// NSString *str = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@/xfff",path] ofType:@"mp3"];
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/yuyin.mp3",[NSHomeDirectory() stringByAppendingFormat:@"/Documents/"]]];
AudioServicesCreateSystemSoundID((__bridge CFURLRef _Nonnull)(url), &soundID);
AudioServicesPlayAlertSound(soundID);
AudioServicesPlayAlertSoundWithCompletion(soundID, ^{
NSLog(@"播放完成");
});
}
}
//合成開始
- (void) onSpeakBegin {
}
//合成緩沖進度
- (void) onBufferProgress:(int) progress message:(NSString *)msg {
NSLog(@"-----進度---------%@",msg);
}
//合成播放進度
- (void) onSpeakProgress:(int) progress beginPos:(int)beginPos endPos:(int)endPos {
NSLog(@"====%d==%d=====",beginPos,endPos);
}
- (void)serviceExtensionTimeWillExpire {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
// self.contentHandler(self.bestAttemptContent);
}
@end```
extension plist里面需要加就可以播放了 如果音質變化需要自己去調試參數
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
QQ 873702616
截止11.16號 支付寶 收錢吧 12.1也沒解決此問題 希望大家盡量先不要在這個方法上浪費太多時間了,上邊這個方法提交版本會有問題,提供一種解決思路 希望大家有后續方案進行探討