MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Objective-C应用内购买(IAP)集成与验证

2024-04-266.7k 阅读

应用内购买概述

应用内购买(In-App Purchase,简称 IAP)允许用户在应用内购买虚拟商品或服务。这一功能为开发者提供了除付费下载应用之外的另一种重要盈利模式。在 iOS 应用开发中,利用 Objective-C 进行 IAP 集成可以解锁应用的更多高级功能、提供额外内容或者移除广告等。

准备工作

  1. 创建 App ID:在苹果开发者中心,为你的应用创建一个唯一的 App ID。确保该 App ID 启用了 In-App Purchase 功能。
  2. 配置 In-App Purchase 项目:同样在开发者中心,定义你应用中的内购项目。每个内购项目都有一个唯一的产品 ID,用于在代码中识别和处理该项目的购买。例如,如果你提供一个 “解锁高级功能” 的内购,你需要为它设置一个类似 “com.yourcompany.app.unlockpremium” 的产品 ID。
  3. 下载最新的 StoreKit 框架:StoreKit 是苹果提供的用于处理应用内购买的框架。确保你使用的 Xcode 版本包含最新的 StoreKit 框架,因为它会不断更新以支持新的功能和安全要求。

集成步骤

  1. 导入 StoreKit 框架:在你的项目中,打开 Xcode,选择你的项目文件,在 “General” 标签下的 “Frameworks, Libraries, and Embedded Content” 部分,点击 “+” 号,搜索并添加 “StoreKit.framework”。在需要使用 IAP 功能的文件(通常是视图控制器文件)中,导入 StoreKit 头文件:
#import <StoreKit/StoreKit.h>
  1. 请求产品信息:在发起购买之前,需要获取内购项目的详细信息,如价格、描述等。首先,创建一个 SKProductsRequest 对象,并实现 SKProductsRequestDelegate 协议。
@interface YourViewController () <SKProductsRequestDelegate, SKPaymentTransactionObserver>

@property (nonatomic, strong) NSMutableArray *productIdentifiers;
@property (nonatomic, strong) NSMutableDictionary *products;

@end

@implementation YourViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.productIdentifiers = [NSMutableArray arrayWithObjects:@"com.yourcompany.app.unlockpremium", nil];
    NSSet *set = [NSSet setWithArray:self.productIdentifiers];
    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
    request.delegate = self;
    [request start];
}

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
    NSArray *products = response.products;
    for (SKProduct *product in products) {
        self.products[product.productIdentifier] = product;
        NSLog(@"Product title: %@", product.localizedTitle);
        NSLog(@"Product price: %@", product.price);
        NSLog(@"Product description: %@", product.localizedDescription);
    }
}

- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
    NSLog(@"Error fetching product information: %@", error);
}

@end
  1. 发起购买:当用户点击购买按钮时,创建一个 SKPayment 对象,并将其添加到支付队列中。
- (IBAction)purchaseButtonTapped:(id)sender {
    if ([SKPaymentQueue canMakePayments]) {
        SKProduct *product = self.products[@"com.yourcompany.app.unlockpremium"];
        SKPayment *payment = [SKPayment paymentWithProduct:product];
        [[SKPaymentQueue defaultQueue] addPayment:payment];
    } else {
        NSLog(@"User cannot make payments.");
    }
}
  1. 处理交易:实现 SKPaymentTransactionObserver 协议的方法来处理购买交易的不同状态。
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions {
    for (SKPaymentTransaction *transaction in transactions) {
        switch (transaction.transactionState) {
            case SKPaymentTransactionStatePurchased:
                [self completeTransaction:transaction];
                break;
            case SKPaymentTransactionStateFailed:
                [self failedTransaction:transaction];
                break;
            case SKPaymentTransactionStateRestored:
                [self restoreTransaction:transaction];
                break;
            default:
                break;
        }
    }
}

- (void)completeTransaction:(SKPaymentTransaction *)transaction {
    NSLog(@"Transaction completed successfully.");
    // 解锁高级功能或提供购买的内容
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

- (void)failedTransaction:(SKPaymentTransaction *)transaction {
    if (transaction.error.code != SKErrorPaymentCancelled) {
        NSLog(@"Transaction failed with error: %@", transaction.error);
    }
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
    NSLog(@"Transaction restored successfully.");
    // 恢复购买的内容
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
  1. 验证购买:虽然苹果在服务器端会验证购买的合法性,但为了进一步确保安全,你可以在自己的服务器上验证购买收据。购买完成后,获取交易的收据数据,并将其发送到你的服务器进行验证。
- (void)completeTransaction:(SKPaymentTransaction *)transaction {
    NSData *receiptData = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];
    NSString *receiptString = [receiptData base64EncodedStringWithOptions:0];
    // 将 receiptString 发送到你的服务器进行验证
    // 这里假设你的服务器有一个验证接口,例如:
    NSString *urlString = [NSString stringWithFormat:@"https://yourserver.com/verifyreceipt?receipt=%@", receiptString];
    NSURL *url = [NSURL URLWithString:urlString];
    NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (!error && data) {
            NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
            if ([[responseDict objectForKey:@"status"] integerValue] == 0) {
                // 验证成功,解锁内容
            } else {
                // 验证失败
            }
        }
    }];
    [task resume];
    
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

常见问题及解决方法

  1. 购买失败:常见原因包括网络问题、用户取消支付、账户余额不足等。在 failedTransaction: 方法中,根据 transaction.error.code 来判断具体的失败原因,并给用户提供相应的提示。例如,如果是网络问题,可以提示用户检查网络连接并重新尝试。
  2. 验证失败:服务器验证失败可能是由于收据格式错误、服务器配置问题或苹果服务器临时故障。确保在将收据发送到服务器之前,对其进行正确的编码。同时,检查服务器端的验证逻辑,确保与苹果的验证机制兼容。如果是苹果服务器故障,可以提示用户稍后再试,并在本地记录交易状态,以便后续重试验证。
  3. 恢复购买:当用户在不同设备上登录或重新安装应用后,可能需要恢复之前的购买。在 restoreTransaction: 方法中,实现恢复购买内容的逻辑。注意,恢复购买也需要进行收据验证,以确保恢复的交易是合法的。

安全考虑

  1. 防止欺诈:除了在服务器端验证收据外,还可以采用一些其他的安全措施。例如,对敏感的内购功能进行加密处理,只有在验证通过后才解密并提供给用户。同时,监控购买行为的异常模式,如短时间内大量重复购买,及时发现并阻止可能的欺诈行为。
  2. 数据保护:购买相关的数据,如交易记录、用户购买的商品信息等,应该进行妥善的保护。在存储这些数据时,使用加密技术,防止数据被窃取或篡改。在传输过程中,采用安全的通信协议,如 HTTPS,确保数据的安全性。

测试应用内购买

  1. 沙盒环境:在开发和测试阶段,使用苹果的沙盒环境进行应用内购买测试。创建沙盒测试用户账号,在 Xcode 中使用该账号进行购买测试。注意,沙盒环境下的购买不会产生实际费用,但会模拟真实的购买流程,包括验证过程。
  2. 全面测试:对各种购买场景进行全面测试,包括购买成功、购买失败、恢复购买等。同时,测试不同网络环境下的购买情况,确保应用在各种情况下都能正常处理购买交易。

通过以上详细的步骤和注意事项,你可以在 Objective-C 开发的 iOS 应用中成功集成并验证应用内购买功能,为用户提供丰富的购买体验,同时保障开发者的收益安全。在实际应用中,还需要不断优化购买流程,根据用户反馈进行改进,以提高用户满意度和应用的盈利能力。