最近IAP尿酸高是不是肾有问题有问题,测试购买总是失败

豆丁微信公众号
君,已阅读到文档的结尾了呢~~
IAP-SDK 返回码速查手册手册,sdk,速查手册,码速查手册
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
IAP-SDK 返回码速查手册
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='http://www.docin.com/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口本帖已被设为精华帖!
1.平时测试接口,总是现写代码,对测试用例的管理,以及测试报告的管理持久化做的不够,
2.工作中移动端开发和后端开发总是不能并行进行,需要一个mock的依赖来让他们并行开发。
3.同时让自己锻炼去开发测试平台,掌握flask开发程序,提高自己的业务水平。
整体思路:
1.利用flask+bootstrap来进行web界面开发,对接口,接口测试用例,定时任务,测试报告的持续集成。
2.IAPTest支持接口用例管理,接口多用例测试,支持定时测试任务,测试报告持久化
3.目前mock服务支持单一path,定时任务可以开启暂停多用例执行,定时任务执行后自动发送测试报告,多用例的单次执行,单接口的调试功能。对测试环境的管理
下面来看下最后的效果图,以及附上github开源地址。
测试环境管理界面:
定时任务界面:
测试报告界面
用例管理界面
接口管理界面
核心代码分享区:
定时任务对应视图开发
class StartTaskView(MethodView):#开始定时任务
@login_required
def get(self,id):
task=Task.query.filter_by(id=id).first()
if len(task.interface.all())&=1:
flash('定时任务执行过程的测试用例为多用例,请你谅解')
redirect(url_for('timingtask'))
scheduler.add_job(func=addtask, id=str(id), args=str(id),trigger=eval(task.taskstart),replace_existing=True)
task.yunxing_status='启动'
db.session.commit()
flash(u'定时任务启动成功!')
redirect(url_for('timingtask'))
except Exception as e:
flash(u'定时任务启动失败!请检查任务的各项内容各项内容是否正常')
return redirect(url_for('timingtask'))
class ZantingtaskView(MethodView):#暂停定时任务
@login_required
def get(self,id):
task = Task.query.filter_by(id=id).first()
scheduler.pause_job(str(id))
task.yunxing_status = '暂停'
db.session.commit()
flash(u'定时任务暂停成功!')
return redirect(url_for('timingtask'))
task.yunxing_status = '创建'
db.session.commit()
flash(u'定时任务暂停失败!已经为您初始化')
return redirect(url_for('timingtask'))
class HuifutaskView(MethodView):#回复定时任务
@login_required
def get(self,id):
task = Task.query.filter_by(id=id).first()
scheduler.resume_job(str(id))
task.yunxing_status='启动'
db.session.commit()
flash(u'定时任务恢复成功!')
return redirect(url_for('timingtask'))
task.yunxing_status = '创建'
db.session.commit()
flash(u'定时任务恢复失败!已经为您初始化')
return redirect(url_for('timingtask'))
class YichuTaskView(MethodView):#移除定时任务
@login_required
def get(self,id):
task = Task.query.filter_by(id=id).first()
scheduler.delete_job(str(id))
task.yunxing_status='关闭'
db.session.commit()
flash(u'定时任务移除成功!')
return redirect(url_for('timingtask'))
task.yunxing_status = '创建'
db.session.commit()
flash(u'定时任务移除失败!已经为您初始化')
return redirect(url_for('timingtask'))
定时任务所执行的func代码
def addtask(id):#定时任务执行的时候所用的函数
in_id=int(id)
task=Task.query.filter_by(id=in_id).first()
starttime = datetime.datetime.now()
star = time.time()
day = time.strftime("%Y%m%d%H%M", time.localtime(time.time()))
basedir = os.path.abspath(os.path.dirname(__file__))
file_dir = os.path.join(basedir, 'upload')
file = os.path.join(file_dir, (day + '.log'))
if os.path.exists(file) is False:
os.system('touch %s' % file)
filepath = os.path.join(file_dir, (day + '.html'))
if os.path.exists(filepath) is False:
os.system(r'touch %s' % filepath)
projecct_list = []
model_list = []
Interface_name_list = []
Interface_url_list = []
Interface_meth_list = []
Interface_pase_list = []
Interface_assert_list = []
Interface_headers_list = []
id_list = []
for task_yongli in task.interface.all():
id_list.append(task_yongli.id)
projecct_list.append(task_yongli.projects)
model_list.append(task_yongli.models)
Interface_url_list.append(task_yongli.Interface_url)
Interface_name_list.append(task_yongli.Interface_name)
Interface_meth_list.append(task_yongli.Interface_meth)
Interface_pase_list.append(task_yongli.Interface_pase)
Interface_assert_list.append(task_yongli.Interface_assert)
Interface_headers_list.append(task_yongli.Interface_headers)
apitest = ApiTestCase(Interface_url_list, Interface_meth_list, Interface_pase_list, Interface_assert_list, file,
Interface_headers_list)
result_toal, result_pass, result_fail, relusts, bask_list = apitest.testapi()
endtime = datetime.datetime.now()
end = time.time()
createHtml(titles=u'接口测试报告', filepath=filepath, starttime=starttime, endtime=endtime, passge=result_pass,
fail=result_fail, id=id_list, name=projecct_list, headers=Interface_headers_list,
coneent=Interface_url_list, url=Interface_meth_list, meth=Interface_pase_list,
yuqi=Interface_assert_list, json=bask_list, relusts=relusts)
hour = end - star
user_id = User.query.filter_by(role_id=2).first().id
new_reust = TestResult(Test_user_id=user_id, test_num=result_toal, pass_num=result_pass, fail_num=result_fail,
test_time=starttime, hour_time=hour, test_rep=(day + '.html'), test_log=(day + '.log'))
email = EmailReport.query.filter_by(role_id=2, default_set=True).first()
send_emails(sender=email.send_email, receivers=task.taskrepor_to, password=email.send_email_password,
smtp=email.stmp_email, port=email.port, fujian1=file, fujian2=filepath, subject=u'%s自动用例执行测试报告' % day,
url='%stest_rep'%(request.url_root))
db.session.add(new_reust)
db.session.commit()
mock服务的一个请求方式的代码
class MakemockserverView(MethodView):#做一个mock服务
def get(self,path):#get请求方法
huoqupath=Mockserver.query.filter_by(path=path,status=True).first()
heders=request.headers
method=request.method
if not huoqupath:
abort(404)
if method.lower() !=huoqupath.methods:
jsonify({'code':'-1','message':'请求方式错误!','data':''})
if huoqupath.is_headers==True:
if comp_dict(heders,huoqupath.headers) ==True:
if huoqupath.ischeck==True:
paerm = request.values.to_dict()
if dict_par(paerm,huoqupath.params)==True:
if huoqupath.rebacktype == 'json':
json_fan = json.dumps(huoqupath.fanhui)
return jsonify({'code': '1', 'message': 'successs', 'data': json_fan})
return jsonify({'code': '-2', 'message': '你写入的返回不能正常json!请检查', 'data': ''})
elif huoqupath.rebacktype == 'xml':
response = make_response(huoqupath.fanhui)
response.content_type = 'application/xml'
return response
return jsonify({'code': '-2', 'message': '你写入的类型目前系统不支持', 'data': ''})
return jsonify({'code': '-4', 'message': '你输入的参数不正确', 'data': ''})
if huoqupath.rebacktype=='json':
json_fan=json.dumps(huoqupath.fanhui)
jsonify({'code': '1', 'message': 'successs', 'data':json_fan})
return jsonify({'code': '-2', 'message': '你写入的返回不能正常json!请检查', 'data': ''})
elif huoqupath.rebacktype =='xml':
response=make_response(huoqupath.fanhui)
response.content_type='application/xml'
return response
return jsonify({'code': '-2', 'message': '你写入的类型目前系统不支持', 'data': ''})
return jsonify({'code': '-3', 'message': '安全校验失败!', 'data': ''})
if huoqupath.ischeck == True:
paerm = request.values.to_dict()
if dict_par(paerm, huoqupath.params) == True:
if huoqupath.rebacktype == 'json':
json_fan = json.dumps(huoqupath.fanhui)
return jsonify({'code': '1', 'message': 'successs', 'data': json_fan})
return jsonify({'code': '-2', 'message': '你写入的返回不能正常json!请检查', 'data': ''})
elif huoqupath.rebacktype == 'xml':
response = make_response(huoqupath.fanhui)
response.content_type = 'application/xml'
return response
return jsonify({'code': '-2', 'message': '你写入的类型目前系统不支持', 'data': ''})
return jsonify({'code': '-4', 'message': '你输入的参数不正确', 'data': ''})
if huoqupath.rebacktype == 'json':
json_fan = json.dumps(huoqupath.fanhui)
return jsonify({'code': '1', 'message': 'successs', 'data': json_fan})
return jsonify({'code': '-2', 'message': '你写入的返回不能正常json!请检查', 'data': ''})
elif huoqupath.rebacktype == 'xml':
response = make_response(huoqupath.fanhui)
response.content_type = 'application/xml'
return response
return jsonify({'code': '-2', 'message': '你写入的类型目前系统不支持', 'data': ''}) #
开源地址:
使用说明:
1.依赖包为requirements.txt文件下的,可能部分不全,需要什么可以自己使用中增加。
2.目前由于考虑后续迁移内部使用的话,所以移除了注册功能,改为管理员后台添加方式,默认登录:liwanlei
密码:liwanlei
3.部分功能调试还存在一定的问题,欢迎各位多提宝贵意见,
部分功能欠缺:
定时任务的持久化,现在处理容易受到运行过程中的宕机等情况重新启动服务器的定时任务全部需要开启
mock接口只能支持单一的path
测试环境没有改为动态配置,动态支持。目前测试环境管理以及上线
部分地方可能还会有不严谨性,但是工具可以使用。
目前仅支持 http请求中的json格式的,
大家可以多提意见,后续会优化,最近一直熬夜加班可能有些消息不能及时回复,还望谅解。
项目开发中,有些功能的开发参照了论坛部分作者的文章给我学习上面指引了方向,感恩testerhome,
测试路上,我一直在前进,感恩各位社区大拿的分享的好技术,好文章
附言 1 &·&
增加体验地址。临时地址
账号:liwanlei
密码:liwanlei
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
继续努力。
想请问下,界面是用什么做的呢
if huoqupath.is_headers==True:
if comp_dict(heders,huoqupath.headers) ==True:
if huoqupath.ischeck==True:
paerm = request.values.to_dict()
if dict_par(paerm,huoqupath.params)==True:
if huoqupath.rebacktype == 'json':
代码需要优化,判断条件太多且重复,需要抽离方法,先提一个,判断 True 用 is 不用 ==
建议把任务管理独立模块化或者做成service。
目前没有这个打算,后期可以优化
有些地方看是重复,但是有的地方的检验是必须的,优化后续再进行。
可以做环境分离 建议参考hdc插件的设计
Hdc插件是什么,没了解呢,请指点
Chrome 一个api插件 类似psotman
后续可以研究研究优化进去。
将本帖设为了精华贴
厉害!前来捧场
正好最新在学习flask,这次有代码可以看了,谢谢!
里面的Task类,是自己实现的吗?
好巧,我用reactjs+flask+unitest,也写了个。
问一下,支持多接口间传参吗?支持数据库查询值作为参数吗?支持对json类型返回值的解析吗?
下库下了一个小时
用例就是存数据库。json支持的,你说的多接口传参什么意思。
没救了,网速
我需要先请求创建订单的接口,才能生成相应的订单id;然后下一个编辑订单的接口里,我需要用这个订单id作为入参;额外需要的能力是,接口返回的是json格式的内容,而这个id是json内的很多个键值对的其中之一,所以需要解析json才能拿到这个id值;
现在有个接口,他的入参之一是个时间值,规则是不能超过当前日期60天,不能低于当前时间30天,例如现在是12月5日,那么这个参数只能是2月5日之前,1月5日之后的时间值(大约的数值,没有判定31天什么的),那么在你的平台我要如何生成这个时间值?
我这里的接口都是保证接口测试的独立性。
你的意思是你的接口只能独立测试(也就是单接口测试),而不能组成业务流程?那直接用postman不就好了?postman有分组协作功能的,完全可以当做一个平台使用
业务流那是另外一种,我这种服务的是单独的接口测试,想改业务流的那种也可以。目前没有做到那一步。工具选择根据自己的业务和自己公司的情况来定,工具不是万能的,只能是大家一起努力让工具更加万能
其实把前一个接口的返回值保存起来(文件、常量或者数据库),下个接口再去取,并读取解析到指定字段就可以了。我的平台已经实现了,有空再整理下分享出来。
,如果真的支持业务接口串行了,那你这个可以做爬虫了 ,
我们最近也要做一个自动化测试平台,包含ui自动化和接口自动化,另外包含部分运维功能。
给点儿建议:
1、可以再增加一些返回是html的解析。在判断期望值和接口返回值的时候做一下兼容。
2、接口测试方法要改一下,最好重新封装,做一些兼容。尽量把错误抛出来,不要错误就返回空{},可以改成{‘error’:str(e)}
在报告里面给出来。
3、换数据库
另外有些表单的处理,并没有触发相关的sql,可以改进一下。一个人写这样很不错了,我们三个人做一个平台,还没搞定。
这个就是我前段时间想做的,但是实践有点难啊,虽然已经写好了接口的PO框架,但不知如何和flask结合起来,我要好好看下你写的,学习一下
—— 来自TesterHome官方
你们开发用的也是Python么,我对Python. mock不是很了解,我们公司开发语言是Java,能用Python模拟java的mock么,目前mock都是开发自己写的,比如放款功能,如果可以用Python写的话那就是福音了,哈哈哈哈哈哈
—— 来自TesterHome官方
可以的,完全可以实现。
仅楼主可见
想请问下楼主,自动化测试的投入产出比咋样,或者通过什么措施将自动化测试价值体现到最大。现在比较困惑这一点,求交流。
我之前也有这个困惑,这个投入产出跟你做的自动化项目框架、项目需求是否稳定等各种原因堆积在一起的。如果需求经常变更,甚至ui经常变更,这种做自动化项目投入比较大,。当然不管怎么样,一个好的框架,能提高产出比。
注意,我这里说到的是接口,接口变动的相对于ui低,我也在力推接口。
对于mock 可以更好的改进一下,可以通过jsonpath 匹配post 中的json ,还有一个就是可以控制mock response status 和header ,还有回调方法!还有一种需要解决的问题就是如何处理pathvaribal 的请求方式!
太厉害了。。希望有一天自己也能像你一样维护自己搭建的测试框架
没看懂最后的接口管理界面和用例管理界面的区别是什么,为什么要设计两个,看内容感觉好像一回事儿
接口管理和接口用例这两个功能都不一样,依据接口管理的接口来写接口测试用例。一个管理接口,一个管理用例
我感觉两个场景都是可以实现的,目前没有加入进去这个,第一个场景 技术处理还简单,第二个 能实现,但是做出来也内部用行, 一般我做的 基于的都是通用的,类似你说的这种可以实现,但是不通用的,不能做到所有的接口都支持,只能是尽可能的去满足大部分的接口测试,迁移到公司用的开放平台都会二次开发,因为这些做的都是针对通用的技术比较多。
谢谢建议,数据库我才用的是最简单方便的,表单处理上面会如果产生数据的交互才会触发,这个数据库迁移还是很快的,我在迁移到公司来说,这个sqlite 满足业务需求,增加运维平台这里我感觉应该运维是一个单独的平台更好,UI自动化的测试平台其实好做了很多,接口能做出来,做UI就不难,关键是需求,还有三个人并行开发的配合能力、。
后方可回复, 如果你还没有账号请点击这里 。
liwanlei (李雷雷)
第 8523 位会员 /
共收到 37 条回复在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
APP是首次开发 还没有迭代任何一个版本 1.0也没有提交过审核现在想在应用内添加IAP 在iTunes connect里添加了APP内购买项目
现在一直是这个状态
请问IAP可以单独提交审核么?(不和APP一起)如果想用测试账号进行购买测试 要在审核通过了之后才能进行么?
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
第一次添加IAP要随App新版本一起提交,测试的话可以在iTunes Connect里面的Users and Roles里添加几个Sandbox tester来测试。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
这个状态就可以测试了。 记得用申请的测试账号
同步到新浪微博
分享到微博?
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:
在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。苹果应用内购买(IAP)—从入门到放弃苹果应用内购买(IAP)—从入门到放弃网易企业服务百家号文本总结了大量IAP相关的规则、设计开发要点和实践经验,适合产品需要做IAP和所有对IAP知识感兴趣的策划、交互、开发、测试。●●●IAP规则详解本文所述IAP(In-App Purchase),特指苹果App Store的应用内购买,是苹果为App内购买虚拟商品或服务提供的一套交易系统。首先来讨论一下IAP的基本规则以及其中的一些要点:1.1适用范围在App内需要付费使用的产品功能或虚拟商品/服务,如游戏道具、电子书、音乐、视频、订阅会员、App的高级功能等。App内购买实体商品(如淘宝买衣服)不适用IAP,不在App内使用的虚拟商品(如充话费)或服务(如滴滴叫车)也不适用IAP。那么问题来了,假如在App内购买一个音乐专辑,既能在App里面听数字专辑,同时也能获得实体商品cd,适不适用IAP呢?答案是适用的。因为App内的数字专辑和实体商品cd在使用上是可以分离的,数字专辑符合IAP的适用范围,购买就要用IAP。否则各种游戏里面卖648的道具,都声称商品不仅包含游戏道具,购买后还能获得一个5毛钱的实体纪念品(举例),就直接绕过IAP,苹果岂不玩蛋?苹果规定,适用范围内的虚拟商品或服务,必须使用IAP购买支付,不允许使用支付宝、微信支付等其它支付方式(包括Apple Pay),也不允许以任何方式(包括跳出App、提示文案等)引导用户通过应用外部渠道购买。原则上苹果也不允许通过外部兑换码等方式在应用内解锁虚拟商品或服务,但实际上兑换码的限制是有些模糊的,因为有些App可以在应用内获得兑换码(比如活动发放优惠券或签到奖励),很难严格界定是一个外部兑换码还是内容兑换码。因此,在IAP购买中使用优惠券抵扣一般情况下是允许的,但如果很明显地引导用户在App外购买兑换码,再在App内兑换成虚拟商品或服务,是会被苹果Reject的。另外在App Store Review Guidelines 3.1.4 里面还有这样一条特殊规则:“Appfeatures that work in combination with an approved physical product (such as atoy) on an optional basis may unlock functionality without using IAP,provided that an IAP option is available as well.”意思就是说,用户在App内购买一个功能,而这个功能需要和一个实体商品结合起来使用,这种情况下,允许使用IAP之外的方式来解锁功能,但前提是仍然需要提供IAP购买的选项。比如用户在一个健康管理App内购买一个高级计步器功能,但这个计步器功能需要跟手环配合使用,要和手环打包购买。这个情况下,App可以在IAP购买的选项基础上,再提供其它的购买方式。但现实中好像并见过没有这样的案例。因为App完全可以把计步器变成免费功能,只是没有手环不起实际作用,然后把手环当成是一个在App外使用的实体商品,这样跟IAP就没有半毛钱关系了。谁没事找事还把这个东西做成IAP还要给苹果分成啊~另外还有一些跨平台同步的复杂案例,在本文的第三部分再进一步介绍。1.2 IAP类型如前面说的,IAP是一套商品交易系统,而非简单的支付系统。每一个购买项目都需要在App的itunes connect后台创建一个商品,提交给苹果审核,审核通过后,购买项目才会生效。在创建IAP商品时,主要有4种类型可供选择:1.2.1 Consumable products该类型适用于可多次购买的消耗型项目,如游戏道具、虚拟币等。1.2.2 Non-consumable products该类型适用于一次购买永久有效的项目,如电子书、游戏关卡等。该类型项目支持跨设备同步和本地restore,比如说,用户在某个App中购买了一本书,可在所有相同Apple ID设备的App中免费获取这本书,而不要需要借助App本身的账号体系,即使在App中删除了这本书,也可免费重新获取。1.2.3 Auto-renewable subscriptions该类型适用于自动续费的订阅项目,如Apple Music的按月订阅,用户购买后会每月自动续费,直到用户手动取消或者开发者下架IAP项目。类似Non-consumableproducts,该类型也支持跨设备同步和本地restore机制。之前这种类型只支持newsstand类别(报刊杂志)的App,从2016年6月开始支持所有类型的App,但除了newsstand类别之外,国内的App很少使用这种类型的内购。1.2.4 Non-renewable subscriptions该类型适用于固定有效期的非自动续费项目,如云音乐的会员和一些视频App的会员。没有跨设备同步和本地restore机制,用户可以多次购买。1.2.5 Free subscriptions该类型是Auto-renewable subscriptions的一个特例,适用于免费的订阅项目,仅支持newsstand类别的App,同样支持跨设备同步和本地restore机制。《In-AppPurchase Programming Guide》详细说明了各种类型的适用范围和特性:其中需要特别注意的是:1针对Non-consumableproducts类型的IAP项目,苹果会要求App提供一个“恢复购买”的功能,以支持跨设备同步和本地restore。同时,如果App本身有用户账号系统,那么用户只要付费一次,就可以通过restore机制将IAP项目无限复制到多个用户账号下,坑爹~因此,对于类似电子书之类的一次购买永久有效的项目,如果希望使用App本身的用户账号系统,避开跨设备同步和本地restore机制,可以考虑选择Non-renewable subscriptions类型。同时,考虑到Non-renewablesubscriptions一般是有固定有效期的,可以加一个无限长的有效期(比如9999天),以应对苹果审核。2Consumable products和Non-renewable subscriptions都是可以重复购买的IAP项目,前者更偏向消耗品,后者更偏向订阅品。另外还有一个区别是,针对Non-renewable subscriptions的IAP项目,用户如果之前已经买过一次,过期后再次购买或者切换App账号后购买,支付流程中会出现一个系统弹窗提示用户之前已经购买过该项目,是否要再次购买,如果用户不小心点了取消,支付流程就会终止。苹果设计这个弹窗的本意更多是根据Apple ID识别用户身份,避免用户重复购买相同项目。但对于有用户账号体系的App,这个提示是有点多余的,虽然影响不大。因此,如果一个IAP项目既适用于Consumable products也适用于Non-renewable subscriptions,比较建议选择Consumableproducts。1.3定价在创建IAP项目的时候,需要设定价格,这个价格只能从苹果预设的价格等级中选择,比如等级1对应1美元、6元人民币,等级2对应2美元、12元人民币……最高等级87对应999.99美元、6498元人民币。另外可能是为了照顾某些货币区的开发者和用户,还有一些特殊的等级,比如备用等级A对应1美元、1元人民币,备用等级B对应1美元、3元人民币这样。除此之外,IAP项目不能定一个9.9元人民币这样不符合任何等级的价格。详细价格等级表可以看苹果的官方文档:苹果的价格等级表通常是不会调整的,但也不排除在某些货币汇率发生巨大变化的情况下,对该货币的定价进行调整,调整前苹果会发邮件通知开发者。另外,价格等级表中不同货币的汇率关系与实际汇率存在差异,淘宝上有部分低价的iOS游戏内购代充就是利用了某些货币的汇率差来做生意。对于开发者来说,如果App在中国区以外发布,可能需要注意一下汇率的问题。某些地区的内购结算成人民币后收入会低于相应价格等级的人民币收入,所以在一些需要严格计算实际收入的情况下(比如财务统计营收,或内购收入需要进一步与平台CP方进行分成),可能需要根据内购的实际支付货币及金额和还有相应汇率来计算收入,或者也可以用一些办法来限制某些地区的内购(在本文2.2部分会讲)。补充说明一下,IAP项目的价格在商品发布以后是可以在itunes connect后台修改的,也可以设置限时优惠价。但是大部分联网App的内购项目价格是从自己的服务端获取的,如果要修改价格或设置限时优惠,需要两边一起处理,还是挺麻烦的。1.4分成很多人都知道,App Store上的付费App和App内购,苹果与开发者默认是3/7分成。但实际上,在某些地区苹果与开发者分成之前需要先扣除交易税,开发者的实际分成不一定是70%。从2015年10月开始,苹果对中国地区的App Store购买扣除了2%的交易税,对于中国区账号购买的IAP,开发者的实际分成在68%~69%之间。而且中国以外不同地区的交易税标准也存在差异,如1.3中所述,如果需要严格计算实际收入,可能需要把这个部分也考虑进来。针对不同地区的内购,内购价格和对应的开发者实际收入在苹果的价格等级表(1.3中的链接)中有详细列举。另外,根据苹果在2016年6月的新规则,针对Auto-RenewableSubscription类型的IAP,如果用户购买的订阅时间超过1年,那么从第二年开始,开发者可以获得85%的分成。详情可查看:1.5结算针对IAP的交易收入,苹果一般以5周(每年1/4/7/10月)或4周(其余月份)作为一个结算周期,并在每个结算周期结束后第33天向开发者付账。●●●IAP设计开发要点1.创建和提交IAP项目开发IAP之前需要先在itunes connect后台创建IAP商品,并按规范填写product id、商品名称、价格、截图等信息。如果App当前版本支持新增的IAP项目,可不用发版直接提交IAP审核。如果需要App新功能配合,则需要和App版本一起提交。《In-AppPurchase Configuration Guide for iTunes Connect》详细介绍了IAP的创建和提交流程:其中需要特别注意的是:1.1尽量不要删除已创建的IAP已创建的IAP除了product id之外的所有信息都可以修改,如果删除了一个IAP,将无法再创建一个相同product id的IAP,也意味着该product id永久失效。而product id一般有特定的命名规则,用来标示App内的购买项目,如果命名规则下有某个product id永久失效,可能会导致整个product id命名规则都要修改,掉进坑里~1.2注意区分reference name和display namereferencename是给开发者自己看的,display name会在IAP支付流程的确认购买系统弹窗中展示给用户,而且不能随意修改(修改需要重新提交IAP审核),所以命名的时候要弄清楚。1.3当App审核被拒时如果IAP随App版本一起提交审核,有问题时所有新提交的IAP项目和App版本会同时被拒,再次提交App审核时,一定要记得重新提交所有IAP项目(每个IAP还得要手动编辑一下才能重新提交真麻烦),否则苹果是无法继续审核的,不要傻傻的等上半个月发现苹果一点反应都没有~2 IAP支付流程这部分内容属于功能实现的逻辑,同样在《In-App Purchase Programming Guide》中有详细说明:个人觉得产品的策划或交互也非常有必要了解一下其中的业务逻辑,才能和开发一起设计出用户体验比较好的功能方案。具体来说,IAP的支付模式分为客户端校验和服务端校验2种模式,客户端校验模式因为容易伪造支付凭据,安全性比较低,一般只有非常简单的单机App才会使用,大部分App都会采用服务端校验模式。另外不同类型的IAP支付流程也会有一些小差异(主要是restore机制),下面就以最常用的Consumable products和Non-renewablesubscriptions类型为例,来说明一下IAP的支付流程:用户准备购买某个项目时,App客户端通过product id向苹果API请求支付信息手机系统弹窗验证用户的Apple ID(可能需要输入Apple ID密码或验证touch ID)Apple ID验证完成后,苹果API向App客户端返回用户将要支付的价格和货币单位App客户端再次验证product id对应的支付价格和货币单位无误(可跳过),继续请求支付手机系统弹窗提示用户确认将要购买的内容和价格,用户点击确认购买App客户端获得苹果API返回的支付成功通知以及支付凭据,向App服务端请求校验支付凭据App服务端拿到客户端的支付凭据,再向苹果服务器请求校验支付凭据(避免一些越狱插件伪造客户端支付凭据)App服务端校验支付凭据成功,通知App客户端App收到支付凭据校验成功通知,代表用户付费成功,再处理后续业务逻辑以上就是一个标准的IAP支付流程,看上去顺理成章,但实际上有很多坑,下面重点来讲一下需要注意的问题。3不能忽视的坑3.1延迟返回支付结果在上述流程的步骤6,由于网络问题等种种原因,即使用户已经付款成功,客户端也可能一时半会收不到苹果API的支付成功通知,也无法主动向苹果API请求查询支付状态,只能被动等待通知。因此有些情况下,客户端会延迟收到支付成功的通知(可能是过了几分钟,也有可能是下次打开App的时候),针对这种情况,需要做好两件事:客户端本地保存所有支付结果未确认的交易信息,并设置一个监听进程,在收到支付成功的信息后,继续处理这笔交易的后续流程。极端情况下,用户在交易结果未确认的情况下删除App,保存在App本地数据库中的交易信息也会丢失,因此,更好的方案是把交易信息存到iOS系统的keychain里面当本地存在支付结果未确认的交易信息时,在交互上提示用户可能需要等待支付结果,避免用户重复付款3.2服务端校验延迟在上述流程6~8的支付凭据校验过程中,因为网络问题等各种原因,客户端可能无法及时收到服务端的校验成功通知,类似的,这种情况需要:客户端本地保存支付凭据,并持续向服务端轮询校验结果,直到返回明确的校验成功或校验无效的结果。支付凭据最好也保存在keychain里面在客户端向服务端轮询结果时,为了避免用户在支付结果页面等待过久,交互层面上可以先结束支付流程(经过一定超时时间),同时提示用户需要等待支付结果,避免用户重复付款3.3非官方渠道包支付失败问题在上述流程步骤1中,如果用户安装的App不是AppStore官方渠道包(从PP助手、同步推等第三方应用商店下载),苹果API会直接返回product id不存在并结束支付流程,在交互层面上表现为用户点击购买后直接提示支付失败。这个问题曾经困扰我们很长一段时间,并且网上查不到任何相似问题的信息,用尽了日志埋点和用户调研等一系列手段,最后才定位出来。类似的,越狱设备在安装某些内购破解插件后,也会导致无法进行内购(返回product id不存在)。不过现在iOS设备的越狱比例已经非常低了,基本可以忽略。因此,针对这个问题的解决办法是:当返回product id不存在时,提示用户安装的可能是非官方渠道包,引导用户到App Store下载官方渠道包。3.4货币校验如本文1.3部分所述,如果App在中国区以外发布,但由于某些原因又希望限制某些地区账号的内购,可以在上述流程的步骤4校验用户支付的货币单位,并禁止某些货币的购买。同时在交互上也要给用户相应的提示,类似不支持特殊地区账号购买的弹窗说明。3.5未绑定App Store支付方式的用户支付流程这是一个巨大的坑!如果用户在内购前未绑定App Store的支付方式,在上述流程的步骤5,点击系统弹窗(第1次)的确认购买后,会自动跳转到App Store的绑定支付方式界面。接着如果顺利完成支付方式的绑定,会再自动跳转跳回App,再次出现系统弹窗(第2次)让用户确认购买。但是,当用户点击系统弹窗(第1次)的确认购买后,苹果API会立即向客户端返回支付失败...支付失败...失败......一般情况下,客户端收到支付失败的返回,理所应当认为支付已经取消了,而丢弃本地的交易信息。但万万没想到后面用户绑定支付方式完成后会继续确认购买,这简直就是苹果IAP系统设计的一个大bug!如果知道了这个坑,解决方案也很简单,就是在苹果API返回支付失败时,用类似2.3.1的方式处理,保留待确认的交易信息并持续监听支付结果返回。●●●更多IAP实践经验总结1匿名购买很多App在第一次提交IAP时都会因为不支持匿名购买被拒,原因是App Store ReviewGuidelines要求App在非必要的情况下,不允许强制用户注册/登录后才能使用某些功能。一般情况下,对于没有IAP的App,强制用户注册/登录才能使用是不会被拒的(除非遇到很苛刻的审核人员),但是对于IAP,一般都会要求支持匿名购买。当然你也可以尝试编一堆原因说明为什么强制用户注册/登录是必要的(比如提供的商品或服务需要获取用户手机号或邮箱之类的理由),但也不能保证说服审核人员。支持匿名购买,通常需要在用户未登录App账号的情况下,临时保存用户的购买记录,并在用户登录后合并到App账号数据。2跨平台同步虽然在原则上,苹果不允许通过外部渠道解锁App内需要付费才能使用的功能或虚拟商品,比如在web端购买一个课程,在App内观看,但实际在某些条件下是可以做跨平台同步用户购买的内容:在iOSApp内也提供相应商品IAP购买的前提下,通过App账号同步用户在不同平台上购买的内容。这条规则适用到大部分游戏上可能会比较苛刻,但是一般的内容类App都是行的通的。针对电子书、音乐、视频等项目,App只提供单纯的内容阅读/观看功能,而不提供任何发现和订阅内容的功能(比如Kindle iOS版),可支持用户在外部渠道购买内容后在App中使用(具体可参考App Store Review Guidelines 3.1.3)。但实际上是否允许可能也要取决于审核人员的判断,比如云课堂曾经提交过一个版本,不能购买付费课程,但是允许用户在web端购买付费课程后在iOS端观看,就被拒了,理由是付费课程不属于上述条件的内容范畴。3虚拟币由于IAP的价格等级机制,无法支持灵活的商品定价(如9.9元人民币)和营销功能(如优惠券抵扣等),很多App会引入虚拟币,先通过IAP内购充值特定价格的虚拟币(如6、12、18、648等),再使用虚拟币购买具体的商品。类似IAP跨平台同步问题,iOS平台充值的虚拟币不允许和其他平台(Android、web)流通,外部平台充值的虚拟币不能在iOS平台使用,同时iOS平台充值的虚拟币也不能在外部平台使用。但实际中,我们会发现有些App,比如喜马拉雅和得到,支持用户在微信公众号中充值虚拟币(虽然微信充值也区分了iOS平台和其他平台),再在App内使用,并且在App内的充值界面,隐晦的提示用户如果充值遇到问题,可以关注微信公众号获取客服帮助(实际上就是引导用户用微信充值)。这种做法严格意义上是不合规的,但如果苹果审核不严也能通过,算是打擦边球,估计这招效果还不错~4退款问题根据苹果政策,用户在购买IAP后90天内,能以各种原因申请退款(扣款后购买失败、买错了、不喜欢等等),但实际能不能退成功苹果说了算。如果一个用户申请退款成功,苹果会在与开发者结算时记一笔退款订单(当然原来购买成功的订单也在),钱就不给了,而且苹果也不会告诉你是哪个用户退款的,而且用户购买的东西还在,简直就是霸王条件~订单数据可以在itunes connect后台的“付款和财务报告”中查看,但没有详细时间信息和用户信息,很难定位到相应的平台订单。对于游戏或者一些自营平台来说,可能就是少点收入。而对于需要与平台CP方一一分成的产品来说,可能就要亏钱。为了解决这个问题,我们尝试设计过一套复杂的退款订单分配规则,根据IAP订单的时间周期、金额,结合平台订单的一些信息,将IAP退款订单分配到平台订单,由平台和CP方共同承担退款。但是由于开发排期原因,这个方案放了一年多至今都没做……退款都由平台承担了→_→从历史数据来看,一般不遇到大量恶意退款的情况下,IAP的退款率可能在1~3%之间(取决于App内容质量、用户心情,还有苹果的心情)。对于IAP营收额很大的App,可能需要考虑一下退款的问题。5支付成功率云课堂曾经对比过iPhone端使用支付宝/微信支付(注意:绕过IAP使用第三方支付属于违规行为,可能导致应用下架或开发者被封号,切勿模仿!)和IAP的支付数据,发现第三方支付的用户支付成功率大概是IAP的2~3倍,反映在营收上也差了2倍多。不难理解,国内App Store的用户支付习惯肯定不如第三方支付成熟。而经过进一步的用户问卷调研,发现影响IAP支付成功率的因素有很多方面:用户安装的App来自第三方应用商店或使用越狱设备,无法使用IAP支付用户未绑定App Store支付方式用户在IAP支付过程绑定支付方式遇到问题,放弃了以上数据仅代表云课堂iPhone端的用户群,某种意义上也说明云课堂的用户比较小白(产品本身的目标用户很大一部分就是小白),没接触过IAP这种支付方式。不同产品的目标用户群的App Store内购使用习惯肯定也存在差异。不过,随着App Store内购的普及(一方面是游戏内购带动,另一方面也得益于苹果的推广,比如经常搞一些App一元购活动,还有从2016年11月开始支持绑定支付宝),用户的内购习惯也在持续养成,从数据上也能看出IAP支付成功率的上升趋势,对于接入IAP的产品是利好的。以上由网易企业服务-企业信息化服务提供商:湖南领先网络科技 整理发布。网易企业服务(qiye163.co)是网易凭借其20年品牌优势与经验打造的企业级产品矩阵,致力于提供一站式企业信息化解决方案。网易企业服务的推出,是网易在企业邮箱的基础上对企业市场的进一步重要布局。湖南领先网络科技是网易企业产品一级经销商,专业为企业提供一站式信息化解决方案。本文仅代表作者观点,不代表百度立场。系作者授权百家号发表,未经许可不得转载。网易企业服务百家号最近更新:简介:网易企业服务-企业信息化专属服务平台作者最新文章相关文章

我要回帖

更多关于 靳东走路是不是有问题 的文章

 

随机推荐