项目背景:
长久以来,iOS的灰度一直用的越狱渠道(不用审核,不用审核,不用审核),好处有了,那么问题是什么呢→(没人啊,一周才能上100的安装量啊,然后基本上只能帮我们看看有没有启动就crash,感觉这个如果发现了有点打脸)。于是乎,在@大胖 同学的建议帮助下,开始研究TestFlight及其流程优化。
TestFlight简介:
苹果官方提供给开发者,邀请内测用户的载体(最多邀请10000人)。
TestFlight优化前的完整流程:
TestFlight优化历程:
从上图可以看出几个痛点:
(1) 需要和至少1w个用户沟通,并记录用户的邮箱。
(2) 如果需要不同人群(聊天活跃高的、 录音活跃高的、 活动活跃高的等),那么(1)的沟通成本就会成倍数增加
(3) 用户操作步骤多:提供邮箱、读取邮件且记录邀请码、App Store下载TestFlight、TestFlight输入邀请码下载唱吧
(4) 用户理解要求高,TestFlight面向用户的使用步骤为纯英文,用户无法轻松操作。
既然找到了痛点,那这些就是要优化的地方,所以我们是这样设计的:
(1)针对痛点1和2,首先我们要做的是干掉通过用户收集邮箱的步骤,也就是说我们自己来维护1W个邮箱。这个事情开始困扰了我一段时间,也分别尝试了几个方式:
• 发动同学们一起注册:当前几乎所有的邮箱注册都需要绑定手机号,且最多不超过5个,也就是说,我们需要至少2000个同学(pass);
• 搭建邮箱服务器:时间成本+维护服务器稳定性(pass);
• 某宝shopping1W个:便宜的找不到,贵的买不起(pass);
• @大马 同学偶然提过xx+N@gmail.com 相当于xx@gmail.com,瞬间起飞,匹配TestFlight测试员的格式{email, xx, aa},马上生成了ss+1@gmail.com,xx+1,aa+1 到 ss+10000@gmail.com , xx+10000,aa+10000 ,共10000个邮箱,愉快的下发测试邀请,果然可以收到N封邀请邮件 {perfect}
But,一个坑完了另一个坑又来了,随着接收到的邀请邮件到100封左右,数量就不增加了,于是通过重新下发,换新的邮箱等得出了结论:同一个邮箱“每天”“最多”收到100封左右的邀请邮件。
所以最终的方案是:维护100+邮箱(辛苦团队同学们注册!),每一版TestFlight灰度,分别生成100*100个测试员(简单的循环追加写文件)。
(2)针对痛点3和4,分两步走,第一步:python脚本解析1W封邀请邮件,获取邀请链接。
这里我是用.INI文件{以节(section)和键(key)构成的配置文件}作为存储host、邮箱等数据容器(读取配置文件的方法这里就不介绍了)。
[host]
sina_pophost = pop.sina.com
sohu_pophost = pop3.sohu.com
qq_pophost = pop.qq.com
aliyun_pophost = pop3.aliyun.com
[aliyun]
zzb@aliyun.com = XXXX
zzb@aliyun.com = XXXX
zzb@aliyun.com = XXXX
zzb@aliyun.com = XXXX
主体是通过基于python的poplib模块的POP3类来实现邮件的收取,话不多说,直接上代码: 首先两种登录模式,一种是SSL协议登录,一种是非SSL协议登录。
def login_with_ssl(self, host, username, password):
server = poplib.POP3_SSL(host)
print "username is %s status is %s " % (username, server.getwelcome())
server.user(username)
server.pass_(password)
return server
def login(self, host, username, password):
server = poplib.POP3(host)
print "\n username is %s status is %s " % (username, server.getwelcome())
server.user(username)
server.pass_(password)
return server
然后获取邮件根实例,方便获取邮件的各种信息
def get_msgs(self, server, index):
"""
:param server:
:param index: email_index
:return:
"""
res_status, lines, msgsize = server.retr(index)
msg_content = '\r\n'.join(lines)
msgs = Parser().parsestr(msg_content)
return msgs
再然后是关键的获取邮件信息,并拿到邀请链接。为了拿到邀请链接,先看下邮件的构成,如图
通过开发者工具,我们可以找到{ 标签a的 href 属性}就是我们需要的邀请链接,那么ok,开始撸代码:
def get_identifying_code_url(self, msgs, user_email):
"""
:param msgs: Message对象结构的根实例
:param user_email:
:return:
"""
if msgs.is_multipart():
# get_payload()返回list,包含所有的子对象:
parts = msgs.get_payload()
for n, part in enumerate(parts):
self.get_identifying_code_url(msgs=part, user_email=user_email)
else:
content_type = msgs.get_content_type()
if content_type == 'text/html':
# 纯文本或HTML内容:
content = msgs.get_payload(decode=True)
# 获取文档对象
soup = BeautifulSoup(content, "html.parser")
# 获取tag==a的Tag
tag = soup.a
# 获取tag中的href属性, 也就是我们需要的url
if tag:
url = tag["href"]
url = replace(url, old="https", new="itms-beta")
c = open('url%s.txt ' % self.today_time, 'a')
c.write(user_email + "--" + url + "\n")
c.close()
else:
url = "error! tag is None"
self.write_failure_file(text=url, username=user_email)
elif content_type == 'text/plain':
pass
else:
pass
见code可以看到,直接通过BeautifulSoup实例获取标签a,然后获取href属性,这里大家注意下,我们不只是获取了邀请链接,而是把https换成了items-beta,这个replace会在后面介绍。
说到这基本上处理邮件获取url的脚本就ok了,剩下的遍历邮箱,拿到对应版本的TestFlight链接,区分唱吧或火星(不同的业务线)等逻辑,通过邮件的'From', 'To', 'Subject', "Date"特征来区分,这里就不上code了。
接着回到前面的https替换成items-beta话题上,大家或许注意到,解决痛点3和4我们的第一步是获取邀请链接,而不是邀请码,这是为什么呢,这也就是我们解决痛点3和4的第二步,用户可从唱吧客户端直接内跳至TestFlight,而不是我们再次和用户沟通并转交验证码。
items-beta是TestFlight的URL Scheme,而URL Scheme是苹果提供的一个可以让app相互之间可以跳转的协议。
这样我们就提供了一个邀请弹窗,用户通过点击立即体验按钮,向服务器申请测试资格,服务器下发我们从邮件中读取的邀请链接,客户端收到后直接跳转至App Store TestFlight or 唱吧安装界面,如图:
到此,我们设计的第一版优化就完成了,看下新的流程图
如图,完全干掉了和用户沟通的成本,同时可以筛选当前灰度重要功能活跃度高的用户测试。相对于用户,只需要从唱吧内点击一个按钮,就可以跳转至App Store下载TestFlight,然后安装唱吧(如果已安装过TestFlight,则直接安装唱吧)。
当我们快快乐乐的上线,脸一黑。。。发现给4000个用户下发了2000个邀请链接,一天带来的安装量只有80多个,于是重新分析我们优化后的流程,发现了几个会带来损失的点:
(1)由于怕打扰用户,体验弹窗只会弹出一次,在用户跳转安装TestFlight或者唱吧的过程中,一旦用户关闭该弹窗,则客户端内就不会再有入口暴露给用户;
(2)对用户安装的吸引力小
根据损失点,我们重新调整了策略,在用户点击立即体验的同时,下发notice,给予这些用户体验常驻入口;然后针对所有体验用户,随机抽取部分用户给予一个月会员奖励。就这样,随着新策略上线,同等用户群体1小时内,安装量变成了400+,持续发现概率crash20+(此刻应该有掌声)。 最终的优化流程:
每当你认为要搞定了,八成又要踩坑了,上线几天后,零星收到用户反馈无法正常支付,经过google后,发现TestFlight的支付全部走沙盒,所以非测试AppleId均会支付失败,这都是我们后面要解决的问题。
当然,在踩坑的过程中,我们也get到一些点:某个版本,TestFlight苹果审核过后,提交相同app版本不同build版本,会马上审核过,会马上审核过,会马上审核过,所以为了节省审核时间,我们可以预先提审一个稳定版本(占坑),然后等灰度开始,持续不断地提审该版本。
总结:
整个优化过程就是找坑→填坑→踩坑→续填的过程,每一步都有收获。从用户的角度发现问题,从开发者的角度解决问题,再从用户的角度验证问题。PS 欢迎小伙伴们与我们沟通对TestFlight流程优化的见解,欢迎加入唱吧测试小分队。