在上一篇文章中,我对“App内购买”进行了一些介绍,如果你已经看过,那么相信你已经对它有了一定的了解,接下来要怎么把这一技术手段用(mai)在(le)实(huan)际(qian)中呢?
如果你是一名iOS开发工程狮,你将会在这篇文章中得到对于这个问题的解答,如果你不是,那么你也可以来围观下我们的开发日常~
本文的结构一、要使用什么API
你要使用到的API主要会有两个:StoreKit、NSURLSession
-
StoreKit
这款“商店工具包”里,已经包括了“App内购买”各个阶段中你需要的“扳手”、“钳子”,通过使用它们,你就可以在你的App里打造出一个小商店,出售你的产品。
-
NSURLSession
如果你的产品是交给Apple在App Store中进行托管的,那么你就需要在App内把用户购买的产品相关的信息下载下来,在下载这些信息时,你需要使用NSURLSession,并在后台完成下载。
不要使用NSURLConnect,因为苹果对它进行了限制。
二、购买过程的各个阶段
你可以先通过下面这张图对购买过程有一个初步了解:
购买过程的各个阶段
- 检索产品信息
在上一篇文章中,我已经讲过如何创建一个App内购买项目,当你已经创建好项目,你就可以使用产品标识符从App Store检索产品信息,这些信息包括产品价格、产品名称等。
关于产品标识符:
a.产品标识符是创建App内购买项目时,由你来设置的。
b.要注意这个产品标识符必须是唯一的,而且只能是大写英文字母(A-Z)、小写英文字母(a-z)、下划线( _ )或点号( . )的组合。
c.Apple建议我们使用反域名的方式进行命名,比如“com.companyname.application.productid”。
d.没错,产品标识符看起来跟App ID和Bundle ID非常像,不过它们不是一回事,记住不要弄混了。
在对产品标识符进行管理时,苹果没有提供任何方式支持你从App Store直接获取产品标识符,你需要自己记下所有的产品标识符,然后提供给你的App来使用,有两种策略可选:
a. 将产品标识符列表放在App的bundle中
当你的产品标识符是固定不变的,你可以使用这种策略,然后从本地读取产品标识符列表。
b.将产品标识符列表放在服务器端
当你的产品标识符在App不更新的情况下也是会变化的,你可以使用这种策略,然后从服务器端读取产品标识符列表。
在从服务器端获取产品标识符列表时,要注意制定缓存策略和保证可靠性。
当你已经在App内获取到产品标识符后,你就可以通过他们来向App Store请求产品对象,以及这些产品的可用性。这个时候就轮到我们在文章开头提到的大宝贝StoreKit出场了:实例化StoreKit中的 SKProductsRequest 类,用你的产品标识符列表对它进行实例化,然后发起请求:
// Custom method
- (void)validateProductIdentifiers:(NSArray *)productIdentifiers
{
SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithArray:productIdentifiers]];
// Keep a strong reference to the request.
self.request = productsRequest;
productsRequest.delegate = self;
[productsRequest start];
}
App Store收到你的请求并处理完成后,SKProductsRequestDelegate 中的代理方法将会被回调,回调的结果中会包括:一个有效的产品标识符列表和一个无效的产品标识符列表。你可以在这个方法里处理你的产标识符列表,比如把无效的产品标识符删除掉。
// SKProductsRequestDelegate protocol method
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
self.products = response.products;
for (NSString *invalidIdentifier in response.invalidProductIdentifiers) {
// Handle any invalid product identifiers.
}
[self displayStoreUI]; // Custom method
}
现在你可以向用户展示你的销售界面了,在展示产品价格时,可以使用NSNumberFormatter来格式化成本地价格:
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[numberFormatter setLocale:product.priceLocale];
NSString *formattedPrice = [numberFormatter stringFromNumber:product.price];
- 请求付款
在用户选择了一个产品进行购买后,你就可以创建一个支付请求了,创建时要填入在上一步检索产品信息时获取到的相应的产品对象,如果需要的话,再填入产品购买数量。
SKProduct *product = <# Product returned by a products request #>;
SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:product];
payment.quantity = 2;
然后将支付请求加入到支付队列中:
[[SKPaymentQueue defaultQueue] addPayment:payment];
- 交付产品
在提交了支付请求后,需要等待App Store对交易进行处理,这里需要首先注册对于App Store处理过程的监听:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
/* ... */
[[SKPaymentQueue defaultQueue] addTransactionObserver:observer];
}
然后就是实现 SKPaymentTransactionObserver 中的回调方法:
- (void)paymentQueue:(SKPaymentQueue *)queue
updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
// Call the appropriate custom method for the transaction state.
case SKPaymentTransactionStatePurchasing:
[self showTransactionAsInProgress:transaction deferred:NO];
break;
case SKPaymentTransactionStateDeferred:
[self showTransactionAsInProgress:transaction deferred:YES];
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStatePurchased:
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
[self restoreTransaction:transaction];
break;
default:
// For debugging
NSLog(@"Unexpected transaction state %@", @(transaction.transactionState));
break;
}
}
}
下一步就是根据App Store给你的用户的支付收据,向用户交付产品。获取支付收据可以采用下面的方式:
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
在交易完成后,记得主动关闭当前交易:
SKPaymentTransaction *transaction = <# The current payment #>;
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
参考:
In-App Purchase:https://developer.apple.com/in-app-purchase/
网友评论