21、如何在iOS软件中实现内购功能

如何在iOS软件中实现内购功能

在当今的移动应用市场中,内购功能已经成为了许多应用获取收入的重要途径。无论是游戏还是其他类型的软件,都可以通过内购来提供额外的功能或内容,从而增加用户的粘性和付费意愿。本文将详细介绍如何在iOS软件中实现内购功能,包括在iTunes Connect中配置应用、添加产品、获取产品列表、向用户展示产品以及处理购买交易等步骤。

1. 在iTunes Connect中配置应用

要在iOS应用中实现内购功能,首先需要在iTunes Connect中对应用进行配置。具体步骤如下:
1. 登录iTunes Connect(http://itunesconnect.apple.com),你需要有一个现有的项目。如果还没有在iTunes Connect中创建项目,可以先创建一个。
2. 选择要添加内购支持的项目,然后点击“Manage In-App Purchases”按钮。
3. 点击“Manage In-App Purchases”按钮后,会进入一个设置新产品的屏幕,点击窗口左上角的“Create New”按钮。

需要注意的是,从创建应用到上传二进制文件进行审核有90天的时间限制,确保在项目完成前90天内保存内购配置。

2. 配置内购产品类型

在iTunes Connect中,可以配置多种类型的内购产品,包括:
- 消耗品(Consumable) :用户每次下载都必须购买的产品,例如游戏内的货币。
- 非消耗品(Non-Consumables) :每个用户只需购买一次的产品,通常用于解锁功能,如额外的关卡、可重复使用的道具或额外的内容。
- 自动续订订阅(Auto-Renewable Subscriptions) :允许用户在设定的时间段内购买应用内的内容,到期后会自动续订,除非用户选择取消。例如杂志和报纸的订阅模式。
- 非续订订阅(Non-Renewing Subscriptions) :与自动续订订阅功能类似,但用户需要在每次到期时手动续订。

以示例UFO游戏为例,我们先添加一个非消耗品购买项目,即用户当前飞船的付费升级,命名为“com.dragonforged.ufo.newShip1”。创建新项后,需要添加至少一个本地化描述和标题,并选择一个定价层级。

添加消耗品产品的步骤与添加非消耗品产品相同。如果要添加基于订阅的产品,需要注意一些新的字段,例如需要定义订阅的持续时间,iTunes Connect支持一周、一个月、两个月、三个月、六个月或一年等选项,还可以提供免费订阅,前提是用户同意参与营销活动,如提供他们的电子邮件地址。

3. 添加产品到应用

苹果没有为内购提供预先设计的GUI,开发者需要为用户设计一个商店界面。要让在iTunes Connect中添加的产品在应用中显示出售,需要完成以下步骤:
- 确保App ID唯一 :在进行内购时,苹果要求App ID不能包含通配符,需要有一个唯一的App ID。如果没有唯一的App ID,可以按照以下步骤创建:
1. 在浏览器中导航到http://developer.apple.com/iPhone,从右侧列表中选择“iPhone Developer Program Portal”。
2. 从左侧列中选择“App ID”,然后点击右上角的“New App ID”按钮。
3. 填写应用的相关信息。
4. 点击“Submit”。
5. 点击列表旁边的“Configure”按钮,确保“ In-App Purchase”已开启(默认情况下应该是开启的)。
- 设置项目
1. 向项目中添加StoreKit框架。
2. 创建一个新的类“UFOStoreViewController”,用于向用户显示商店。设置头文件如下:

#import <UIKit/UIKit.h>
#import <StoreKit/StoreKit.h>

@interface UFOStoreViewController : UIViewController <SKProductsRequestDelegate>
{
    SKProductsRequest *productsRequest;
}

@end
  1. 为用户添加访问商店的方式,例如在主屏幕上添加一个按钮,并添加相关代码以展示新的视图控制器(UFOStoreViewController)。
4. 获取产品列表

修改新商店视图控制器的 viewDidLoad viewDidUnload 方法,以使用在iTunes Connect中设置的产品标识符发起新的商店请求。代码如下:

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSSet *productIdentifiers = [NSSet setWithObjects:@"com.dragonforged.ufo.newShip1", @"com.dragonforged.ufo.subscription", nil];
    productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
    productsRequest.delegate = self;
    [productsRequest start];
}

- (void)viewDidUnload
{
    productsRequest.delegate = nil;
}

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

    for (NSString *invalidProduct in response.invalidProductIdentifiers)
    {
        NSLog(@"Invalid: %@", invalidProduct);
    }

    [request release];
}

