真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

iOS開(kāi)發(fā)微信收款到賬語(yǔ)音提醒功能思路詳解

一、背景

為鐘山等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及鐘山網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、鐘山網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!

為了解決小商戶老板們?cè)陬l繁交易中不方便核對(duì)、確認(rèn)到賬的痛點(diǎn),產(chǎn)品MM提出了新版本需要支持收款到賬語(yǔ)音提醒功能。這篇文章總結(jié)了開(kāi)發(fā)過(guò)程中遇到的坑和一些小技巧。

二、技術(shù)方案

后臺(tái)喚醒App

收款到賬語(yǔ)音提醒需要收款方在收到款后,播放一段TTS合成語(yǔ)音播報(bào)金額,微信在前臺(tái)時(shí)可以通過(guò)模板消息將需要播報(bào)的金額帶下來(lái),再請(qǐng)求TTS數(shù)據(jù)并播放,但是app在掛起或者被kill掉的情況下要如何請(qǐng)求語(yǔ)音數(shù)據(jù)并播放呢?

iOS提供了兩種方式喚醒處于掛起或已經(jīng)被kill掉的app。分別是Silent Notification和VoIP Push Notification,客戶端在被喚醒之后將獲得30s的后臺(tái)運(yùn)行時(shí)間,這段運(yùn)行時(shí)間足以請(qǐng)求合成語(yǔ)音數(shù)據(jù)并播放。

1.Silent Notification:

Silent Notification在iOS7以上便可以支持,但是每小時(shí)能推送的Silent Notification次數(shù)有限制。

2.VoIP Push Notification

VoIP Push Notification則是在iOS8以上才支持的新Push類型,相比于Silent Notification,VoIP Push具有高優(yōu)先級(jí)、低延遲的優(yōu)勢(shì),并且沒(méi)有次數(shù)限制。
對(duì)比這兩種技術(shù)方案,VoIP Push Notification明顯更適合用于收款到賬語(yǔ)音提醒的喚醒方案。

TTS合成語(yǔ)音

TTS語(yǔ)音合成方案分為離線合成方案和在線合成方案,離線合成方案省去網(wǎng)絡(luò)請(qǐng)求,合成速度更快,節(jié)省網(wǎng)絡(luò)流量,但是合成音的聽(tīng)起來(lái)比較機(jī)械,語(yǔ)速和停頓的處理較差一些。如果對(duì)合成音的效果要求不是特別高,可以考慮采用iOS自帶的AVSpeechSynthesis框架,免去語(yǔ)音庫(kù)的合入,減少安裝包大小。

在線合成方案的效果則相對(duì)更像人聲,富有感情。考慮到產(chǎn)品體驗(yàn),我們采用了搜索產(chǎn)品部提供的在線語(yǔ)音合成方案,接入方式可以看這篇文章。合成音格式支持wav,mp3,silk,amr,speex,對(duì)比后發(fā)現(xiàn),在合成相同文本的情況下,amr的壓縮率最高,但是能聽(tīng)到音質(zhì)下降明顯。silk格式壓縮率次高,且能保持相對(duì)清晰的音質(zhì),單條合成語(yǔ)音大小在2KB左右。

喚醒后播放音頻文件

在請(qǐng)求到合成語(yǔ)音后,要在后臺(tái)或者鎖屏狀態(tài)下播放音頻文件,AVAudio Session的Category值需要使用AVAudioSessionCategoryPlayback或是AVAudioSessionCategoryPlayAndRecord,CategoryOptions根據(jù)實(shí)際需要可選擇MixWithOthers(與其他聲音混音)或是DuckOthers(調(diào)低其他聲音的音量)。

iOS開(kāi)發(fā)微信收款到賬語(yǔ)音提醒功能思路詳解

需要注意的是,只有iOS10以上才支持app被喚醒后在后臺(tái)/鎖屏狀態(tài)下播放音頻。所以iOS10以下的設(shè)備,在收到VoIP Push后只能在local push上設(shè)定一段固定鈴聲,這也是為什么iOS10以下只有“微信支付收款到賬”,而沒(méi)有后面具體的金額數(shù)值。

