我所在的是一个小团队,从 2015 年底开发、运营一款供房地产经纪人使用的免费的工具 App ,使用极光差不多两年了。在使用中遇到过一些或有趣或挠头或无奈的事,下面摘录一二与大家分享。

1

♤♤ 应用的最初版本功能是单一的,只有最基本的功能,也不要求用户注册,所以根本就没考虑过推送功能,就连 App 的开发也是外包给几位前同事业余时间搞出来的。

♤♤ 随着功能的完善和用户量的增加,推送功能也就提上了日程。极光在推送服务这方面做的不错,所以就选择了极光,当然是免费版😎。

♤♤ 我是做服务端接口的。在接下来挺长一段时间内,推送都没有用服务端 SDK 调用 Push API ,而是我们的运营人员登录极光网站,手动群推一些版本升级、活动上线之类的——当时我们连后台都没有,用户使用数据都是在友盟后台看的——所以我就告诉安卓的开发 s ,去极光注册个账号和应用,然后自己参考安卓 sdk 集成进应用里;然后把账号给 ios 开发 p ,自己看 Appkey 、 ios 的 sdk ,也集成进 ios 版应用里。

♤♤ 直到有一天,需要把人工审核用户所提交资料的结果推送给用户,这就需要服务端代码调用极光的推送 API ,我登录进极光账号一看,居然有两个应用,就去问 s ,在用的是哪一个,回答是两个都在用,一个是 android 平台,另一个 ios 平台。当时我就不淡定了:

  • “为什么注册两个应用啊?不应该是一个应用推到两个平台吗?”
  • -“ p 说苹果的推送机制跟安卓不一样,所以他又注册了一个。”
  • “可是极光推送是可以选择要推的平台啊,当时你没觉得有什么不对吗?”
  • -“没啊,我觉得他说的挺有道理。可能 ios 就是这样的吧……”
  • “……那么你们测试时,和运营手动推的时候是怎么推的?”
  • -“测试时各测各的,运营就是同样的消息推两次。”

♤♤ 于是,如今我们的极光账户下有两个应用,分别对应 android 和 ios 平台,群推消息时一个消息推两次😭……

♤♤ 如果有刚用极光的新手看本文的话,作为长者我可以给一点经验:

  • 针对一个 App 申请一个极光应用就可以了,在推送时可以通过 setPlatform() 指定要推送的平台。不过,如果你的开发环境和生产环境是分开的,就要注意了, ios 是可以设定推送环境的(下文会讲到),安卓就只能自己区分推送环境了。

  • 为了避免开发环境的消息推送到生产环境这样的情况,可以另外申请个极光应用给安卓的开发环境用,把 AppKey 写进环境变量里。当然也有其他办法,比如给不同环境的用户设置不同的别名或标签;但是这样也不保险,特别是群推或者推所有人时。

2

♤♤ 前面说了我们是小团队,没有专职的测试,一般是产品兼任了测试的工作。

♤♤ 一次版本上线前内测,产品反馈说 ios 的消息推不到,但手动推送是能推到的。我检查代码后发现忘记改推送环境参数了,消息推送到生产环境了;而手动推时因为是可视化的界面,不容易错过这个参数。

♤♤ 不过,虽然我知道一定有个地方可以修改推送环境,但我找遍 Node.js 的 SDK 都没发现怎么改。最后看过 REST API 才知道是 setOptions 方法。在 github 上极光的 Node.js SDK 文档是这样写的:

setOptions: 设置options,本方法接收5个参数,sendno(int),time_to_live(int),override_msg_id(int),apns_production(boolean),big_push_duration(int)

♤♤ 就这样,只告诉我有这 5 个参数,却没有解释这 5 个参数是什么意思😥。

♤♤ 所以做服务端开发的小伙伴们,不要只看 Java 、PHP、C#、Node.js 这些语言的服务端 SDK ,虽然它有文档还有示例,但它只是对 REST API 的封装,看 REST API 的文档还是很有必要的。

3