需要注意的是,内购功能在模拟器上无法工作,所有测试都需要在设备上进行。而且,获取产品列表的请求可能需要几秒钟才能得到响应,建议在加载过程中向用户显示某种加载指示器。

5. 向用户展示产品

为了向用户展示产品,需要在商店视图控制器中添加一个表格视图,并设置数据源和委托。同时,添加一个新的属性来保存产品列表。代码如下:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [productArray count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil)
    {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
    }

    SKProduct *product = [self.productArray objectAtIndex: [indexPath row]];
    cell.textLabel.text = [NSString stringWithFormat:@"%@ - $%@", product.localizedTitle, product.price];
    cell.detailTextLabel.text = product.localizedDescription;
    return cell;
}

最后,在 productsRequest 方法的末尾添加重新加载表格的方法。运行游戏后,应该会看到类似以下的输出:

2011–08-19 17:31:23.970 UFOs[3580:707] Product title: Ship+
2011–08-19 17:31:23.973 UFOs[3580:707] Product description: Paint your ship and show off to your friends
2011–08-19 17:31:23.975 UFOs[3580:707] Product price: 8.99
2011–08-19 17:31:23.977 UFOs[3580:707] Product id: com.dragonforged.ufo.newShip1
2011–08-19 17:31:23.979 UFOs[3580:707] Product title: Subscription
2011–08-19 17:31:23.981 UFOs[3580:707] Product description: A subscription service
2011–08-19 17:31:23.983 UFOs[3580:707] Product price: 1.99
2011–08-19 17:31:23.987 UFOs[3580:707] Product id: com.dragonforged.ufo.subscription

下面是整个过程的mermaid流程图:

graph TD;
    A[登录iTunes Connect] --> B[选择项目并点击Manage In-App Purchases];
    B --> C[点击Create New创建产品];
    C --> D[配置产品类型和信息];
    D --> E[确保App ID唯一];
    E --> F[添加StoreKit框架和UFOStoreViewController类];
    F --> G[获取产品列表];
    G --> H[向用户展示产品];
5. 处理购买交易

在前面的步骤中,我们已经完成了在应用中添加产品和展示产品的操作。接下来,我们将详细介绍如何处理购买交易,包括购买代码的实现、处理多个物品的购买、处理交易状态以及恢复之前完成的交易等内容。

5.1 购买代码

要实现购买功能,首先需要让 UFOStoreViewController 类遵循 SKPaymentTransactionObserver 协议,并修改 viewDidLoad 方法。在 viewDidLoad 方法中,添加自身作为交易观察者,并检查设备是否支持支付。如果支持支付,则发起产品请求;如果不支持支付,则显示一个警告提示用户。代码如下:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    if ([SKPaymentQueue canMakePayments])
    {
        NSSet *productIdentifiers = [NSSet setWithObjects:@"com.dragonforged.ufo.newShip1", @"com.dragonforged.ufo.subscription", nil];
        productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
        productsRequest.delegate = self;
        [productsRequest start];
    }
    else
    {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"Unable to make purchases with this device." delegate:nil cancelButtonTitle:@"Dimiss" otherButtonTitles: nil];
        [alert show];
        [alert release];
    }
}

同时,需要添加 didSelectRowAtIndexPath 方法来处理表格视图中的选择事件。当用户选择某一行时,创建一个 SKPayment 对象并将其添加到支付队列中。代码如下:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    SKProduct *product = [self.productArray objectAtIndex: [indexPath row]];
    SKPayment *payment = [SKPayment paymentWithProductIdentifier:product.productIdentifier];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

运行应用并选择表格行时,会出现一个确认购买的提示框。但此时还没有编写处理交易的代码,也没有设置测试用户,所以暂时只能进行到这一步。

5.2 购买多个物品

苹果提供了方便的方式让用户一次购买多个物品。例如,用户想要购买五包100金币,可以使用以下代码:

SKMutablePayment *payment = [SKMutablePayment paymentWithProductIdentifier:@"com.dragonforged.rpg.100gold"];
payment.quantity = 5;
[[SKPaymentQueue defaultQueue] addPayment: payment];
5.3 处理交易状态

当用户请求购买后,需要确保交易能够成功完成。实现 SKPaymentTransactionObserver 协议中的 paymentQueue:updatedTransactions: 方法,根据交易状态调用不同的方法。代码如下:

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    for (SKPaymentTransaction *transaction in transactions)
    {
        if ([transaction transactionState] == SKPaymentTransactionStatePurchased)
        {
            [self transactionDidComplete:transaction];
        }
        else if ([transaction transactionState] == SKPaymentTransactionStateFailed)
        {
            [self transactionDidFail:transaction];
        }
        else if ([transaction transactionState] == SKPaymentTransactionStateRestored)
        {
            [self transactionDidRestore:transaction];
        }
        else
        {
            NSLog(@"Unhandled case: %@", transaction);
        }
    }
}