三、靜音開(kāi)關(guān)檢測(cè)

不幸的是,在產(chǎn)品發(fā)布后沒(méi)多久就受到了某互聯(lián)網(wǎng)大佬的吐槽。

iOS開(kāi)發(fā)微信收款到賬語(yǔ)音提醒功能思路詳解

從產(chǎn)品體驗(yàn)上來(lái)說(shuō),收款到賬的金額播報(bào)是隨著local push的彈出一起播放的,更像是一種特殊的push鈴聲,而蘋(píng)果對(duì)push鈴聲的處理是受到靜音開(kāi)關(guān)控制的,所以講道理,這個(gè)吐槽是合理的。然而前面提到App在被VoIP Push喚醒之后,需要將AudioSessionCategory設(shè)置為AVAudioSessionCategoryPlayback或AVAudioSessionCategoryPlayAndRecord才可以在后臺(tái)播放音頻文件,這兩種模式是不受靜音開(kāi)關(guān)控制的。要實(shí)現(xiàn)這個(gè)需求,就必須獲取當(dāng)前靜音開(kāi)關(guān)的狀態(tài)。而蘋(píng)果在iOS5之后并沒(méi)有明確地提供一種方式讓開(kāi)發(fā)獲取靜音開(kāi)關(guān)的狀態(tài),這就陷入了一個(gè)尷尬的局面。

蘋(píng)果在iOS5之前可以使用以下方式監(jiān)聽(tīng)靜音鍵開(kāi)關(guān)

- (BOOL)isMuted 
{ 
 CFStringRef route; 
 UInt32 routeSize = sizeof(CFStringRef); 
 OSStatus status = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &routeSize, &route); 
 if (status == kAudioSessionNoError) 
 { 
  if (route == NULL || !CFStringGetLength(route)) 
   return YES; 
 } 
 return NO; 
}

蘋(píng)果在iOS5之后便禁止了使用這種方式監(jiān)聽(tīng)靜音按鍵,背后的原因應(yīng)該是蘋(píng)果希望開(kāi)發(fā)者使用AVAudioSession來(lái)提供統(tǒng)一的音頻播放效果。

最后我在Reddit上找到了一種曲線救國(guó)的方式,實(shí)現(xiàn)起來(lái)也不復(fù)雜:使用AudioServicesPlaySystemSound播放一段0.2s的空白音頻,并監(jiān)聽(tīng)音頻播放完成事件,如果從開(kāi)始播放到回調(diào)完成方法的間隔時(shí)間小于0.1s,則意味當(dāng)前靜音開(kāi)關(guān)為開(kāi)啟狀態(tài)。

void SoundMuteNotificationCompletionProc(SystemSoundID ssID,void* clientData){
 MMSoundSwitchDetector* detecotr = (__bridge MMSoundSwitchDetector*)clientData;
 [detecotr complete];
}
- (instancetype)init {
 self = [super init];
 if (self) {
  NSURL *pathURL = [[NSBundle mainBundle] URLForResource:@"mute" withExtension:@"caf"];
  if (AudioServicesCreateSystemSoundID((__bridge CFURLRef)pathURL, &_soundId) == kAudioServicesNoError){
   AudioServicesAddSystemSoundCompletion(self.soundId, CFRunLoopGetMain(), kCFRunLoopDefaultMode, SoundMuteNotificationCompletionProc,(__bridge void *)(self));
   UInt32 yes = 1;
   AudioServicesSetProperty(kAudioServicesPropertyIsUISound, sizeof(_soundId),&_soundId,sizeof(yes), &yes);
  } else {
   MMErrorWithModule(LOGMODULE, @"Create Sound Error.");
   _soundId = 0;
  }
 }
 return self;
}
- (void)checkSoundSwitchStatus:(CheckSwitchStatusCompleteBlk)completHandler {
 if (self.soundId == 0) {
  completHandler(YES);
  return;
 }
 self.completeHandler = completHandler;
 self.beginTime = CACurrentMediaTime();
 AudioServicesPlaySystemSound(self.soundId);
}
- (void)complete {
 CFTimeInterval elapsed = CACurrentMediaTime() - self.beginTime;
 BOOL isSwitchOn = elapsed > 0.1;
 if (self.completeHandler) {
  self.completeHandler(isSwitchOn);
 }
}

