OC/Swift-支付集成(微信/支付宝)

一,前期准备,设置URL Types

  • 注册微信支付宝这些就不说了
image.png

微信设置identifier:weixin(可以固定),后面的URL Schemes为注册微信的appkey
支付宝设置identifier:alipay(可以固定),后面的URL Schemes只要唯一就好了
注意:我这里都是固定的,方便后续去info.plist文件里获取数据方便

  • 这里的weixinalipay固定后续会用的 作为Key来获取URLScheme

Swift版

1.创建管理器
import UIKit

private let URLSchemeWechat = "weixin"
private let URLSchemeAlipay = "alipay"
private var successBlock:(()->())?
private var failBlock:((String)->())?
private var appscheme:[String:String] = [:]
enum HWPayType :Int {
    case wx = 0
    case zfb = 1
}

class wxPayModel : BaseModel { // 注意:这里的模型需要对应后台返回的 不一定是这些 可以对应修改
    /// 预支付订单
    var prepayid: String?
    /// 商家向财付通申请的商家id
    var partnerid: String?
    /// 商家根据财付通文档填写的数据和签名
    var package: String?
    /// 随机串,防重发
    var noncestr: String?
    /// 商家根据微信开放平台文档对数据做的签名
    var sign: String?
    /// 时间戳,防重发
    var timestamp: Int = 0
    /// 由用户微信号和AppID组成的唯一标识,发送请求时第三方程序必须填写,用于校验微信用户是否换号登录
    var appid: String?
}
class PaymentManage: NSObject {
    public static var aliSdkManager:PaymentManage!
    /// 获取单例
    public static func shared() -> PaymentManage{
        PaymentManage.aliSdkManager = PaymentManage.init()
        return PaymentManage.aliSdkManager
    }
    /// 注册支付系统
    func registApp(){
        let path = Bundle.main.path(forResource: "Info", ofType: "plist")
        let dict = NSDictionary(contentsOfFile: path!)
        guard let urlTypes:Array<Dictionary<String,Any>> = dict!["CFBundleURLTypes"] as? Array<Dictionary<String,Any>> else {return}
        for  item in urlTypes {
            let urlName = item["CFBundleURLName"] as? String
            if  let urlSchemes : Array<String> = item["CFBundleURLSchemes"] as? Array<String>{
                let urlScheme = urlSchemes.last ?? ""
                if urlName! == URLSchemeWechat {
                    appscheme[URLSchemeWechat] = urlScheme
                    // 注册微信
                    WXApi.registerApp(urlScheme)
                }else if urlName == URLSchemeAlipay{
                    // 保存支付宝的
                    appscheme[URLSchemeAlipay] = urlScheme
                }
            }
        }
    }
    
    // 外部用这个方法调起支付支付
    func pay(_ type: HWPayType,
             request:Any,
             paySuccess: @escaping () -> Void,
             payFail:@escaping (String) -> Void) {
        successBlock = paySuccess
        failBlock = payFail
        if type == .zfb {
            let newrequest = request as! String
            AlipaySDK.defaultService().payOrder(newrequest, fromScheme: appscheme[URLSchemeAlipay]) { (result) in }
        } else {
            if !WXApi.isWXAppInstalled()  {//检查一下是否可以使用微信
                failBlock!("未安装微信")
                HWPrint("未安装微信")
                return
            } else if !WXApi.isWXAppSupport() {
                failBlock!("当前版本微信不支持微信支付")
                HWPrint("当前版本微信不支持微信支付")
                return
            }
            let model = request as! wxPayModel
            let req = PayReq() // 生成支付模型
            req.openID = model.appid
            req.partnerId = model.partnerid
            req.prepayId = model.prepayid
            req.package = model.package
            req.timeStamp = UInt32(model.timestamp)
            req.nonceStr = model.noncestr
            req.sign = model.sign
            WXApi.send(req) //调起微信
        }
    }
    