同时,需要实现一些辅助方法来简化处理过程。如果交易成功完成或恢复,需要记录交易事件、解锁用户购买的内容并进行清理;如果交易失败或取消,只需进行清理并可能通知用户出现问题。代码如下:

- (void)transactionDidComplete:(SKPaymentTransaction *)transaction
{
    [self recordTransactionData:transaction];
    [self unlockContent:[[transaction payment] productIdentifier]];
    [self finishTransaction:transaction withSuccess:YES];
}

- (void)transactionDidRestore:(SKPaymentTransaction *)transaction
{
    [self recordTransactionData:transaction.originalTransaction];
    [self unlockContent:[[[transaction originalTransaction] payment] productIdentifier]];
    [self finishTransaction:transaction withSuccess:YES];
}

- (void)transactionDidFail:(SKPaymentTransaction *)transaction
{
    if ([[transaction error] code] != SKErrorPaymentCancelled)
    {
        [self finishTransaction:transaction withSuccess:NO];
    }
    //SKErrorPaymentCancelled
    else
    {
        [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    }
}
5.4 记录交易数据

recordTransactionData 方法用于记录交易数据,使用 NSUserDefaults 来保存所有完成的交易数组。代码如下:

- (void)recordTransactionData:(SKPaymentTransaction *)transaction
{
    NSArray *transactions = [[NSUserDefaults standardUserDefaults] objectForKey:@"transactions"];
    NSMutableArray *transactionArray = [transactions mutableCopy];
    [transactionArray addObject:[transaction transactionReceipt]];
    [[NSUserDefaults standardUserDefaults] setObject:transactionArray forKey:@"transactions"];
    [transactionArray release];
}
5.5 解锁内容

unlockContent 方法用于解锁用户购买的内容。在这个示例中,通过设置 NSUserDefaults 中的标志来表示用户是否购买了某个功能。代码如下:

- (void)unlockContent:(NSString *)productId
{
    if ([productId isEqualToString:@"com.dragonforged.ufo.newShip1"])
    {
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"shipPlusAvailable"];
    }
    if ([productId isEqualToString:@"com.dragonforged.ufo.subscription"])
    {
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"subscriptionAvailable"];
    }
}
5.6 完成交易

finishTransaction 方法用于完成交易并记录交易结果。在这个方法中,调用 finishTransaction 方法结束交易,并根据交易是否成功记录日志。代码如下:

- (void)finishTransaction:(SKPaymentTransaction *)transaction withSuccess:(BOOL)success
{
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    NSDictionary *transactionDictionary = [NSDictionary dictionaryWithObjectsAndKeys:transaction, @"transaction", nil];
    if (success)
    {
        NSLog(@"Transaction was successful: %@", transactionDictionary);
    }
    else
    {
        NSLog(@"Transaction was unsuccessful: %@", transactionDictionary);
    }
}
5.7 恢复之前完成的交易

用户可能需要恢复之前购买的内容,例如重新安装应用或在不同设备上使用应用。可以使用以下代码恢复之前完成的交易:

[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];

调用这个方法后,会重新购买所有之前购买的内容,并且会收到 paymentQueue:updatedTransactions: 方法的回调,可以使用现有的代码来解锁内容。

5.8 测试账户和测试购买

