简介
这一系列讲述的是免SDK实现分享、登录、支付等业务。
将会使用ShareSDK Demo进行部分试验。
一、获取支付参数
因涉及到敏感数据所以用参数名代替
实际使用时无需加{},添加{}主要是提醒这个是参数
----------open url: 0----------
weixin://app/{appId}/pay/?nonceStr=Ijs2foLuSi8sHEYS&package=Sign%3DWXPay&partnerId={partnerId}&prepayId={prepayId}&timeStamp=1499752264&sign={sign}&signType=SHA1
2、参数解释
以下为微信支付参数
//微信 URL Scheme
weixin
//固定写法
app
//微信app id
{appId}
//支付时使用 固定写法
pay
//随机串,防重发
nonceStr
//package iOS 只能是 Sign=WXPay 这里做了URL编码等号变成%3D
package
//商家向财付通申请的商家id
partnerId
//预支付订单
prepayId
//时间戳,防重发
timeStamp
商家根据微信开放平台文档对数据做的签名
sign
//签名类型
signType
二、构造支付参数
代码仅供参考,部分代码做了封装,需要到demo里的TWeChatPlatform类查看。
支付参数全部通过服务端获取,本地不做任何处理
//服务器返回JSON形式数据,需要自己去拼接
+ (NSString *)payToWechatParameters:(NSDictionary *)parameters appid:(NSString *)appid onStateChanged:(TPayStateChangedHandler)stateChangedHandler {
if (stateChangedHandler) {
[TWeChatPlatform shareInstance].payStateChangedHandler = stateChangedHandler;
}
//生成URLscheme
// NSString *str = [NSString stringWithFormat:@"weixin://app/%@/pay/?nonceStr=%@&package=Sign%%3DWXPay&partnerId=%@&prepayId=%@&timeStamp=%@&sign=%@&signType=SHA1",appid,nonceStr,partnerId,prepayId,[NSString stringWithFormat:@"%d",[timeStamp intValue] ],sign];
NSString * partnerId = parameters[@"partnerId"];
NSString * prepayId = parameters[@"prepayId"];
NSString * nonceStr = parameters[@"nonceStr"];
NSString * timeStamp = parameters[@"timeStamp"];
// NSString * package = parameters[@"package"];
NSString * sign = parameters[@"sign"];
NSString * wechatPayInfo = [NSString stringWithFormat:@"weixin://app/%@/pay/?nonceStr=%@&package=Sign%%3DWXPay&partnerId=%@&prepayId=%@&timeStamp=%@&sign=%@&signType=SHA1",appid,nonceStr,partnerId,prepayId,timeStamp,sign];
return wechatPayInfo;
}
//服务器返回String 无需自己拼接
+ (NSString *)payToWechatOrderString:(NSString *)orderString appid:(NSString *)appid onStateChanged:(TPayStateChangedHandler)stateChangedHandler {
if (stateChangedHandler) {
[TWeChatPlatform shareInstance].payStateChangedHandler = stateChangedHandler;
}
NSString * wechatPayInfo = [NSString stringWithFormat:@"weixin://app/%@/pay/?%@&signType=SHA1",appid,orderString];
return wechatPayInfo;
}
三、发起请求
代码仅供参考,部分代码做了封装,需要到demo里的Trochilus类查看。
//微信支付 需要手动拼接参数
+ (void)payToWechatParameters:(NSDictionary *)parameters onStateChanged:(TPayStateChangedHandler)stateChangedHandler {
[Trochilus shareInstance].isPayment = YES;
NSString * wechatPayInfo = [TWeChatPlatform payToWechatParameters:parameters
appid:[self platformForKey:weChat][@"appId"]
onStateChanged:^(TResponseState state, TUser *user, NSError *error) {
if (stateChangedHandler) {
stateChangedHandler(state,user,error);
}
}];
[Trochilus sendToURL:wechatPayInfo];
}
//微信支付 服务器拼接好参数
+ (void)payToWechatorderString:(NSString *)orderString onStateChanged:(TPayStateChangedHandler)stateChangedHandler {
[Trochilus shareInstance].isPayment = YES;
NSString * wechatPayInfo = [TWeChatPlatform payToWechatOrderString:orderString
appid:[self platformForKey:weChat][@"appId"]
onStateChanged:^(TResponseState state, TUser *user, NSError *error) {
if (stateChangedHandler) {
stateChangedHandler(state,user,error);
}
}];
[Trochilus sendToURL:wechatPayInfo];
}
+ (void)sendToURL:(NSString *)url {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.001 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
});
}
四、微信客户端回调
代码仅供参考,部分代码做了封装,需要到demo里的TWeChatPlatform类查看。
+ (BOOL)handleUrlWithWeChat:(NSURL *)url {
if ([url.absoluteString rangeOfString:@"://pay/"].location != NSNotFound) {
//微信支付
NSDictionary * wechat = [NSMutableDictionary dictionaryWithUrl:url];
if ([wechat[@"ret"] integerValue] == 0) {
//支付成功
if ([TWeChatPlatform shareInstance].payStateChangedHandler) {
[TWeChatPlatform shareInstance].payStateChangedHandler(TResponseStateSuccess, nil, nil);
}
}else if ([wechat[@"ret"] integerValue] == -2){
//用户点击取消并返回
if ([TWeChatPlatform shareInstance].payStateChangedHandler) {
[TWeChatPlatform shareInstance].payStateChangedHandler(TResponseStateCancel, nil, nil);
}
}
else {
//支付失败
if ([TWeChatPlatform shareInstance].payStateChangedHandler) {
NSError * err = [NSError errorWithDomain:@"WechatDomain" code:[wechat[@"ret"] integerValue] userInfo:wechat];
[TWeChatPlatform shareInstance].payStateChangedHandler(TResponseStateFail, nil, err);
}
}
}
return NO;
}
五、iOS9起状态栏返回回调处理
iOS9起在状态栏左右两侧增加了返回APP的功能,通过这个功能微信客户端是不会发信息给我们APP的,因此需要做特殊处理。
我们看看微信返回我们APP时,我们APP的appDelegate方法执行顺序是什么
applicationWillEnterForeground:-> application:openURL:options: || application:openURL:sourceApplication:annotation:
因此我们在applicationWillEnterForeground做文章,代码如下:
- (void)t_applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
[self t_applicationWillEnterForeground:application];
dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5/*延迟执行时间*/ * NSEC_PER_SEC));
dispatch_after(delayTime, dispatch_get_main_queue(), ^{
//延迟0.5s执行
if ([Trochilus isURLResponse] == NO && [Trochilus isPay] == YES) {
[[NSNotificationCenter defaultCenter] postNotificationName:kTrochilusPayment object:self userInfo:nil];
}
});
}
这里做了 method swizzle 具体看UIApplication+Trochilus类,实现了ShareSDK那个效果
同时做了延迟处理 判断客户端是否有返回信息,没有就去自己服务器请求结果吧
[Trochilus isURLResponse] == YES 说明微信有返回信息 反之 微信没返回信息,那么我们需要去自己服务器查支付结果
[Trochilus isPay] == YES 说明是支付类型,因为我这还有分享、授权,为了避免发送不必要的通知
六、参考资料
https://github.com/100apps/openshare
http://www.jianshu.com/p/8930b4496023
七、Demo
https://github.com/quanweiwang/Trochilus
目录
分享篇
1、我的APP不可能这么胖之QQ好友分享
2、我的APP不可能这么胖之QQ空间分享
3、我的APP不可能这么胖之微信好友分享
4、我的APP不可能这么胖之微信朋友圈分享
5、我的APP不可能这么胖之新浪微博分享
登录篇
6、我的APP不可能这么胖之QQ登录
7、我的APP不可能这么胖之微信登录
8、我的APP不可能这么胖之新浪微博登录
支付篇
9、我的APP不可能这么胖之微信支付
10、我的APP不可能这么胖之支付宝支付