    func noticeopen(_ url: URL) {
        if url.host == "safepay" { // 支付宝
            AlipaySDK.defaultService().processOrder(withPaymentResult: url as URL?, standbyCallback: { [weak self]
                (resultDic) -> Void in
                //调起支付结果处理
                self?.showResult(result: resultDic! as NSDictionary);
            })
        } else if url.host!.contains("pay"){ // 微信
            WXApi.handleOpen(url, delegate: self)
        }
    }
    
    
    /// 授权回调(这里用的是下一种)
    func showAuth_V2Result(result:NSDictionary){
        //        9000    请求处理成功
        //        4000    系统异常
        //        6001    用户中途取消
        //        6002    网络连接出错
        let returnCode:String = result["resultStatus"] as! String
        var returnMsg:String = ""
        switch  returnCode{
        case "6001":
            returnMsg = "用户中途取消"
            break
        case "6002":
            returnMsg = "网络连接出错"
            break
        case "4000":
            returnMsg = "系统异常"
            break
        case "9000":
            returnMsg = "授权成功"
            break
        default:
            returnMsg = "系统异常"
            break
        }
        HWPrint(returnMsg)
    }
    /// 传入回调参数
    func showResult(result:NSDictionary){
        //        9000    订单支付成功
        //        8000    正在处理中
        //        4000    订单支付失败
        //        6001    用户中途取消
        //        6002    网络连接出错
        let returnCode:String = result["resultStatus"] as! String
        var returnMsg:String = ""
        switch  returnCode{
        case "6001":
            returnMsg = "用户中途取消"
            if failBlock == nil {return}
            failBlock!(returnMsg)
            break
        case "6002":
            returnMsg = "网络连接出错"
            if failBlock == nil {return}
            failBlock!(returnMsg)
            break
        case "8000":
            returnMsg = "正在处理中"
            if failBlock == nil {return}
            failBlock!(returnMsg)
            break
        case "4000":
            returnMsg = "订单支付失败"
            if failBlock == nil {return}
            failBlock!(returnMsg)
            break
        case "9000":
            if successBlock == nil {return}
            successBlock!()
            returnMsg = "支付成功"
            break
        default:
            returnMsg = "订单支付失败"
            if failBlock == nil {return}
            failBlock!(returnMsg)
            break
        }
        HWPrint(returnMsg)
    }
}
extension PaymentManage : WXApiDelegate {
    func onResp(_ resp: BaseResp!) {
        if let payressp:PayResp = resp as? PayResp{
            switch payressp.errCode{
            case 0:
                HWPrint("支付成功")
                if successBlock == nil {return}
                successBlock!()
                break
            case -1:
                HWPrint(resp.errStr)
                if failBlock == nil {return}
                failBlock!(resp.errStr ?? "")
                break
            case -2:
                HWPrint("用户中途取消")
                if failBlock == nil {return}
                failBlock!("用户中途取消")
                break;
            default:
                HWPrint("未知错误")
                if failBlock == nil {return}
                failBlock!("未知错误")
                break;
            }
        }
    }
}
2.使用
  • 首先需要在AppDelegatedidFinishLaunchingWithOptions方法里进行注册
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        PaymentManage.shared().registApp() // 注册支付管理者
        return true
}
  • 其次收到回调信息后通知管理者进行回调
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
        let result = UMSocialManager.default().handleOpen(url, sourceApplication: sourceApplication, annotation: annotation)
        if (!result) {
            // 其他如支付等SDK的回调
            PaymentManage.shared().noticeopen(url)
        }
        return result;
    }
  • 最后就是使用了
例如:当前是微信支付 
if type == .wx {
 // 网络请求对应的支付信息 转成模型 <注意模型要转成wxPayModel类型,因为内部用这个类型处理事件的> 
        PaymentManage.shared().pay(.wx, request: model , paySuccess: {
                    /// 支付成功要做的事
                }, payFail: { (error) in
                    ///error 支付失败的信息
                })
} else {
  支付宝就直接把json数据传入进去就好了
}

OC版