在沙盒环境中测试购买时,需要创建一个新的测试账户,以避免被收费。具体步骤如下:
1. 登录iTunes Connect(http://iTunesConnect.apple.com)。
2. 从iTunes Connect主屏幕选择“Manage User”部分。
3. 选择创建新的测试用户选项。
测试用户不需要使用真实的电子邮件地址,可以选择一个容易输入和记忆的地址,如 abc@def.com 。同时,需要输入出生日期和其他识别信息,但这些信息可以虚构。确保选择适合测试应用本地化的iTunes Store,可以为每个要测试的地区创建一个新账户。

下面是处理购买交易的mermaid流程图:

graph TD;
    A[用户选择产品并点击购买] --> B[创建SKPayment对象并添加到支付队列];
    B --> C[监听交易状态变化];
    C --> D{交易状态};
    D -- 已购买 --> E[调用transactionDidComplete方法];
    D -- 失败 --> F[调用transactionDidFail方法];
    D -- 恢复 --> G[调用transactionDidRestore方法];
    E --> H[记录交易数据];
    E --> I[解锁内容];
    E --> J[完成交易并记录成功日志];
    F --> K[完成交易并记录失败日志];
    G --> H;
    G --> I;
    G --> J;

通过以上步骤,你可以在iOS应用中实现完整的内购功能,包括配置应用、添加产品、展示产品和处理购买交易等。在实际开发过程中,还需要注意一些细节,如处理网络延迟、错误提示等,以提供更好的用户体验。希望本文对你有所帮助,祝你开发顺利!

如何在iOS软件中实现内购功能(续)

6. 其他注意事项

在实现iOS内购功能的过程中,还有一些其他的注意事项需要开发者关注,这些细节可能会影响到应用的稳定性和用户体验。

6.1 截图上传问题

在iTunes Connect中配置产品时,可能会出现“Waiting for Screenshot”的错误提示。不过不用担心,这个问题会在后续流程中处理。在等待上传截图的过程中,仍然可以测试购买功能。具体的截图上传步骤如下:
1. 准备好符合要求的截图,截图应清晰展示应用内购界面和相关产品信息。
2. 在iTunes Connect中找到对应的产品,点击进入产品编辑页面。
3. 在页面中找到截图上传区域,选择准备好的截图进行上传。

6.2 产品更新和同步问题

新的购买项目和更改可能需要几个小时才能在应用中反映出来。如果检查所有设置后仍然看不到产品,建议等待几个小时后再尝试。为了避免用户在等待过程中产生不良体验,在发起产品请求时,应向用户展示某种加载指示器,例如一个旋转的进度条或提示文字“正在加载,请稍候”。

6.3 价格本地化问题

虽然API会返回本地化的标题和描述,但价格不会自动本地化。在开发国际应用时,需要开发者自己处理价格的本地化。可以通过获取用户的地区信息,根据不同地区的货币格式来显示价格。例如,在美国显示为美元格式,在欧洲显示为欧元格式等。

7. 常见问题及解决方案

在实现内购功能的过程中,可能会遇到一些常见的问题,下面为你提供相应的解决方案。

问题描述 可能原因 解决方案
产品请求无响应 网络问题、产品ID错误、服务器延迟 检查网络连接,确保产品ID正确,等待几个小时后重试
显示无效产品标识符 产品ID拼写错误、产品未在iTunes Connect中正确配置、时间未同步 仔细检查产品ID,确保在iTunes Connect中正确配置产品,等待产品同步到服务器
无法进行购买 设备不支持支付、测试账户问题、App ID未开启内购功能 检查设备设置,确保支持支付;创建并使用有效的测试账户;检查App ID是否开启内购功能
交易状态未更新 代码逻辑错误、网络问题 检查 paymentQueue:updatedTransactions: 方法的实现,确保代码逻辑正确;检查网络连接
8. 总结与展望

通过本文的介绍,我们详细了解了在iOS软件中实现内购功能的全过程,包括在iTunes Connect中配置应用、添加产品、获取产品列表、向用户展示产品、处理购买交易以及一些注意事项和常见问题的解决方案。

内购功能为开发者提供了一种有效的盈利方式,同时也为用户提供了更多的选择和更好的体验。在未来的开发中,随着技术的不断发展和用户需求的不断变化,内购功能可能会有更多的创新和优化。例如,可能会出现更个性化的内购推荐、更安全的支付方式等。

开发者在实现内购功能时,应不断关注苹果的政策和技术更新,确保应用符合相关要求。同时,要注重用户体验,处理好各种异常情况,为用户提供稳定、便捷的内购服务。

下面是整个iOS内购实现过程的总结mermaid流程图:

graph LR;
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;

    A([开始]):::startend --> B(在iTunes Connect配置应用):::process;
    B --> C(配置产品类型和信息):::process;
    C --> D(确保App ID唯一):::process;
    D --> E(添加StoreKit框架和UFOStoreViewController类):::process;
    E --> F(获取产品列表):::process;
    F --> G(向用户展示产品):::process;
    G --> H(处理购买交易):::process;
    H --> I{交易是否成功}:::decision;
    I -- 是 --> J(记录交易数据、解锁内容、完成交易):::process;
    I -- 否 --> K(处理失败情况):::process;
    J --> L(可恢复之前完成的交易):::process;
    K --> M(检查问题并解决):::process;
    L --> N([结束]):::startend;
    M --> F;

希望本文能够帮助开发者顺利实现iOS内购功能,在应用开发的道路上取得更好的成绩。在实际开发过程中,不断积累经验,优化代码,为用户带来更优质的应用体验。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值