## 简介
本项目的官方GitHub地址是 https://github.com/beecloud/beecloud-ios
SDK支持以下支付渠道:
- 微信APP
- 支付宝APP
- 银联在线APP
- PayPal
- 百度钱包
- Apple Pay
提供支付、支付订单以及退款订单的查询功能。
还提供了线下收款功能(包括微信扫码、微信刷卡、支付宝扫码、支付宝条形码),订单状态的查询以及订单撤销。
本SDK是根据BeeCloud Rest API 开发的 iOS SDK, 适用于 iOS 6 及以上版本。
## 流程
其中需要开发者开发的只有:
步骤①**(在App端)发送订单信息**
做完这一步之后就会跳到相应的支付页面(如微信app中),让用户继续后续的支付步骤
步骤②:(在App端)处理同步回调结果
付款完成或取消之后,会回到客户app中,在页面中展示支付结果(比如弹出框告诉用户"支付成功"或"支付失败")。同步回调结果只作为界面展示的依据,不能作为订单的最终支付结果,最终支付结果应以异步回调为准。
步骤③:(在客户服务端)处理异步回调结果(Webhook)
付款完成之后,根据客户在BeeCloud后台的设置,BeeCloud会向客户服务端发送一个Webhook请求,里面包括了数字签名,订单号,订单金额等一系列信息。客户需要在服务端依据规则要验证数字签名是否正确,购买的产品与订单金额是否匹配,这两个验证缺一不可。验证结束后即可开始走支付完成后的逻辑。
了解更多关于BeeCloud,请前往帮助中心
## 准备 参考[快速开始](https://beecloud.cn/apply/),完成开发准备工作。
## 导入SDK
方法一、下载本工程源码,将BCPaySDK
文件夹中的代码拷贝进自己项目,并按照下文的3个步骤导入相应文件进自己工程即可。
-
下载的
BCPaySDK
文件夹下的Channel
文件夹里包含了支付宝
,银联
,微信
,PayPal
,OfflinePay
,百度钱包
的原生SDK,请按需选择自己所需要的渠道。 -
最后加入系统库
libz.dylib
,libsqlite3.dylib
,libc++.dylib
,CoreMotion.framework
(支付宝需要)。
iOS9 加入
libz.1.2.5.tbd
、libc++.tbd
、libsqlite3.tbd
-
使用PayPal支付,需要添加以下系统库:
AudioToolbox.framework
CoreLocation.framework
MessageUI.framework
CoreMedia.framework
CoreVideo.framework
Accelerate.framework
AVFoundation.framework
方法二、使用CocoaPods
在podfile中加入
pod 'BeeCloud' //包含支付宝微信银联三个渠道
pod 'BeeCloud/Alipay' //只包含支付宝
pod 'BeeCloud/Wx' //只包括微信
pod 'BeeCloud/UnionPay' //只包括银联
pod 'BeeCloud/PayPal' //只包括paypal
pod 'BeeCloud/Baidu' //只包括百度钱包
pod 'BeeCloud/Apple' //只包括Apple Pay
## 配置
① 添加URL Schemes
在Xcode
中,选择你的工程设置项,选中TARGETS
,在Info
标签栏的 URL Types
添加URL Schemes
。如果使用微信,填入所注册的微信应用程序APPID
;如果不使用微信,则自定义,允许英文字母和数字,首字母必须是英文字母,建议起名稍复杂一些,尽量避免与支付宝(alipay)等其他程序冲突。
<array>
<dict>
<key>CFBundleURLName</key>
<string>zhifubao</string>
<key>CFBundleURLSchemes</key>
<array>
<string>payDemo</string>
</array>
</dict>
<dict>
<key>CFBundleURLName</key>
<string>weixin</string>
<key>CFBundleURLSchemes</key>
<array>
<string>wxf1aa465362b4c8f1</string>
</array>
</dict>
</array>
② iOS 9
以上版本如果需要使用支付宝和微信支付,需要在Info.plist
添加以下代码:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>weixin</string>
<string>wechat</string>
<string>alipay</string>
</array>
③ iOS 9
默认限制了http协议的访问,如果App需要使用http://
访问,必须在 Info.plist
添加如下代码:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
④ 如果Build失败,遇到以下错误信息:
XXXXXXX does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target.
请到 Xcode 项目的 Build Settings 页搜索 bitcode,将 Enable Bitcode 设置为 NO。
⑤ 如果使用银联支付
或Apple Pay
,请添加以下配置:
选择工程
->targets
->build settings
->linking
->other linker flags
, 配置 -ObjC
⑥ 使用Apple Pay请查看 银联Apple Pay相关
## 加入BeeCloud支付 ### 初始化 ① 初始化BeeCloud
初始化分为生产模式(LiveMode)、沙箱环境(SandboxMode);沙箱测试模式下不产生真实交易
开启生产环境
[BeeCloud initWithAppID:@"BeeCloud AppId" andAppSecret:@"BeeCloud App Secret"];
开启沙箱测试环境
[BeeCloud initWithAppID:@"BeeCloud AppId" andAppSecret:@"BeeCloud Test Secret"];
[BeeCloud setSandboxMode:YES];
或者
[BeeCloud initWithAppID:@"BeeCloud AppId" andAppSecret:@"BeeCloud Test Secret" sandbox:YES];
查看当前模式
/* 返回YES代表沙箱测试模式;NO代表生产模式 */
[BeeCloud getCurrentMode];
② 初始化微信
如果您使用了微信支付,需要用微信开放平台Appid初始化。
[BeeCloud initWeChatPay:@"微信开放平台appid"];
③ 初始化PayPal
如果你需要使用PayPal,使用以下方式初始化
//初始化PayPal
[BeeCloud initPayPal:@"AVT1Ch18aTIlUJIeeCxvC7ZKQYHczGwiWm8jOwhrREc4a5FnbdwlqEB4evlHPXXUA67RAAZqZM0H8TCR" secret:@"EL-fkjkEUyxrwZAmrfn46awFXlX-h2nRkyCVhhpeVdlSRuhPJKXx3ZvUTTJqPQuAeomXA8PZ2MkX24vF" sandbox:YES];
③ handleOpenUrl 此方法用于处理从微信、支付宝钱包回到本应用时的回调
//为保证从支付宝,微信返回本应用,须绑定openUrl. 用于iOS9之前版本
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
if (![BeeCloud handleOpenUrl:url]) {
//handle其他类型的url
}
return YES;
}
//iOS9之后apple官方建议使用此方法
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options {
if (![BeeCloud handleOpenUrl:url]) {
//handle其他类型的url
}
return YES;
}
④ 判断手机是否支持Apple Pay功能,以及是否已加载有可用的支付卡片
//0 表示不区分卡类型;1 表示只支持借记卡;2 表示支持信用卡;默认为0
[BeeCloud canMakeApplePayments: 0];
通过构造BCPayReq
的实例,使用[BeeCloud sendBCReq:payReq]
方法发起支付请求。具体请参考Demo。
响应事件对象为BCPayResp
//微信、支付宝、银联、百度钱包
- (void)doPay:(PayChannel)channel {
NSString *billno = [self genBillNo];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"value",@"key", nil];
/**
按住键盘上的option键,点击参数名称,可以查看参数说明
**/
BCPayReq *payReq = [[BCPayReq alloc] init];
payReq.channel = channel; //支付渠道
payReq.title = billTitle; //订单标题
payReq.totalFee = @"10"; //订单价格
payReq.billNo = billno; //商户自定义订单号
payReq.scheme = @"payDemo"; //URL Scheme,在Info.plist中配置; 支付宝必有参数
payReq.billTimeOut = 300; //订单超时时间
payReq.cardType = 0; // 0 表示不区分卡类型;1 表示只支持借记卡;2 表示支持信用卡;默认为0
payReq.viewController = self; //银联支付和Sandbox环境必填
payReq.optional = dict;//商户业务扩展参数,会在webhook回调时返回
[BeeCloud sendBCReq:payReq];
}
百度钱包需要用回调的参数在当前的viewController使用百度钱包SDK发起支付,并实现BDWalletSDKMainManagerDelegate
/发起支付
- (void)onBeeCloudResp:(BCBaseResp *)resp {
switch (resp.type) {
case BCObjsTypePayResp:
{
BCPayResp *tempResp = (BCPayResp *)resp;
if (tempResp.resultCode == 0) {
BCPayReq *payReq = (BCPayReq *)resp.request;
if (payReq.channel == PayChannelBaiduApp) {
[[BDWalletSDKMainManager getInstance] doPayWithOrderInfo:tempResp.paySource[@"orderInfo"] params:nil delegate:self];
} else {
[self showAlertView:resp.resultMsg];
}
} else {
[self showAlertView:[NSString stringWithFormat:@"%@ : %@",tempResp.resultMsg, tempResp.errDetail]];
}
}
break;
default:
{
if (resp.result_code == 0) {
[self showAlertView:resp.result_msg];
} else {
[self showAlertView:resp.err_detail];
}
}
break;
}
}
实现BDWalletSDKMainManagerDelegate
- (void)BDWalletPayResultWithCode:(int)statusCode payDesc:(NSString *)payDescs {
NSString *status = @"";
switch (statusCode) {
case 0:
status = @"支付成功";
break;
case 1:
status = @"支付中";
break;
case 2:
status = @"支付取消";
break;
default:
break;
}
[self showAlertView:status];
}
- (void)logEventId:(NSString *)eventId eventDesc:(NSString *)eventDesc {
}
通过构造BCPayPalReq
的实例,使用[BeeCloud sendBCReq:payReq]
方法发起支付请求。
响应事件对象为BCBaseResp
- (void)doPayPal {
BCPayPalReq *payReq = [[BCPayPalReq alloc] init];
_payPalConfig = [[PayPalConfiguration alloc] init];
_payPalConfig.acceptCreditCards = YES;
_payPalConfig.merchantName = @"Awesome Shirts, Inc.";
_payPalConfig.merchantPrivacyPolicyURL = [NSURL URLWithString:@"https://www.paypal.com/webapps/mpp/ua/privacy-full"];
_payPalConfig.merchantUserAgreementURL = [NSURL URLWithString:@"https://www.paypal.com/webapps/mpp/ua/useragreement-full"];
_payPalConfig.languageOrLocale = [NSLocale preferredLanguages][0];
_payPalConfig.payPalShippingAddressOption = PayPalShippingAddressOptionPayPal;
PayPalItem *item1 = [PayPalItem itemWithName:@"Old jeans with holes"
withQuantity:2
withPrice:[NSDecimalNumber decimalNumberWithString:@"84.99"]
withCurrency:@"USD"
withSku:@"Hip-00037"];
PayPalItem *item2 = [PayPalItem itemWithName:@"Free rainbow patch"
withQuantity:1
withPrice:[NSDecimalNumber decimalNumberWithString:@"0.00"]
withCurrency:@"USD"
withSku:@"Hip-00066"];
PayPalItem *item3 = [PayPalItem itemWithName:@"Long-sleeve plaid shirt (mustache not included)"
withQuantity:1
withPrice:[NSDecimalNumber decimalNumberWithString:@"37.99"]
withCurrency:@"USD"
withSku:@"Hip-00291"];
payReq.items = @[item1, item2, item3];
payReq.shipping = @"5.00";
payReq.tax = @"2.50";
payReq.shortDesc = @"paypal test";
payReq.viewController = self;
payReq.payConfig = _payPalConfig;
[BeeCloud sendBCReq:payReq];
}
实现PayPalPaymentDelegate,并在支付完成后必须进行Verify的操作
//支付完成
- (void)payPalPaymentViewController:(PayPalPaymentViewController *)paymentViewController didCompletePayment:(PayPalPayment *)completedPayment {
//使用`completedPayment`完成Payment Verify操作
BCPayPalVerifyReq *req = [[BCPayPalVerifyReq alloc] init];
req.payment = _completedPayment;
[BeeCloud sendBCReq:req];
[self dismissViewControllerAnimated:YES completion:nil];
}
//支付取消
- (void)payPalPaymentDidCancel:(PayPalPaymentViewController *)paymentViewController {
[self dismissViewControllerAnimated:YES completion:nil];
}
通过构造BCQueryBillsReq
的实例,使用[BeeCloud sendBCReq:req]
方法发起支付查询。
响应事件类型对象:BCQueryBillsResp
支付订单对象: BCQueryBillResult
BCQueryBillsReq *req = [[BCQueryBillsReq alloc] init];
req.channel = channel;
req.billStatus = BillStatusOnlySuccess; //支付成功的订单
req.needMsgDetail = YES; //是否需要返回支付成功订单的渠道反馈的具体信息
//req.billno = @"20150901104138656"; //订单号
//req.startTime = @"2015-10-22 00:00"; //订单时间
//req.endTime = @"2015-10-23 00:00"; //订单时间
req.skip = 0;
req.limit = 10;
[BeeCloud sendBCReq:req];
通过构造BCQueryBillsCountReq
的实例,使用[BeeCloud sendBCReq:req]
方法发起查询符合条件的支付订单总数。
响应事件类型:BCQueryBillsCountResp
BCQueryBillsCountReq *req = [[BCQueryBillsCountReq alloc] init];
req.channel = channel; //支付渠道
req.billNo = billNo;//商户订单号
req.billStatus = billStatus;//订单状态
req.startTime = startTime; //开始时间
req.endTime = endTime; //结束时间
[BeeCloud sendBCReq:req];
通过构造BCQueryBillByIdReq
的实例,使用[BeeCloud sendBCReq:req]
方法发起查询支付订单。
响应事件类型: BCQueryBillByIdResp
//bcId会在支付的回调中返回
BCQueryBillByIdReq *req = [[BCQueryBillByIdReq alloc] initWithObjectId:bcId];
[BeeCloud sendBCReq:req];
通过构造BCQueryRefundsReq
的实例,使用[BeeCloud sendBCReq:req]
方法发起退款查询。
响应事件类型对象:BCQueryRefundsResp
退款订单对象: BCQueryRefundResult
BCQueryRefundsReq *req = [[BCQueryRefundsReq alloc] init];
req.channel = channel;
req.needApproved = NeedApprovalAll;
// req.billno = @"20150722164700237";
// req.starttime = @"2015-07-21 00:00";
// req.endtime = @"2015-07-23 12:00";
//req.refundno = @"20150709173629127";
req.skip = 0;
req.limit = 10;
[BeeCloud sendBCReq:req];
通过构造BCQueryRefundsCountReq
的实例,使用[BeeCloud sendBCReq:req]
方法查询符合条件的退款订单总数。
响应事件类型: BCQueryRefundsCountResp
BCQueryRefundsCountReq *req = [[BCQueryRefundsCountReq alloc] init];
req.channel = channel;
req.billNo = billNo;
req.needApproved = needApproved;
req.refundNo = billNo;
req.startTime = startTime;
req.endTime = endTime;
[BeeCloud sendBCReq:req];
通过构造BCQueryRefundByIdReq
的实例,使用[BeeCloud sendBCReq:req]
方法发起查询支付订单。
响应事件类型: BCQueryRefundByIdResp
//bcId会在退款的回调中返回
BCQueryRefundByIdReq *req = [[BCQueryRefundByIdReq alloc] initWithObjectId:bcId];
[BeeCloud sendBCReq:req];
通过构造BCRefundStatusReq
的实例,使用[BeeCloud sendBCReq:req]
方法发起退款查询。
响应事件类型对象:BCRefundStatusResp
BCRefundStatusReq *req = [[BCRefundStatusReq alloc] init];
req.refundno = @"20150709173629127";
[BeeCloud sendBCReq:req];
通过构造BCPreRefundReq
的实例,使用[BeeCloud sendBCReq:req]
方法发起预退款。
响应事件类型对象:BCPreRefundResp
说明:
- 移动应用内正确的退款流程:
- 用户在客户端发起预退款请求
- 商户在管理端审核预退款请求,满足条件即调用退款接口完成退款;
// 具体请查看SDK中代码说明
BCPreRefundReq *req = [[BCPreRefundReq alloc] init];
req.billNo = @"2016052412121120"; //支付时商户自定义的订单号
req.refundNo = @"201606241290120"; // 商户按规则自定义退款订单号
req.refundFee = @"10"; //以分为单位,小于等于订单的支付金额
[BeeCloud sendBCReq:req];
实现接口BeeCloudDelegate
,获取不同类型的请求对应的响应;更多内容请参考Demo。
- 使用以下方法设置delegate:
[BeeCloud setBeeCloudDelegate:self];
- 实现BeeCloudDelegate:
- (void)onBeeCloudResp:(BCBaseResp *)resp {
switch (resp.type) {
case BCObjsTypePayResp:
{
// 支付请求响应
BCPayResp *tempResp = (BCPayResp *)resp;
if (tempResp.resultCode == 0) {
BCPayReq *payReq = (BCPayReq *)resp.request;
//百度钱包比较特殊需要用户用获取到的orderInfo,调用百度钱包SDK发起支付
if (payReq.channel == PayChannelBaiduApp && ![BeeCloud getCurrentMode]) {
[[BDWalletSDKMainManager getInstance] doPayWithOrderInfo:tempResp.paySource[@"orderInfo"] params:nil delegate:self];
} else {
//微信、支付宝、银联支付成功
[self showAlertView:resp.resultMsg];
}
} else {
//支付取消或者支付失败
[self showAlertView:[NSString stringWithFormat:@"%@ : %@",tempResp.resultMsg, tempResp.errDetail]];
}
}
break;
default:
{
if (resp.resultCode == 0) {
[self showAlertView:resp.resultMsg];
} else {
[self showAlertView:[NSString stringWithFormat:@"%@ : %@",resp.resultMsg, resp.errDetail]];
}
}
break;
}
}
项目中的BCPayExample
文件夹为我们的demo文件
项目中的BCPaySDK
文件夹为SDK目录,可以查看SDK源码
在真机上运行BCPayExample
target,体验真实支付场景
项目根目录命令行运行bash runTest.sh
, 就可以完成Unit Test。