♤♤ 某天,运营提出了需求,要写一个系统服务定期推送消息,内容是对用户在过去一段时间的 App 使用情况总结,比如发布了多少产品,有多少浏览量、点赞量、电话量,和同城市的平均值以及比较,用户点击通知栏消息会跳转到应用内一个界面查看更多详情以及图表之类。

♤♤ 由于每个用户的推送内容都不一样,就只能使用别名来单个推送。而悲催的极光免费套餐对推送速度有限制,单个消息推送速度是每分钟限制600条(就是调用接口的速度,忘记在哪儿看到的了,好像是在QQ官方的开发者群里?),极光的技术建议最好自己限制推送速度,我就只好增加了延时。而且通知栏每条消息就那么一两行再去掉标题也显示不了多少内容,类似的像支付宝“年度账单” 之类的往往就是群推一条通知,用户点进去看详情。

♤♤ 我找到管运营的老板 y总,痛陈利弊之后,他说:带胶布(大丈夫),咱们应用目前用户数不多,能送达的就更少了,就这么先推着吧……

♤♤ 可以预见地,当某天我们的用户数增长到一整天也推不完的时候,这个消息就再也没有推过(事实上是为了减轻服务器负担,没让服务自动跑,而是手动在闲暇时启动,我经常忘记推了23333)。

♤♤ 还有一个略坑的地方就是,极光的免费版套餐在 Report Api 提供的功能比收费版要少,没有送达的原因比较复杂,尤其是安卓,无法知道用户是卸载了应用还是没有启动应用(接收服务),所以无法标记哪些用户是死的、无法送达的——下次就不推这个用户了。

♤♤ 像这样把所有用户单个推一遍的事最好不要做,能群推就尽量群推吧,群推所有人也只是调一次接口。虽然免费套餐群推速度也有共享每秒 20 万条的限制,但也足够用了,免费的就不用奢求太多啦。

4

♤♤ 还是推送消息数量的问题。应用增加了内容运营,不久后推广、客服伙伴们反馈,有用户觉得推送太频繁,把通知权限给关了。

♤♤ 可是事实上我们的推送并不多,在没有版本升级唤醒、活动上线的等特殊情况下,大概每周群推一次。想来想去只有小编会每天推消息了,一问小编,小编说她每天推三四次,除了早上定时发一次外,每次有新文章发布就会推😰。

♤♤ 推送多了,问题也跟着来了:ios 还好,由于推送机制与安卓不同,只要有网络基本都能到达;但安卓是要接收服务在运行的情况下才能收到,现在的手机厂商的某某 UI 、某某 OS 之类的订制安卓系统,连同助手、管家类的安全软件,通常是不给第三方应用后台运行的权限的。也就意味着你下次再打开这个 APP 之前是不会收到推送的;所以极光有一个可选参数:

time_to_live: int 离线消息保留时长(秒) 推送当前用户不在线时,为该用户保留多长时间的离线消息,以便其上线时再次推送。默认864001天),最长10天。设置为0表示不保留离线消息,只有推送当前在线的用户可以收到。

♤♤ 就在你打开应用的这一刻,所有的离线消息叮咚叮咚都来了。

♤♤ 有用户就说,为什么每次打开你们应用都有四五条未读消息啊,我想说那是你长时间没有打开应用了,积存的离线消息。

♤♤ 幸好我们用的是极光的免费套餐,留存的离线消息数量只有5条,如果是 vip 套餐可以保留 100 条离线消息那该多壮观啊。这就是所谓的塞翁失马,焉知非福吧😎。

♤♤ 当然这是我们推送的失误,直接手动群推的话就用了默认参数,离线消息保留一天。像运营内容、文章资讯这样的不重要的消息,应该只推线上用户或者离线保留时间短一些;像资料审核结果这样比较重要的消息,就应该保留长一些。

♤♤ 不知道极光的 vip 套餐情况怎样,我觉得即使能保留 100 条离线消息,用户在长时间未使用 App 的情况下忽然打开就弹几十上百条消息,用户体验也不会好。最好可以设定保留离线消息的数量,然后给消息设定优先级,比如最多保留 5 条消息,超过 5 条时把优先级低的给顶掉,剩下的 5 条是优先级高的、用户不应该错过的消息。

♤♤ 不过安卓 App 不能后台运行就推不到,这是安卓系统的问题,相信极光也没有好的解决办法,最近在考虑针对小米、华为手机用户,使用官方的系统推送服务 SDK 了。其实开发人员也不想集成多个推送 SDK ,有个想法就是极光能不能代替第三方 App 在小米、华为的系统中注册推送服务,极光就像个适配器,自动识别客户端手机型号使用不同的推送通道。

5

♤♤ 我们知道,极光的 ios 、安卓 SDK 可以设置别名和标签以便作为用户标识来推送。别名只能设置一个,往往用来作为唯一性的标识,比如用户 id ;而标签可以设置多个,在文档里 setAlias 和 setTags 都有这样的说明:

需要理解的是,这个接口是覆盖逻辑,而不是增量逻辑。即新的调用会覆盖之前的设置。

♤♤ 比如打标签时,如果想在旧的标签数组基础上增加一个新的标签字符串,就应该传一个新数组带上所有的旧标签和新标签作为参数。

♤♤ 不过,据说 setAlias 和 setTags 也会互相覆盖,也就是说,如果已经打了别名(无论有没有设置过标签),当你调用 setTags 时,别名会丢失,只有新设置的标签生效。这就有点不符合正常的思维习惯了:别名覆盖别名,标签覆盖标签是可以理解的,都是用新的覆盖旧的;别名和标签互相覆盖就让人摸不着头脑了。对应的是,还有另一个方法 setAliasAndTags ,如果想同时设置别名和标签,就只能调用这个方法了。

♤♤ 这个只是据说,我没做过安卓和ios的开发,不清楚是不是这样。有一次我们的APP ios版打标签时就丢了别名,还好发现得比较早,在提交审核前修复了。

6

♤♤ 随着版本迭代、功能的完善增多,s 的经验和姿势越来越丰富,渐渐成长为老司机。由于他以前是做Java Web 的,就更多的支持后台的开发,安卓的开发就渐渐地交给了新司机 d 。

♤♤ 某个版本开始,要加强新注册用户的粘度,比如注册三天内的用户,推送消息让他们使用隐藏较深、可能没用过的功能。客户端按注册日期设置了标签,测试时没发现问题就上线了。

♤♤ 几天后才发现问题:安卓的新注册用户推不到。我找 d 少:

  • “同样的接口,为什么人家 ios 没问题,就你安卓出了问题?” 这是我质问客户端们的金句,如果只有 ios 或安卓一方出问题,我这样说的时候他们通常无语凝噎了。
  • -“……j 哥,你这样说我就无言以对了。”
  • “肯定是你标签打错了呗。”
  • -“不可能,我当时还把标签的值都打印出来了,你也看到了的。”
  • “你现在调试,我看看你的代码。”

♤♤ 果然发现了问题:拼注册日期字符串的时候,取月份用了.getMonth()方法,而这得到的值是 0-11 。测试时没发现问题是因为直接用这个错误的值测的。

  • d少不好意思地说: -“j哥,要不我改了吧,马上发个新版本。”
  • “这个版本已经上线好几天了,目前已经打了错误标签的人怎么办?他们不升级app的话这个标签永远是错的。”

♤♤ 幸好安卓和ios注册成了两个极光应用,将错就错吧。例如 ios 推标签20161231,安卓推20161131(11 月也有 31 号了,😥汗……);ios 推20170101,安卓就推20170001。我太机智了。也再次说明了塞翁失马,焉知非福啊。

后记

本来标题想用《那些年,使用极光踩过的那些坑》,不过想想并不全是坑,有些坑也不关极光的事。
12 月底的时候就看到这个活动了,磨磨蹭蹭直到昨晚才抽空打了这么多字。