关于iOS内支付(简称IAP,全称In App Purchase)的demo可以从以下链接下载:点击打开链接
一、实现支付功能的前提条件:
1.有一个可以发布产品的开发者账号,有一个可以运行应用的开发环境,IAP只能真机测试。
2.自己开发的IAP内支付APP的支付功能实现是需要有Product ID才能实现的,Product ID就是你要购买的产品的标识,可以由以下途径获得:登陆到iTunes Connect,用申请开发者账号的APP ID创建一个新的应用,创建应用内付费项目,设置好价格和Product ID等等。主要是要记住你自己设置好的所有Product ID。
二、iOS内支付开发步骤:
拿以上demo作为实例,其运行成功出现的界面有以下两个按钮:
如果Product ID是错误的话,上面第一个Buy按钮的buyButton.enabled属性为NO。只有当Product ID提供正确,其属性改为YES,才能点击进行购买操作。
此demo的主要流程如下:
1.先在工程导入storekit.frame框架,在EBPurchase.h里#import<StoreKit/StoreKit.h>
2.在ViewController.m文件里将"Your.IAP.Product.ID"改成你自己在上面创建应用时设置好的一个Product ID
#define SUB_PRODUCT_ID @"Your.IAP.Product.ID"
3.在Product ID成功的前提下进行讲解:
1)程序运行后到ViewController.m以下方法:
-(void) viewWillAppear:(BOOL)animated
{
buyButton.enabled = NO; // Only enable after populated with IAP price.
// Request In-App Purchase product info and availability.
if (![demoPurchase requestProduct:SUB_PRODUCT_ID])
{
// Returned NO, so notify user that In-App Purchase is Disabled in their Settings.
[buyButton setTitle:@"Purchase Disabled in Settings" forState:UIControlStateNormal];
}
}
从此方法buyButton.enabled = NO能看出一开始上面界面的第一个按钮是不能点击的。
2)在以上方法的 [demoPurchase requestProduct:SUB_PRODUCT_ID] 方法将Product ID传进程序,并跳转到EBPurchase.m以下方法:-(bool) requestProduct:(NSString*)productId
{
if (productId != nil) {
NSLog(@"EBPurchase requestProduct: %@", productId);
if ([SKPaymentQueue canMakePayments]) {
// Yes, In-App Purchase is enabled on this device.
// Proceed to fetch available In-App Purchase items.
// Initiate a product request of the Product ID.
SKProductsRequest *prodRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:productId]];
prodRequest.delegate = self;
[prodRequest start];
[prodRequest release];
return YES;
} else {
// Notify user that In-App Purchase is Disabled.
NSLog(@"EBPurchase requestProduct: IAP Disabled");
return NO;
}
} else {
NSLog(@"EBPurchase requestProduct: productId = NIL");
return NO;
}
}
此方法最重要的是以下这一段代码:里面的
[SKPaymentQueue canMakePayments]
方法是查询用户是否允许应用内付费,如果不允许就不用进行下面的操作了
if ([SKPaymentQueue canMakePayments]) {
// Yes, In-App Purchase is enabled on this device.
// Proceed to fetch available In-App Purchase items.
// Initiate a product request of the Product ID.
SKProductsRequest *prodRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:productId]];
prodRequest.delegate = self;
[prodRequest start];
[prodRequest release];
return YES;
} else {
// Notify user that In-App Purchase is Disabled.
NSLog(@"EBPurchase requestProduct: IAP Disabled");
return NO;
}
3)由以上代码里的
[prodRequest
start
]方法会由系统调SKProductsRequestDelegate协议里以下方法:
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
// Parse the received product info.
self.validProduct = nil;
int count = [response.products count];
if (count>0) {
// Grab the first product in the array.
self.validProduct = [response.products objectAtIndex:0];
}
if (self.validProduct) {
// Yes, product is available, so return values.
[delegate requestedProduct:self identifier:self.validProduct.productIdentifier name:self.validProduct.localizedTitle price:[self.validProduct.price stringValue] description:self.validProduct.localizedDescription];
} else {
// No, product is NOT available, so return nil values.
[delegate requestedProduct:self identifier:nil name:nil price:nil description:nil];
}
}
上面提供的Product ID如果不正确,以上方法查询会失败,count为0.如果正确,在以上方法里由 [delegate requestedProduct:self identifier:self.validProduct.productIdentifier name:self.validProduct.localizedTitle price:[self.validProduct.price stringValue] description:self.validProduct.localizedDescription] 调ViewController.m里EBPurchaseDelegate协议里的以下方法:
-(void) requestedProduct:(EBPurchase*)ebp identifier:(NSString*)productId name:(NSString*)productName price:(NSString*)productPrice description:(NSString*)productDescription
{
NSLog(@"ViewController requestedProduct");
if (productPrice != nil)
{
// Product is available, so update button title with price.
[buyButton setTitle:[@"Buy Game Levels Pack " stringByAppendingString:productPrice] forState:UIControlStateNormal];
buyButton.enabled = YES; // Enable buy button.
} else {
// Product is NOT available in the App Store, so notify user.
buyButton.enabled = NO; // Ensure buy button stays disabled.
[buyButton setTitle:@"Buy Game Levels Pack" forState:UIControlStateNormal];
UIAlertView *unavailAlert = [[UIAlertView alloc] initWithTitle:@"Not Available" message:@"This In-App Purchase item is not available in the App Store at this time. Please try again later." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[unavailAlert show];
[unavailAlert release];
}
}
从上面方法代码能看到
buyButton.enabled = YES 现在点击界面里的Buy按钮进行购买操作
跳转到以下方法:
-(IBAction)purchaseProduct<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">由此方法里的</span><span style="font-family: Arial, Helvetica, sans-serif;">[demoPurchase purchaseProduct:demoPurchase.validProduct]</span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">跳转到EBPurchase.m里的以下方法:</span>
-(bool) purchaseProduct:(SKProduct*)requestedProduct
{
if (requestedProduct != nil) {
NSLog(@"EBPurchase purchaseProduct: %@", requestedProduct.productIdentifier);
if ([SKPaymentQueue canMakePayments]) {
// Yes, In-App Purchase is enabled on this device.
// Proceed to purchase In-App Purchase item.
// Assign a Product ID to a new payment request.
SKPayment *paymentRequest = [SKPayment paymentWithProduct:requestedProduct];
// Assign an observer to monitor the transaction status.
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
// Request a purchase of the product.
[[SKPaymentQueue defaultQueue] addPayment:paymentRequest];
return YES;
当购买有结果时会由系统调用SKPaymentTransactionObserver协议里的以下方法:
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for(SKPaymentTransaction *transaction in transactions) {
switch ((int)transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
// Item is still in the process of being purchased
break;
case SKPaymentTransactionStatePurchased:
// Item was successfully purchased!
// Return transaction data. App should provide user with purchased product.
[delegate successfulPurchase:self identifier:transaction.payment.productIdentifier receipt:transaction.transactionReceipt];
// After customer has successfully received purchased content,
// remove the finished transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
break;
case SKPaymentTransactionStateRestored:
// Verified that user has already paid for this item.
// Ideal for restoring item across all devices of this customer.
// Return transaction data. App should provide user with purchased product.
[delegate successfulPurchase:self identifier:transaction.payment.productIdentifier receipt:transaction.transactionReceipt];
// After customer has restored purchased content on this device,
// remove the finished transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
break;
case SKPaymentTransactionStateFailed:
// Purchase was either cancelled by user or an error occurred.
if (transaction.error.code != SKErrorPaymentCancelled) {
// A transaction error occurred, so notify user.
[delegate failedPurchase:self error:transaction.error.code message:transaction.error.localizedDescription];
}
// Finished transactions should be removed from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
break;
}
}
}
购买成功后进行移除监听:
- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions
{
NSLog(@"EBPurchase removedTransactions");
// Release the transaction observer since transaction is finished/removed.
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}