服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - IOS - iOS开发微信收款到账语音提醒功能思路详解

iOS开发微信收款到账语音提醒功能思路详解

2021-03-27 17:17腾讯bugly IOS

这篇文章主要介绍了iOS开发微信收款到账语音提醒功能思路详解,需要的朋友可以参考下

一、背景

为了解决小商户老板们在频繁交易中不方便核对、确认到账的痛点,产品mm提出了新版本需要支持收款到账语音提醒功能。这篇文章总结了开发过程中遇到的坑和一些小技巧。

二、技术方案

后台唤醒app

收款到账语音提醒需要收款方在收到款后,播放一段tts合成语音播报金额,微信在前台时可以通过模板消息将需要播报的金额带下来,再请求tts数据并播放,但是app在挂起或者被kill掉的情况下要如何请求语音数据并播放呢?

ios提供了两种方式唤醒处于挂起或已经被kill掉的app。分别是silent notification和voip push notification,客户端在被唤醒之后将获得30s的后台运行时间,这段运行时间足以请求合成语音数据并播放。

1.silent notification:

silent notification在ios7以上便可以支持,但是每小时能推送的silent notification次数有限制。

2.voip push notification

voip push notification则是在ios8以上才支持的新push类型,相比于silent notification,voip push具有高优先级、低延迟的优势,并且没有次数限制。
对比这两种技术方案,voip push notification明显更适合用于收款到账语音提醒的唤醒方案。

tts合成语音

tts语音合成方案分为离线合成方案和在线合成方案,离线合成方案省去网络请求,合成速度更快,节省网络流量,但是合成音的听起来比较机械,语速和停顿的处理较差一些。如果对合成音的效果要求不是特别高,可以考虑采用ios自带的avspeechsynthesis框架,免去语音库的合入,减少安装包大小。

在线合成方案的效果则相对更像人声,富有感情。考虑到产品体验,我们采用了搜索产品部提供的在线语音合成方案,接入方式可以看这篇文章。合成音格式支持wav,mp3,silk,amr,speex,对比后发现,在合成相同文本的情况下,amr的压缩率最高,但是能听到音质下降明显。silk格式压缩率次高,且能保持相对清晰的音质,单条合成语音大小在2kb左右。

唤醒后播放音频文件

在请求到合成语音后,要在后台或者锁屏状态下播放音频文件,avaudio session的category值需要使用avaudiosessioncategoryplayback或是avaudiosessioncategoryplayandrecord,categoryoptions根据实际需要可选择mixwithothers(与其他声音混音)或是duckothers(调低其他声音的音量)。

iOS开发微信收款到账语音提醒功能思路详解

需要注意的是,只有ios10以上才支持app被唤醒后在后台/锁屏状态下播放音频。所以ios10以下的设备,在收到voip push后只能在local push上设定一段固定铃声,这也是为什么ios10以下只有“微信支付收款到账”,而没有后面具体的金额数值。

三、静音开关检测

不幸的是,在产品发布后没多久就受到了某互联网大佬的吐槽。

iOS开发微信收款到账语音提醒功能思路详解

从产品体验上来说,收款到账的金额播报是随着local push的弹出一起播放的,更像是一种特殊的push铃声,而苹果对push铃声的处理是受到静音开关控制的,所以讲道理,这个吐槽是合理的。然而前面提到app在被voip push唤醒之后,需要将audiosessioncategory设置为avaudiosessioncategoryplayback或avaudiosessioncategoryplayandrecord才可以在后台播放音频文件,这两种模式是不受静音开关控制的。要实现这个需求,就必须获取当前静音开关的状态。而苹果在ios5之后并没有明确地提供一种方式让开发获取静音开关的状态,这就陷入了一个尴尬的局面。

苹果在ios5之前可以使用以下方式监听静音键开关

?
1
2
3
4
5
6
7
8
9
10
11
12
- (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;
}

苹果在ios5之后便禁止了使用这种方式监听静音按键,背后的原因应该是苹果希望开发者使用avaudiosession来提供统一的音频播放效果。

最后我在reddit上找到了一种曲线救国的方式,实现起来也不复杂:使用audioservicesplaysystemsound播放一段0.2s的空白音频,并监听音频播放完成事件,如果从开始播放到回调完成方法的间隔时间小于0.1s,则意味当前静音开关为开启状态。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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);
 }
}

四、设置声音阈值