1.创建管理者
  • .h文件
#import <Foundation/Foundation.h>

#define DWQWECHATURLNAME @"weixin"
#define DWQALIPAYURLNAME @"alipay"

NS_ASSUME_NONNULL_BEGIN

@interface HWPayWXModel : NSObject

@property (nonatomic, copy) NSString *prepayid;

@property (nonatomic, copy) NSString *partnerid;

@property (nonatomic, copy) NSString *package;

@property (nonatomic, copy) NSString *noncestr;

@property (nonatomic, assign) UInt32 timestamp;

@property (nonatomic, copy) NSString *sign;

@property (nonatomic, copy) NSString *appid;

@end

@interface HWPayManage : NSObject
/** 单例管理 */
+ (instancetype)shareManager;
/** 注册 */
- (void)hw_registerApp;
/** 支付 */
- (void)hw_payWithOrderMessage:(id)orderMessage success:(void(^)(void))success fail:(void(^)(NSString *error))fail;
/** 收到回调后接收通知 */
- (BOOL)hw_handleUrl:(NSURL *)url;
@end

NS_ASSUME_NONNULL_END
  • .m文件
#import "HWPayManage.h"
#import <WXApi.h>
#import <AlipaySDK/AlipaySDK.h>

// 回调url地址为空
#define DWQTIP_CALLBACKURL @"url地址不能为空!"
// 订单信息为空字符串或者nil
#define DWQTIP_ORDERMESSAGE @"订单信息不能为空!"
// 没添加 URL Types
#define DWQTIP_URLTYPE @"请先在Info.plist 添加 URL Type"
// 添加了 URL Types 但信息不全
#define DWQTIP_URLTYPE_SCHEME(name) [NSString stringWithFormat:@"请先在Info.plist 的 URL Type 添加 %@ 对应的 URL Scheme",name]

@implementation HWPayWXModel

@end

@interface HWPayManage ()<WXApiDelegate>
// 缓存appScheme
@property (nonatomic,strong)NSMutableDictionary *appSchemeDict;
/** <#注释#> */
@property(nonatomic, copy) void(^successBlock)(void);
/** <#注释#> */
@property(nonatomic, copy) void(^failBlock)(NSString *error);
@end

@implementation HWPayManage

+ (instancetype)shareManager{
    static HWPayManage *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}
- (void)hw_registerApp {
    NSString *path = [[NSBundle mainBundle] pathForResource:@"Info" ofType:@"plist"];
    NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
    NSArray *urlTypes = dict[@"CFBundleURLTypes"];
    NSAssert(urlTypes, DWQTIP_URLTYPE);
    for (NSDictionary *urlTypeDict in urlTypes) {
        NSString *urlName = urlTypeDict[@"CFBundleURLName"];
        NSArray *urlSchemes = urlTypeDict[@"CFBundleURLSchemes"];
        NSAssert(urlSchemes.count, DWQTIP_URLTYPE_SCHEME(urlName));
        // 一般对应只有一个
        NSString *urlScheme = urlSchemes.lastObject;
        if ([urlName isEqualToString:DWQWECHATURLNAME]) {
            [self.appSchemeDict setValue:urlScheme forKey:DWQWECHATURLNAME];
            // 注册微信
            [WXApi registerApp:urlScheme];
        } else if ([urlName isEqualToString:DWQALIPAYURLNAME]){
            // 保存支付宝scheme,以便发起支付使用
            [self.appSchemeDict setValue:urlScheme forKey:DWQALIPAYURLNAME];
        }
    }
}

