一、设置协议等相关
1.点击协议、税务和银行业务。
2.点击 Request Contracts 下面的 Request,一直点击直到主协议界面。
主协议界面
Contact info :联系人信息
Bank info :银行信息
Tax info :税务信息
3.点击 Contact Info 下面的Set Up,设置联系人信息,然后点击 Add New Contract,添加新的联系信息。
4.填写完整并保存。
!填写完整并保存.png](https://upload-images.jianshu.io/upload_images/2267403-171bc9c91b214d53.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
5.选择联系人,因为我是独立开发,所以填写的自己的,如果你是多人开发,你可以添加多个联系人。
Senior Management:高级管理人员
Financial :财务
Technical :技术支持
Legal :法务
Marketing :市场推广
添加完成之后,对应选择好就行。
6.点击 Bank Info 下的 Set Up,然后点击 Add Bank Account 添加银行账号。
点击 Select One,选择 China ,点击 next。
填写 CNAPS Code,点击 next。
CNAPS Code:中国现代化支付系统代码,又叫做联行号。可以从网上查询,也可以直接点击Look up CNAPS Code进行查询,再不济,也可以直接打电话咨询相应银行客服。
点击 next,核对一下,继续 next。
填写银行卡相关信息,点击 next。(持卡人姓名,如张三(Zhang San))
确认一下,点击 save 保存。
选择对应的银行卡,点击 save。
7.点击 Tax Info 下面的 Set Up,设置税务信息。
税务分三种:
U.S Tax Forms : 美国税务
Australia Tax Forms:澳大利亚税务
Canada Tax Forms : 加拿大税务
我们选择美国税务,点击 Done。
如果没有就选择 NO,点击 Submit。
如果没有就选择 NO。
填写完整,点击 Submit。
核对信息无误后提交,状态显示 Processing 表示成功。
二、创建项目的内购条目
1.进入 APP,点击功能。
根据情况选择,我选择的第一个。
填写内购项目信息,点击存储。
下面这些信息也要填完整,否则会提示元数据丢失(坑)。
注意:你 App 有几个内购级别就需要依次创建几个条目。
三、添加沙盒测试账号
1.点击用户和职能
2.点击沙盒技术测试员
3.点击 “+” 添加测试员,邮箱和密码用于支付的时候登陆 Apple ID。
四、代码集成
#import "ApplePayVC.h"
//导入
#import <StoreKit/StoreKit.h>
//遵循代理
@interface ApplePayVC ()
<
SKPaymentTransactionObserver,
SKProductsRequestDelegate
>
//支付按钮
@property (nonatomic, strong) UIButton *payBtn;
@end
@implementation ApplePayVC
- (void)viewDidLoad
{
[super viewDidLoad];
[self setupPayBtn];
//设置支付服务
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
#pragma mark - UI
- (void)setupPayBtn
{
_payBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_payBtn.frame = CGRectMake(100, 100, 100, 100);
_payBtn.backgroundColor = [UIColor redColor];
[_payBtn setTitle:@"支付" forState:UIControlStateNormal];
[_payBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
_payBtn.titleLabel.font = [UIFont systemFontOfSize:15.0];
[_payBtn addTarget:self action:@selector(payBtnAction) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_payBtn];
}
#pragma mark - BtnAction
- (void)payBtnAction
{
//是否允许内购
if ([SKPaymentQueue canMakePayments]) {
NSLog(@"用户允许内购");
//bundleid+xxx 就是你添加内购条目设置的产品ID
NSArray *product = [[NSArray alloc] initWithObjects:@"bundleid+xxx",nil];
NSSet *nsset = [NSSet setWithArray:product];
//初始化请求
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
request.delegate = self;
//开始请求
[request start];
}else{
NSLog(@"用户不允许内购");
}
}
#pragma mark - SKProductsRequestDelegate
//接收到产品的返回信息,然后用返回的商品信息进行发起购买请求
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response NS_AVAILABLE_IOS(3_0)
{
NSArray *product = response.products;
//如果服务器没有产品
if([product count] == 0){
NSLog(@"没有该商品");
return;
}
SKProduct *requestProduct = nil;
for (SKProduct *pro in product) {
NSLog(@"%@", [pro description]);
NSLog(@"%@", [pro localizedTitle]);
NSLog(@"%@", [pro localizedDescription]);
NSLog(@"%@", [pro price]);
NSLog(@"%@", [pro productIdentifier]);
//如果后台消费条目的ID与我这里需要请求的一样(用于确保订单的正确性)
if([pro.productIdentifier isEqualToString:@"bundleid+xxx"]){
requestProduct = pro;
}
}
//发送购买请求
SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:requestProduct];
payment.applicationUsername = userId;//可以是userId,也可以是订单id,跟你自己需要而定
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
#pragma mark - SKRequestDelegate
//请求失败
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
NSLog(@"error:%@", error);
}
//请求结束
- (void)requestDidFinish:(SKRequest *)request
{
NSLog(@"请求结束");
}
#pragma mark - SKPaymentTransactionObserver
//监听购买结果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for(SKPaymentTransaction *tran in transactions){
switch (tran.transactionState) {
case SKPaymentTransactionStatePurchased:
NSLog(@"交易完成");
[self completeTransaction:tran];
break;
case SKPaymentTransactionStatePurchasing:
NSLog(@"商品添加进列表");
break;
case SKPaymentTransactionStateRestored:
NSLog(@"已经购买过商品");
// [[SKPaymentQueue defaultQueue] finishTransaction:tran]; 消耗型商品不用写
break;
case SKPaymentTransactionStateFailed:
NSLog(@"交易失败");
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
break;
default:
break;
}
}
}
//交易结束,当交易结束后还要去appstore上验证支付信息是否都正确,只有所有都正确后,我们就可以给用户方法我们的虚拟物品了。
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
// 验证凭据,获取到苹果返回的交易凭据
// appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
// 从沙盒中获取到购买凭据
NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
//发送POST请求,对购买凭据进行验证
//测试验证地址:https://sandbox.itunes.apple.com/verifyReceipt
//正式验证地址:https://buy.itunes.apple.com/verifyReceipt
NSURL *url = [NSURL URLWithString:AppStore_URL];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0f];
urlRequest.HTTPMethod = @"POST";
NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
_receipt = encodeStr;
NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
urlRequest.HTTPBody = payloadData;
NSData *result = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:nil];
if (result == nil) {
NSLog(@"验证失败");
return;
}
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil];
NSLog(@"请求成功后的数据:%@",dic);
//这里可以通过判断 state == 0 验证凭据成功,然后进入自己服务器二次验证,,也可以直接进行服务器逻辑的判断。
//本地服务器验证成功之后别忘了 [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
NSString *productId = transaction.payment.productIdentifier;
NSString *applicationUsername = transaction.payment.applicationUsername;
NSLog(@"applicationUsername++++%@",applicationUsername);
NSLog(@"payment.productIdentifier++++%@",productId);
if (dic != nil) {
userId = applicationUsername;
//服务器二次验证
[self vertifyApplePayRequestWith:transaction];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}