另外一个用户反馈较多的问题是听不到播报声音,通过查看日志发现是触发语音播报时,用户设置的系统音量过小所导致。首先想到的解决方案是直接设置avaudioplayer的volume(或者是audioqueue中的kaudioqueueparam_volume),然而实验过后发现这样行不通,volume属性受制于系统音量(比如系统volume是0.5,avaudioplayer的音量是0.6,则最终的音量为0.5*0.6 =0.3)。要解决音量过小的问题,还是需要通过调节系统音量。最终的解决方案借鉴了进入收付款展示二维码时自动调节屏幕亮度的方案:如果屏幕亮度未达到阈值,则调高屏幕亮度到阈值,离开页面时,将亮度设回原亮度。同理,播放提示音时,若用户设置的系统音量小于阈值,则调节到阈值。提示音播放完毕后,将提示音调回原音量。

控制系统音量有两种方式:

方式一:通过mpmusicplayercontroller设置音量

?
1
2
3
mpmusicplayercontroller *mpc = [mpmusicplayercontroller applicationmusicplayer];
//this property is deprecated -- use mpvolumeview for volume control instead.
mpc.volume = 0; //0.0~1.0

第一种方式简单粗暴,在设置的时候会弹出系统音量提示框,如果用户在使用app的过程突然弹出音量框,会对用户造成困扰,不建议使用这种方式,并且苹果在ios7.0以后已将该属性标为deprecated。

方式二:通过mpvolumeview设置音量

第二种方式则是将一个看不见的mpvolumeview添加到当前视图上,系统音量提示框就不会显示了

需要注意的是,在调节完系统音量需要将mpvolumeview移除,否则后续用户手动调节音量会出现系统音量提示框不显示的情况。

调节音量的方式,则是先取到mpvolumeview中名为mpvolumeslider的子view,并对其发送模拟用户操作的事件。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (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];
  //通过send
  [volumeviewslider sendactionsforcontrolevents:uicontroleventtouchupinside];
 }
}

总结

以上所述是小编给大家介绍的ios开发微信收款到账语音提醒功能思路详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!

原文链接:http://www.cnblogs.com/bugly/archive/2017/09/11/7504984.html
 

延伸 · 阅读

精彩推荐
  • IOSiOS中tableview 两级cell的展开与收回的示例代码

    iOS中tableview 两级cell的展开与收回的示例代码

    本篇文章主要介绍了iOS中tableview 两级cell的展开与收回的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    J_Kang3862021-04-22
  • IOSIOS 屏幕适配方案实现缩放window的示例代码

    IOS 屏幕适配方案实现缩放window的示例代码

    这篇文章主要介绍了IOS 屏幕适配方案实现缩放window的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    xiari5772021-06-01
  • IOSIOS开发之字典转字符串的实例详解

    IOS开发之字典转字符串的实例详解

    这篇文章主要介绍了IOS开发之字典转字符串的实例详解的相关资料,希望通过本文能帮助到大家,让大家掌握这样的方法,需要的朋友可以参考下...

    苦练内功5832021-04-01
  • IOSiOS通过逆向理解Block的内存模型

    iOS通过逆向理解Block的内存模型

    自从对 iOS 的逆向初窥门径后,我也经常通过它来分析一些比较大的应用,参考一下这些应用中某些功能的实现。这个探索的过程乐趣多多,不仅能满足自...

    Swiftyper12832021-03-03
  • IOS关于iOS自适应cell行高的那些事儿

    关于iOS自适应cell行高的那些事儿

    这篇文章主要给大家介绍了关于iOS自适应cell行高的那些事儿,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    daisy6092021-05-17
  • IOSiOS布局渲染之UIView方法的调用时机详解

    iOS布局渲染之UIView方法的调用时机详解

    在你刚开始开发 iOS 应用时,最难避免或者是调试的就是和布局相关的问题,下面这篇文章主要给大家介绍了关于iOS布局渲染之UIView方法调用时机的相关资料...

    windtersharp7642021-05-04
  • IOS解析iOS开发中的FirstResponder第一响应对象

    解析iOS开发中的FirstResponder第一响应对象

    这篇文章主要介绍了解析iOS开发中的FirstResponder第一响应对象,包括View的FirstResponder的释放问题,需要的朋友可以参考下...

    一片枫叶4662020-12-25
  • IOSiOS 雷达效果实例详解

    iOS 雷达效果实例详解

    这篇文章主要介绍了iOS 雷达效果实例详解的相关资料,需要的朋友可以参考下...

    SimpleWorld11022021-01-28