四、設(shè)置聲音閾值

另外一個(gè)用戶反饋較多的問(wèn)題是聽(tīng)不到播報(bào)聲音,通過(guò)查看日志發(fā)現(xiàn)是觸發(fā)語(yǔ)音播報(bào)時(shí),用戶設(shè)置的系統(tǒng)音量過(guò)小所導(dǎo)致。首先想到的解決方案是直接設(shè)置AVAudioPlayer的volume(或者是AudioQueue中的kAudioQueueParam_Volume),然而實(shí)驗(yàn)過(guò)后發(fā)現(xiàn)這樣行不通,volume屬性受制于系統(tǒng)音量(比如系統(tǒng)volume是0.5,AVAudioPlayer的音量是0.6,則最終的音量為0.5*0.6 =0.3)。要解決音量過(guò)小的問(wèn)題,還是需要通過(guò)調(diào)節(jié)系統(tǒng)音量。最終的解決方案借鑒了進(jìn)入收付款展示二維碼時(shí)自動(dòng)調(diào)節(jié)屏幕亮度的方案:如果屏幕亮度未達(dá)到閾值,則調(diào)高屏幕亮度到閾值,離開(kāi)頁(yè)面時(shí),將亮度設(shè)回原亮度。同理,播放提示音時(shí),若用戶設(shè)置的系統(tǒng)音量小于閾值,則調(diào)節(jié)到閾值。提示音播放完畢后,將提示音調(diào)回原音量。

控制系統(tǒng)音量有兩種方式:

方式一:通過(guò)MPMusicPlayerController設(shè)置音量

MPMusicPlayerController *mpc = [MPMusicPlayerController applicationMusicPlayer];
//This property is deprecated -- use MPVolumeView for volume control instead.
mpc.volume = 0; //0.0~1.0

第一種方式簡(jiǎn)單粗暴,在設(shè)置的時(shí)候會(huì)彈出系統(tǒng)音量提示框,如果用戶在使用app的過(guò)程突然彈出音量框,會(huì)對(duì)用戶造成困擾,不建議使用這種方式,并且蘋(píng)果在iOS7.0以后已將該屬性標(biāo)為deprecated。

方式二:通過(guò)MPVolumeView設(shè)置音量

第二種方式則是將一個(gè)看不見(jiàn)的MPVolumeView添加到當(dāng)前視圖上,系統(tǒng)音量提示框就不會(huì)顯示了

需要注意的是,在調(diào)節(jié)完系統(tǒng)音量需要將MPVolumeView移除,否則后續(xù)用戶手動(dòng)調(diào)節(jié)音量會(huì)出現(xiàn)系統(tǒng)音量提示框不顯示的情況。

調(diào)節(jié)音量的方式,則是先取到MPVolumeView中名為MPVolumeSlider的子View,并對(duì)其發(fā)送模擬用戶操作的事件。

- (void)setSystemVolume:(float)volume {
 UISlider* volumeViewSlider = nil;
 for (UIView *view in [self.m_privateVoulmeView subviews]){
  if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
   volumeViewSlider = (UISlider*)view;
   break;
  }
 }
 if (volumeViewSlider != nil) {
  [volumeViewSlider setValue:volume animated:NO];
  //通過(guò)send
  [volumeViewSlider sendActionsForControlEvents:UIControlEventTouchUpInside];
 }
}

總結(jié)

以上所述是小編給大家介紹的iOS開(kāi)發(fā)微信收款到賬語(yǔ)音提醒功能思路詳解,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)創(chuàng)新互聯(lián)網(wǎng)站的支持!


本文題目:iOS開(kāi)發(fā)微信收款到賬語(yǔ)音提醒功能思路詳解
文章分享:http://weahome.cn/article/jiesee.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部