目录
准备工作
微信登录和支付
支付宝登录和支付
对比
准备工作
微信
注册微信开放平台,成为开发者(开发)
注册你的App,会给你一个AppId和AppSecret
注册微信商户平台,成为商户(收钱)
会给你一个商户ID
共有三个ID:AppID、AppSecret、PID
支付宝
注册蚂蚁金服开放平台,成为开发者(开发)
开放平台会给你的App一个AppId(支付宝没有AppSecret)
注册蚂蚁金服商家中心,成为商家(收钱)
商家中心会给你一个商家ID
共有两个ID:AppID、PID
微信登录和支付
开放平台创建应用
首先,你在微信开放平台上要有自己的应用
平台会让你上传你的App的logo,名称,简述什么的,因为这些在你调用微信App的时候用得着。
微信登录
首先,要在开放平台中为你的App申请相关接口(微信登录是默认开放给你的)
然后,就是代码工作了。
我是用ShareSDK套件统一实现的微信登录,集成ShareSDK的方法见在App中集成ShareSDK。
登录过程就是调用ShareSDK的函数,传入微信登录的参数
然后,用一个listener去监听登录授权
这个listener会监听到一个Platform对象,从Plateform对象中可以取出用户id、昵称、头像等
so easy
微信支付
支付的基本流程
实现微信支付,流程上比登录复杂多了,具体流程如下:
1.授权
微信第三方支付是需要去开放平台申请权限的:
2.签约
相关的商家需要去在线签约:
3.文档
微信在官方文档中提供了很多种支付方式,我们使用的是其中的App支付:
根据官方文档,支付流程如下:
看起来很复杂,其实大概分这么几步:
1.你的业务服务器和微信后台交互生成订单,微信后台给业务服务器一个预交易订单号
(微信后台准备好支付数据)
2.你的业务服务器给你的App预交易订单号
(你的后台通知你的App去调起微信支付)
3.你的App调起微信App支付,把预交易订单号传给微信App
(你的App发起微信App支付)
4.微信App告知你的App支付完成,微信后台告知你的业务服务器支付完成
(App对App,后台对后台)
整个故事情节大概是这样的
需要注意的是,微信官方文档有这么一句话:
注意一定不能以客户端返回作为用户支付的结果,应以服务器端的接收的支付通知或查询API返回的结果为准。
就是说,你的App只负责触发下一步业务流程,是否支付成功要以你的业务服务器收到的通知为准。
支付的具体实现
代码实现上,微信的官方文档说的挺明白的,照做吧:
1.在gradle里添加引用
2.初始化一个IWXAPI实例
3.利用IWXAPI实例去请求调起支付
4.实现一个给微信支付回调的Activity
在支付完成时,微信App会自动打开这个回调Activity,如果你没有定义这个Activity的外观,你会发现,手机白屏了
你可以好好画画这个Activity的界面,也可以不去管它,在完成下面的操作后,直接关掉。
这个回调Activity,主要功能是接收微信反馈的支付结束事件
反馈的BaseResp对象没啥有用信息,因为微信的App支付接口纯粹是个触发器,只能用来通知支付结束,你从它的反馈信息里,无法得到订单号。
那业务服务器怎么知道是哪个订单完成了支付呢?
你的App和业务服务器自己想办法吧。
支付宝登录和支付
【高能预警】支付宝的文档,真的超级烂!超级烂!超级烂!你可以信任它的支付,但不可以信任它的文档!
【严正警告】除了你抓到的真实数据,不要相信支付宝的官方文档和Demo代码,要小心支付宝!要小心支付宝!要小心支付宝!
开放平台创建应用
首先,你在蚂蚁金服开放平台上要有自己的应用
平台会让你上传你的App的logo,名称,简述什么的,因为这些在你调用支付宝App的时候用得着。
支付宝登录
ShareSDK里没有集成支付宝登录,我们需要自己实现。
登录的基本流程
1.授权
首先,你要去开放平台请求授权
每个App有对应的授权功能列表
点击图中右上角的“继续添加”,可以看到支付宝提供的接口列表,其中有很多迷惑性的名字,要选择恰当的接口服务,我们需要选择的是App支付宝登录
2.签约
很多服务,是需要签约之后才能生效的
签约过程需要一定的周期,而且需要公司相关人员出面
3.文档
是的,虽然支付宝的文档很烂,但是,原始文档还是要看的,App支付宝登录产品介绍
把里面的流程图摘出来
眼花了是不是?梳理一下步骤:
1.你的App调起支付宝App授权,用户确认后,支付宝App返回一个openid和authcode
(支付宝App认可你,给你两样东西,一个是用户id,一个是安全信物)
2.你拿着authcode向支付宝后台服务换一个token
(因为你有安全信物,所以支付宝后台也认可你)
3.有了这个token,其实你就有权限去做很多事情了,比如,再去支付宝后台查查用户的昵称,头像什么的,对应的接口是支付宝用户信息查询接口(这是一个后台接口,我也是在后台做的查询)
(因为支付宝后台认可你,所以你可以去后台查询用户的昵称和头像)
整个流程涉及到你和支付宝双方的App,双方的后台服务器,故事情节大概可以这样理解
这个故事还有另外一个版本:
支付宝:“你要用户ID,还要登录?好啊,没问题”
支付宝:“神马?你要用户昵称和头像?保安!保安!保安!...”
登录的具体实现
在调起支付宝App登录时,其实就是从我们的App里调用支付宝App一个接口函数的过程,大概分三步:
1.准备函数的参数(按照规定的格式,拼出一个请求的String)
2.调用函数(支付宝接口中AuthTask的authV2)
3.接收函数的返回值(一个Map),从中取出authcode和用户openid
步骤很简单吧,支付宝还贴心的提供了demo代码,具体流程是这样的
1.用开放平台给你的AppId,商户PId,RSA私钥一起,拼出请求的String
最终拼出来的authInfo大概长这个样子
2.调用AuthTask的authV2函数
3.把返回的Map映射为AuthResult函数,从中取出authcode和用户id
当然这个过程是异步的,看起来很简单是吧?可是,当我们仔细观摩支付宝官方Demo代码的时候,我们就会发现...
demo代码里有这样一段话
也就是说,第一步是错的,你不要自己去拼参数,因为你的App不能持有RSA私钥!
为什么?因为不安全啊,RSA私钥放在App里,攻击者很容易通过逆向你的App来搞出你的RSA私钥,所以这几乎就相当于面向社会公开了你的银行卡密码啊
那你怎么获取这个参数呢?也就是这个authInfo呢?
我们看authInfo里面的这些字段,其实就是sign需要用到RSA加密,而sign又是安全不可逆的,所以我们可以向我们自己的业务服务要这个sign。
那么业务服务器是怎样生成的这个sign呢?
业务服务器保存有RSA喽...
业务服务器,请你一定要安全啊...
支付宝支付
支付的基本流程
1.授权(参考登录)
2.签约(参考登录)
3.文档(参考登录,这次的官方文档位置在App支付)
根据官方文档,App支付的流程是这样的:
我再来梳理一下步骤,梳理一下步骤:
1.你的业务服务器做好订单信息,安全签名后发给你的App
(你的业务服务器负责RSA加密)
2.你的App拿着订单信息,去请求支付宝App支付
(支付宝App解密订单信息,确认订单安全)
3.支付宝App通知你的App支付完成;同时,支付宝后台服务通知你的业务服务器支付完成)
(App对App,后台对后台)
整个流程涉及到你和支付宝双方的App,双方的后台服务器,故事情节大概可以这样理解
需要注意的是,支付宝官方文档里有这么一句话:
同步返回的数据,只是一个简单的结果通知,商户确定该笔交易付款是否成功需要依赖服务端收到支付宝异步通知的结果进行判断
这句话的意思就是说,虽然你的App也会收到反馈,但是必须以业务服务器为准
你的App收到支付成功的反馈,其实是用来触发下一步业务操作的
支付的具体实现
支付的具体实现如下:
1.业务服务器发订单信息到你的App,你可能会给服务器开放一个这样的接口:
public void payAli(String orderinfo) {...}
2.你的App调用支付宝的接口
Map result = alipay.payV2(orderInfo, true);
3.你的App收到支付结束的通知,从支付宝App的返回值中寻找自己需要的数据
然后,你就可以告诉你的业务服务器:
“哥,支付宝App刚刚跟我说,他们给过钱了”
你的业务服务器很可能会问你:
“给钱的是靠墙的那桌,还是靠窗的那桌?”
你说:
“我...我找找”
然后,你就会栽进坑里...
要小心支付宝!
关于支付结果的一个坑
前面说过,App支付时,需要异步调起一个PayTask执行支付操作,真正执行支付的是这行代码:
Map result = alipay.payV2(orderInfo, true); //执行支付操作
result就是支付宝反馈给App的支付结果,在(成功/失败/超时/取消)支付操作后,我们把这个Map通过Message传递给Handler,Handler里会把这个Map映射为PayResult对象,根据PayResult去处理后续逻辑。
根据支付宝官方文档及Demo代码,我们通过PayResult对象的ResultStatus(=9000)就可以判断是否支付成功,交易订单号也可以从PayResult中找到,但是这里有个潜在的大坑:如何获取交易订单号,支付宝并没有做完全的说明,事实上:
--当交易成功时,我们要从PayResult的result字段中获取成功交易信息(但是,交易失败时result字段为空,而且官方文档没有提到这一点)
--当交易失败时,我们要从PayResult的memo字段中获取原始交易信息(但是,官方文档没有确认这一点)
--当交易取消时,PayResult的result字段为空,memo字段值为“操作已取消”
而且我们不能根据这个现象做决策,还记得吗,要小心支付宝!要小心支付宝!要小心支付宝!
对自己负责任的做法是,在支付的一开始,就要对支付宝的不靠谱有所防备,我的做法是,在异步执行PayTask的时候,我自己把原始支付信息记录下来,因为原始支付信息是我们自己的后台业务服务器发给我们的,在与支付宝的合作中,只有我们自己人是可信赖的,所以原始信息是可信赖的,我从原始信息中取出交易订单号,放进Map里,哪个Map?这个Map:
Map result = alipay.payV2(orderInfo, true); //执行支付操作
在这行代码下,我会向Map中增加一条信息,就是我们自己的后台业务服务器发给我的原始支付信息。
这样的话,原始支付信息会在Map中,随着Message一起发给处理支付结果的Handler。
Handler仍然会把Map转换为PayResult
而我会这样获取交易订单号:
1.先从PayResult的result字段中,尝试解析支付宝的成功交易信息
2.如果上一步取到的结果为空,就从Map中取出我们的原始交易信息
实际上就是加一层保险,以确保可以获取到交易订单号
如果有人问,为什么不根据交易成功或失败,分别从PayResult的result或memo中获取交易信息?
我只能说,too naive,这可是文档超级烂的支付宝,你可以信任它的支付,但不可以信任它的文档!
我最后说一遍,要小心支付宝!要小心支付宝!要小心支付宝!
关于支付宝沙箱
支付宝在蚂蚁金服的官方开放平台提供了一个貌似很有用的沙箱环境,可以在沙箱中模拟支付行为。
这个沙箱呢,其实还是挺有用的,这个测试环境会提供一套虚拟的账户,用来模拟交易行为,帮助检查你的接口写得有没有问题(支付宝:反正给你沙箱了,文档我就随便写写吧)。
另外,你顺便还可以在沙箱里体验一下,拥有1/10个亿,是什么感觉...
当然,支付宝沙箱提供了对应的沙箱App
不过,等你兴冲冲去下载的时候,你会发现,沙箱App只提供Android版,而且...
这个沙箱App,基本没啥用啊!没啥用啊!!没啥用啊!
没错,如果你要在App中对接支付宝登录和支付宝支付,沙箱环境跟你是没有关系的,后台能用上沙箱环境,至于App端么...
还是老老实实等真实线上环境搭好,用1分钱大法来测试吧...
对比
ID
微信需要三个ID:AppID、AppSecret、PID
支付宝需要亮哥ID:AppID、PID
多平台跳转
微信过于分散,从开放平台就不容易跳转到商户平台
蚂蚁金服集中的比较好,各平台互相跳转地很舒服
引用
微信使用gradle引用;支付宝使用jar包引用
登录
微信登录已经集成在ShareSDK了;支付宝没有集成
支付
双方都要求以服务器收到的信息为准,但是微信要求的更彻底,微信的返回值连订单号都没有
调微信App支付时,你的App不知道订单号(预交易订单号不是订单号);调支付宝App支付时,你的App知道订单号(而且知道详细的交易信息)
微信App是通过接口回调异步反馈的;支付宝App是通过函数返回值异步反馈的
微信主要通过后台对后台的方式传递订单和支付信息;支付宝则是主要通过App
(如果说支付行为好像是上楼签合同的话,在微信App支付里,你的后台是那个上楼送合同的人,你的App只是个按电梯开关的;在支付宝App支付,你的App是那个拿着合同上楼的人)
微信先通过后台完成支付,然后通知App;支付宝先通过App完成支付,然后后台跟进
微信支付成功会跳转Activity(要自己写);支付宝是纯逻辑处理
分享
都在ShareSDK中集成了
文档
微信的文档结构是这样的
支付宝的文档结构是这样的
看起来好像差不多,但是你真正用过之后就会发现,这就是两种文档,它们之间的区别是这样的: