注意必读
做了很多电商的项目了,都在用各大第三方支付,苹果已经在强制推行内购了,简单说明一下,如果你购买的商品,是在本app中使用和消耗的虚拟货币,就一定要用内购,否则会被拒绝上线,例如:游戏币,在线书籍,app中使用的道具等。如果购买的就是普通的商品,例如淘宝买东西等,就不需要用内购
现在苹果有一个 bug 就是你填写了银行卡信息之后修改不了只能发邮件给苹果等那边重置,发邮件给他们处理有多慢你懂得....
一.向appStore提交资料
第一步
第二步
第三步
操作完第三步然后记得保存
第四步
第五步
先点击Contact Info 的Set Up
第六步
第七步
都填写完记得保存,然后回到上一个页面
第八步
第九步
第十步
第十一步
第十二步
填写银行卡信息
第十三步
第十四步
第十五步
第十六步
第十七步
第十八步
第十九步
第二十步
第二十一步
恭喜你现在你完成了添加的信息,下面创建内购项目
二.创建内购项目
第一步
第二步
根据自己app的需要选择类型
第三步
第四步
一直下一步到结尾
三、添加项目内购测试帐号
第一步
四、上代码
第一步导入StoreKit.framework库
然后先看.h文件
#import <StoreKit/StoreKit.h>
typedef NS_ENUM(NSInteger, MyJellyShowType)
{
MyJellyShowType_Push = 0,
MyJellyShowType_Present = 1,
};
@interface MyJellyCurrencyViewController : BaseReuqestTableViewController<SKPaymentTransactionObserver,SKProductsRequestDelegate>
{
int buyType;
}
@property (nonatomic) MyJellyShowType showType;
- (void)RequestProductData;
- (void)buy:(int)type;
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions;
- (void)completeTransaction: (SKPaymentTransaction *)transaction;
- (void)failedTransaction: (SKPaymentTransaction *)transaction;
- (void)restoreTransaction: (SKPaymentTransaction *)transaction;
@end
然后看.m文件
//在内购项目中创的商品单号
#define ProductID_IAP0p600 @"guodong600"//60
#define ProductID_IAP1p1200 @"guodong1200" //1200
#define ProductID_IAP2p5000 @"guodong5000" //5000
enum{
IAP0p600 = 0,
IAP1p1200,
IAP4p5000,
} buyCoinsT
#pragma mark - 点击购买按钮
-(void)buttonClickIndex:(NSInteger)index
{
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
if (index == 0)
{
buyCoinsTag = IAP0p600;
}
else if (index == 1)
{
buyCoinsTag = IAP1p1200;
}else if (index == 2)
{
buyCoinsTag = IAP4p5000;
}
coinNum = [jellyMutAry objectAtIndex:index];
[LoadingTool showLoadingTo:self.view isAfterDelay:NO];
mainTableView.userInteractionEnabled = NO;
[self buy:buyCoinsTag];
}
-(void)buy:(int)type{
buyType = type;
if ([SKPaymentQueue canMakePayments])
{
//允许程序内付费购买
[self RequestProductData];
}
else
{
//不允许程序内付费购买
mainTableView.userInteractionEnabled = YES;
[LoadingTool hideProgressHud:self];
UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"您的手机没有打开程序内付费购买"
delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
[alerView show];
}
}
#pragma mark - 请求对应的产品信息
-(void)RequestProductData
{
NSArray *product = nil;
switch (buyType)
{
case IAP0p600:
product=[[NSArray alloc] initWithObjects:ProductID_IAP0p600,nil];
break;
case IAP1p1200:
product=[[NSArray alloc] initWithObjects:ProductID_IAP1p1200,nil];
break;
case IAP4p5000:
product=[[NSArray alloc] initWithObjects:ProductID_IAP2p5000,nil];
break;
default:
break;
}
NSSet *nsset = [NSSet setWithArray:product];
SKProductsRequest *request=[[SKProductsRequest alloc] initWithProductIdentifiers: nsset];
request.delegate=self;
[request start];
}
#pragma mark - 收到产品反馈信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
SKProduct * selectedProduct = nil;
selectedProduct = [response.products objectAtIndex:0];
SKPayment *payment = [SKPayment paymentWithProduct:selectedProduct];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
#pragma mark - 先商品添加进列表 再交易
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions//交易结果
{
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased://交易完成
{
[self completeTransaction:transaction];
}
break;
case SKPaymentTransactionStateFailed://交易失败
{
//交易失败
[self failedTransaction:transaction];
[WarningTool showToastHintWithText:@"购买失败,请重试!"];
}
break;
case SKPaymentTransactionStateRestored://已经购买过该商品
[self restoreTransaction:transaction];
break;
case SKPaymentTransactionStatePurchasing://商品添加进列表
break;
default:
break;
}
}
[LoadingTool hideProgressHud:self];
mainTableView.userInteractionEnabled = YES;
}
#pragma mark - 交易完成调用
- (void) completeTransaction: (SKPaymentTransaction *)transaction{
NSString *product = transaction.payment.productIdentifier;
if ([product length] > 0)
{
NSArray *tt = [product componentsSeparatedByString:@"."];
NSString *bookid = [tt lastObject];
if ([bookid length] > 0)
{
[self recordTransaction:transaction];
}
}
// Remove the transaction from the payment queue.结束交易
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
#pragma mark - 记录交易
-(void)recordTransaction:(SKPaymentTransaction *)transaction
{
transactionIdentifier = transaction.transactionIdentifier;
[self verifyPruchase];
// NSString *product = transaction.payment.productIdentifier;
// NSString *applicationUsername = transaction.payment.applicationUsername;
// NSString *transactionIdentifier = transaction.transactionIdentifier;
// // 验证凭据,获取到苹果返回的交易凭据
// // appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
// NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
// // 从沙盒中获取到购买凭据
// NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
// NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
// NSString *result =[[ NSString alloc] initWithData:transaction.transactionReceipt encoding:NSUTF8StringEncoding];
// NSString *base64Str = [transaction.transactionReceipt base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
}
- (void)verifyPruchase
{
[LoadingTool showLoadingTo:self.view isAfterDelay:NO];
// 验证凭据,获取到苹果返回的交易凭据
// appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
// 从沙盒中获取到购买凭据
NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
// 发送网络POST请求,对购买凭据进行验证
NSURL *url = [NSURL URLWithString:XTY_IAP_VerifyReceipt];
// 国内访问苹果服务器比较慢,timeoutInterval需要长一点
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];
request.HTTPMethod = @"POST";
NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPBody = payloadData;
// 提交验证请求,并获得官方的验证JSON结果
NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
// 官方验证结果为空验证失败
if (result == nil)
{
[LoadingTool hideProgressHud:self];
[WarningTool showToastHintWithText:@"验证失败"];
return;
}
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil];
//验证成功
if ([[dict objectForKey:@"status"] integerValue] == 0) {
// 比对字典中以下信息基本上可以保证数据安全
// bundle_id&application_version&product_id&transaction_id
[self addJelly];
}else if ([[dict objectForKey:@"status"] integerValue] == 21007){
// 验证凭据,获取到苹果返回的交易凭据
// appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
// 从沙盒中获取到购买凭据
NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
// 发送网络POST请求,对购买凭据进行验证
NSURL *url = [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"];
// 国内访问苹果服务器比较慢,timeoutInterval需要长一点
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];
request.HTTPMethod = @"POST";
NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPBody = payloadData;
// 提交验证请求,并获得官方的验证JSON结果
NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
// 官方验证结果为空验证失败
if (result == nil)
{
[LoadingTool hideProgressHud:self];
[WarningTool showToastHintWithText:@"验证失败"];
return;
}
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil];
if ([[dict objectForKey:@"status"] integerValue] == 0) {
[self addJelly];
}else{
[LoadingTool hideProgressHud:self];
[WarningTool showToastHintWithText:@"验证失败"];
}
}
else{
[LoadingTool hideProgressHud:self];
[WarningTool showToastHintWithText:@"验证失败"];
}
}
//失败
- (void) failedTransaction: (SKPaymentTransaction *)transaction{
if (transaction.error.code != SKErrorPaymentCancelled){}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
//交易恢复处理
- (void) restoreTransaction: (SKPaymentTransaction *)transaction{
// [self PurchasedTransaction:transaction];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
// [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
}
-(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error{
}
-(void) PurchasedTransaction: (SKPaymentTransaction *)transaction{
NSArray *transactions =[[NSArray alloc] initWithObjects:transaction, nil];
[ self paymentQueue:[SKPaymentQueue defaultQueue] updatedTransactions:transactions];
}
-(void)dealloc{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
//解除监听
}
- (void)addJelly
{
NSMutableDictionary *mutDic = [[NSMutableDictionary alloc]init];
[mutDic setObject:transactionIdentifier forKey:@"flowNO"];
[mutDic setObject:coinNum forKey:@"coinNum"];
[[NetworkRequests sharedClient]requestWithName:XTY_CoinCharge withParameters:mutDic successCallBack:^(MyJellyModel *myJellyModel) {
[LoadingTool hideProgressHud:self];
if ([myJellyModel.status integerValue] == 1)
{
[self beginRefreshing];
}
else
{
[WarningTool showToastHintWithText:myJellyModel.error];
}
} failCallback:^(NSString *error) {
[LoadingTool hideProgressHud:self];
[WarningTool showToastNetError];
}];
}