// // IAPShare.m // inappPurchasesTest //// #import "IAPShare.h" @implementation IAPShare static IAPShare *instance = nil;//不能让外部访问,同时放在静态块中的 +(IAPShare *)shareInstance{ if(instance == nil){ instance = [[IAPShare alloc] init]; } return instance; } -(void)initPay { //设置支付服务 [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; } #pragma mark - BtnAction - (void)payBtnAction { //是否允许内购 if ([SKPaymentQueue canMakePayments]) { NSLog(@"用户允许内购"); //bundleid+xxx 就是你添加内购条目设置的产品ID NSArray *product = [[NSArray alloc] initWithObjects:@"test.pay.money.18",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绑定一个appUsername就可以让这次payment有一个固定的发起者,这样当这次payment在苹果后台支付成功后,我们就可以通过监听的回调,将这个发起者的唯一标识符上传给自家后台,使得这次购买能找到一个合适的主人。就算用户在购买的过程中切换账号或者退出,也能够让这次充值验证成功。 //payment.applicationUsername = @"haho";//可以是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 NSString*AppStore_URL=@"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]; [[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]; // } } @end