- (void)hw_payWithOrderMessage:(id)orderMessage success:(void(^)(void))success fail:(void(^)(NSString *error))fail {
    self.successBlock = success;
    self.failBlock = fail;
    if (orderMessage[@"info"]) { // 支付宝支付
        [[AlipaySDK defaultService] payOrder:orderMessage[@"info"] fromScheme:self.appSchemeDict[DWQALIPAYURLNAME] callback:^(NSDictionary *resultDic) {}];
    } else { // 微信支付
        if (![WXApi isWXAppInstalled]) { // 没有安装微信
            self.failBlock(@"没有安装微信");
            return;
        }
        if (![WXApi isWXAppSupportApi]) { // 当前版本微信不支持微信支付
            self.failBlock(@"当前版本微信不支持微信支付");
            return;
        }
        HWPayWXModel *model = [HWPayWXModel mj_objectWithKeyValues:orderMessage];
        PayReq *payReq = [[PayReq alloc] init];
        payReq.partnerId = model.partnerid;
        payReq.prepayId = model.prepayid;
        payReq.nonceStr = model.noncestr;
        payReq.timeStamp = model.timestamp;
        payReq.package = model.package;
        payReq.sign = model.sign;
        payReq.openID = model.appid;
        [WXApi sendReq:payReq];
    }
}
- (BOOL)hw_handleUrl:(NSURL *)url {
    NSAssert(url, DWQTIP_CALLBACKURL);
    if ([url.host isEqualToString:@"pay"]) {// 微信
        return [WXApi handleOpenURL:url delegate:self];
    } else if ([url.host isEqualToString:@"safepay"]) {// 支付宝
        __weak typeof(self) weakSelf = self;
        // 支付跳转支付宝钱包进行支付,处理支付结果(在app被杀模式下,通过这个方法获取支付结果)
        [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
            [weakSelf showResult:resultDic];
        }];
        return YES;
    } else{
        return NO;
    }
}
- (void)showResult:(NSDictionary *)resultDic {
    NSString *resultStatus = resultDic[@"resultStatus"];
    if ([resultStatus isEqualToString:@"6001"]) {
        self.failBlock(@"用户中途取消");
    } else if ([resultStatus isEqualToString:@"6002"]) {
        self.failBlock(@"网络连接出错");
    } else if ([resultStatus isEqualToString:@"8000"]) {
        self.failBlock(@"正在处理中");
    } else if ([resultStatus isEqualToString:@"4000"]) {
        self.failBlock(@"订单支付失败");
    } else if ([resultStatus isEqualToString:@"9000"]) {
        self.successBlock();
    } else {
        self.failBlock(@"订单支付失败");
    }
}
#pragma mark - WXApiDelegate
- (void)onResp:(BaseResp *)resp {
    // 判断支付类型
    if([resp isKindOfClass:[PayResp class]]){
        //支付回调
        NSString *errStr = resp.errStr;
        switch (resp.errCode) {
            case 0:
                self.successBlock();
                errStr = @"订单支付成功";
                break;
            case -1:
                errStr = resp.errStr;
                self.failBlock(errStr);
                break;
            case -2:
                errStr = @"用户中途取消";
                self.failBlock(errStr);
                break;
            default:
                errStr = resp.errStr;
                self.failBlock(errStr);
                break;
        }
    }
}
- (NSMutableDictionary *)appSchemeDict{
    if (_appSchemeDict == nil) {
        _appSchemeDict = [NSMutableDictionary dictionary];
    }
    return _appSchemeDict;
}
@end
2.使用
  • AppDelegatedidFinishLaunchingWithOptions方法中注册
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [[HWPayManage shareManager] hw_registerApp];
    return YES;
}
  • 收到回调后通知管理者
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    BOOL result = [[UMSocialManager defaultManager] handleOpenURL:url];
    if (!result) {
        // 其他如支付等SDK的回调
       return [[HWPayManage shareManager] hw_handleUrl:url];
    }
    return result;
}
  • 使用 (注意这里没有提供类型选择, 是根据后台返回的json字段中是否有info来判断的)
[[HWPayManage shareManager] hw_payWithOrderMessage:item.data success:^{
                /// 支付成功处理逻辑
            } fail:^(NSString * _Nonnull error) {
                 /// 支付失败处理逻辑
            }];

总结:如果有分享需要注意,收到回调方法可能会被覆盖这样就收不到支付信息的回调了,需要注意
代码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335