首先跟大家介绍两个核心关键词:通知、透传,通知是发送后会在系统通知栏展现,同时响铃或震动提醒用户,并且点击通知栏可以自定义点击行为,透传是发送后消息后台处理,用户无感知,在相应方法中回调,执行对应操作。
付呗app作为一款我们公司主要的移动收单应用,为商户提供收款语音提醒功能,在推送语音方面面临着很大的挑战:一、语音播报的稳定性,二、推送达到率的高低;
面对商户日交易量增长,商户重需求,android碎片化严重,国产品牌手机严格控制后台推送等这些问题,android客户端在推送语音优化,是一项任重道远的事情,可以说这是一场苦战、鏖战,但是最终通过团队的群策群力,使我们的推送语音播报率有了极大的提升。但是面对飞速增长的交易笔数,战斗还未结束,优化之路就不会停止,借用我们雷总在年中会议说的一句话:保持战斗状态。
遇到的问题:app语音播报最初通过百度语音合成的方式,播报一段收款提醒:付呗为您成功收款0.01元,可能是考虑到简单、方便,直接通过第三方语音合成方案,由于前期对百度语音合成研究不够深入,上线后出现了一系列的问题,比如百度语音初始化、离在线合成失败、音量小等。
查找发现问题:我们增加了一些关键埋点,比如商户手机音量情况,百度语音初始化情况,合成过程中错误回调,通过这些埋点我们快速定位到问题有以下几种可能性:商户手机音量设置问题、android6.0存储权限问题(百度语音配置文件无法写入存储卡)、网络问题(网络慢可能会导致TTS流合成出错)、语音播报延迟,通过这些问题我们给出的方案是通过本地语音代替百度语音合成。
解决方案:下面通过商户最常见的收单语音:付呗为您成功收款0.01元,给大家详细阐述本地语音方案。最初想到可能需要大量的本地语音文件,才能实现,但是想想,其实不然,我们可以将收单语音需求拆分成固定的几段语音,包括付呗(应用名)、为您成功收款、零、点、零、壹、元,这里难点在于解析金额,如下:
public static String transferAmount(String amount) {
if (amount == null || "".equals(amount)) {
return null;
}
String xiaoshu = "";
if (amount.contains(".")) {
int pos = amount.indexOf(".");
xiaoshu = amount.substring(pos + 1);
amount = amount.substring(0, pos);
}
String ret ;
if (amount.length() > 16) {
String low12Bit = amount.substring(amount.length() - 12);
String highBit = amount.substring(0, amount.length() - 12);
ret = processHightBit(highBit) + "兆" + transfer16Bit(low12Bit);
} else {
ret = transfer16Bit(amount);
}
if (amount.equals("0") && !xiaoshu.equals("") && ret.equals("")) {
ret = "零";
}
if (xiaoshu.equals("") || xiaoshu.equals("00") || xiaoshu.equals("0")) {
return ret + "元";
}
return ret + "点" + transferXiaoshu(xiaoshu) + "元";
}
最终返回结果零点零壹元,这样我们就可以将对应的文字,匹配相应的本地音频文件
public static List<Integer> transFormNumFile(String num) {
List<Integer> audio_list = new ArrayList();
for (int i = 0; i < num.length(); i++) {
String n = num.substring(i, i + 1);
if (n.equals("点")) {
audio_list.add(Integer.valueOf(R.raw.voice_point));
} else if (n.equals("零")) {
audio_list.add(Integer.valueOf(R.raw.voice_zero));
} else if (n.equals("壹")) {
audio_list.add(Integer.valueOf(R.raw.voice_one));
} else if (n.equals("貮")) {
audio_list.add(Integer.valueOf(R.raw.voice_two));
} else if (n.equals("叁")) {
audio_list.add(Integer.valueOf(R.raw.voice_three));
} else if (n.equals("肆")) {
audio_list.add(Integer.valueOf(R.raw.voice_four));
} else if (n.equals("伍")) {
audio_list.add(Integer.valueOf(R.raw.voice_five));
} else if (n.equals("陆")) {
audio_list.add(Integer.valueOf(R.raw.voice_six));
} else if (n.equals("柒")) {
audio_list.add(Integer.valueOf(R.raw.voice_seven));
} else if (n.equals("捌")) {
audio_list.add(Integer.valueOf(R.raw.voice_eight));
} else if (n.equals("玖")) {
audio_list.add(Integer.valueOf(R.raw.voice_nine));
} else if (n.equals("拾")) {
audio_list.add(Integer.valueOf(R.raw.voice_ten));
} else if (n.equals("佰")) {
audio_list.add(Integer.valueOf(R.raw.voice_hundred));
} else if (n.equals("仟")) {
audio_list.add(Integer.valueOf(R.raw.voice_thousand));
} else if (n.equals("万")) {
audio_list.add(Integer.valueOf(R.raw.voice_ten_thousand));
} else if (n.equals("元")) {
audio_list.add(Integer.valueOf(R.raw.voice_yuan));
}
} return audio_list;
}
将这些本地音频文件存入数组List,这样通过循环,就能播报出付呗为您成功收款0.01元
for (i = 0; i < sound_map.size(); i++) {
mp = sound_map.get(i);
if (mp != null) {
mp.start();
pauseWhile(mp.getDuration());
}
}
但是我们还存在一些商户手机本身设置问题,因此在播报前,我们做了小小优化,手动将商户手机音量设置成最大,以及在语音设置,增加试听功能,去检测商户手机硬件是否存在问题。
优化进阶:由于Android碎片化严重,以及国内厂商自定义系统,严格限制应用后台服务,像华为、小米、OV等厂商,在手机息屏状态下,会杀死后台推送服务,导致推送不到。这个问题也是行业通病,也是我们付呗app最根本的问题。
在优化之前我们之前单纯的采用阿里云推送,但是出现了一系列问题,比如推送延迟、消息推送过期、推送服务器宕机、国内厂商机型推送率低等,在这个基础之上,我们进行了第一次推送优化:通过接入阿里云辅助通道,由于对推送文档不熟悉,在接入辅助通道时没有考虑到小米推送对标题长度有限制,导致用户初始化阿里云推送就失败了,最后放弃了辅助通道这种方案。于是我们进行了第二次推送优化:通过接入多推送通道方案,来优化国内厂商机型,例如华为手机采用华为推送通道、小米手机采用小米推送通道,其他机型采用阿里云推送或个推推送。大概流程如下:
商户启动应用,将商户基本信息,比如手机品牌(用于选择通道)、商户推送基本信息(推送ID),上报给服务器。根据各个推送文档,接入各个推送,将初始化成功的推送ID,分别上报给服务器,当商户发起支付后,后台根据我们预先设定的策略,比如小米手机采用小米推送、华为手机采用华为推送,选择对应推送通道下发消息。实践证明,推送情况并不是很理想,原因在于厂商维护的自身通道经常出现消息延迟。但是在这一过程中我们收集了一些有用的信息:比如阿里云推送过期、待处理等状态占比情况、设置对推送保活作用、后台支付回调慢等。
在收集这些数据后,我们立马投入到第三次推送优化:接入个推VIP,优化各个通道切换逻辑,完善推送统计、语音锦囊等功能。这里重点讲一下选择通道逻辑:付呗app选择推送通道分为两种:自动选择通道、手动选择通道,其中自动选择通道,原则上通过小米手机采用小米通道、华为手机采用华为通道,但是可能会存在一种情况,小米手机可能小米推送初始化失败,这样就无法选择小米推送通道,这种情况我们会根据各个推送优先级,选择最佳通道。
目前我们设置了阿里云推送优先级最高(sort字段),品牌对应的通道(parent_id),通过这张数据表,可以实现多个通道任意切换,一定程度上避免单一推送通道带来的风险。
接入个推VIP,在线情况下推送到达率非常明显,通过接入OV看护,对OV机型,起到一定程度的保活作用,但是息屏状态下,作用不大,我们通过实践发现通过手机设置耗电保护、自启动、神秘模式等设置,可以起到很大的优化作用,这就是”语音锦囊”。
最后:希望更多的小伙伴一起讨论、交流。