返回博客首页
← 所有文章

原生脚本 iOS 应用内购买

2021 年 10 月 20 日 — 作者:Brad Martin

应用内购买和订阅是允许用户快速购买应用程序内内容的好方法。大多数 iOS 用户的 Apple 帐户都设置了某种支付方式,这使得在应用程序中提供购买选项变得容易。

如果您仍然不确定 iOS 上的应用内购买是什么,以下屏幕截图可能会有所帮助。

iOS Purchase Screen

先决条件

提供应用内购买可能令人生畏,但我希望本指南能帮助您概述配置应用程序的步骤,即使您以前从未设置过购买。

  1. 您必须拥有 Apple 开发者帐户。
  2. 您必须完成 AppStore Connect 上“协议、税务和银行业务”部分中列出的 Apple 有偿应用程序协议。
  3. 在有偿应用程序部分输入您的银行信息并通过 Apple 验证。
  4. 一台实际的 iOS 设备,您无法在 iOS 模拟器上完全测试应用内购买。
Sandbox Tester

现在您已准备好向应用程序添加购买项目。

添加购买项目

在您要添加购买项目的应用程序下,在左侧菜单的“应用内购买”下,您可以选择“管理”,然后单击列表旁边出现的 + 按钮。

Adding Purchase Items

创建项目时,产品 ID 非常重要,因为您将使用它在应用程序中查询项目。为了减少代码,请尽可能在您的 Apple iOS 应用程序和 Google Play 商店中使用相同的产品 ID(为了清楚起见,我将在单独的文章中介绍 Google)。这将使您的应用程序代码更容易在运行时查询项目,我们很快就会回顾这一点。

Purchase Items ID

创建项目后,它将显示在列表中,并已准备好进行测试。

Purchase Item List

测试

在购买测试期间,您需要在 AppStore Connect 上创建一个 沙盒测试人员。

Sandbox Tester

您可以在 iOS 设备上的“设置 -> AppStore -> 沙盒帐户”中使用沙盒测试人员帐户登录该设备。

Sandbox Tester on iPhone

如果您没有在此处登录设备,则在购买步骤中会提示您,类似于未登录 Apple 帐户的设备。一旦您开始购买流程,Apple 会接管整个 UI/UX 流程,直到用户完成购买商品或取消购买,您可以根据情况处理结果。

使用原生脚本在 iOS 上设置应用内购买

安装插件

ns plugin add @nativescript/payments

此插件使用 RxJS Observable 在购买流程期间发出事件。如果您不熟悉 RxJS,请不要担心,该插件使一切保持简洁明了,易于理解。

使用应用程序代码实现

  1. init() - 这将设置插件的内部系统。
  2. paymentEvents.connect() - 连接 RxJS Observable。
  3. paymentEvents.pipe(toMainThread()).subscribe((event: PaymentEvent.Type) => {... }) - 这是您将处理购买流程中各种事件的地方。
  4. fetchItems(['item.id']) - 从 App Store 查询由提供的 ID 数组指定的商品。
  5. buyItem('item.id') - 通过将控制权交给 iOS 以显示应用内购买表来启动购买流程。
  6. finalizeOrder(payload) - 在购买成功后完成购买流程。到达这里后,您通常会通过将 iOS 的收据令牌存储在您的后端来与您的后端进行交互。

以下是一个在多个生产应用程序中运行的完整示例

import {
  buyItem,
  BuyItemOptions,
  canMakePayments,
  fetchItems,
  finalizeOrder,
  init as initPayments,
  Item,
  PaymentEvent,
  paymentEvents,
  toMainThread,
} from '@nativescript/payments'
import { Dialogs } from '@nativescript/core'

export class SomeViewModel {
  private item: Item

  pageLoaded() {
    // Connect to the RxJS Observable
    paymentEvents.connect()

    // Subscribe to the RxJS Observable
    // You do not have to handle all of the events
    // RETRIEVING_ITEMS && PROCESSING_ORDER are the ones you'll want to use to handle the purchase flow
    const subscription = paymentEvents.pipe(toMainThread()).subscribe((event: PaymentEvent.Type) => {
      switch (event.context) {
        case PaymentEvent.Context.CONNECTING_STORE:
          console.log('Store Status: ' + event.result)
          if (event.result === PaymentEvent.Result.SUCCESS) {
            const canPay = canMakePayments()
            if (canPay) {
              // pass in your product IDs here that you want to query for
              fetchItems(['io.nstudio.iapdemo.coinsfive', 'io.nstudio.iapdemo.coinsone', 'io.nstudio.iapdemo.coinsonethousand'])
            }
          }
          break
        case PaymentEvent.Context.RETRIEVING_ITEMS:
          if (event.result === PaymentEvent.Result.SUCCESS) {
            // if you passed multiple items you will need to handle accordingly for your app
            this.item = event.payload
          }
          break
        case PaymentEvent.Context.PROCESSING_ORDER:
          if (event.result === PaymentEvent.Result.FAILURE) {
            console.log(`🛑 Payment Failure - ${event.payload.description} 🛑`)
            // handle the failure of the purchase
            Dialogs.alert({ title: 'Error', message: 'Failed to purchase item.', okButtonText: 'Okay' })
          } else if (event.result === PaymentEvent.Result.SUCCESS) {
            // handle the successful purchase
            console.log('🟢 Payment Success 🟢')
            console.log(`Order Date: ${event.payload.orderDate}`)
            console.log(`Receipt Token: ${event.payload.receiptToken}`)
            finalizeOrder(event.payload)
          }
          break
        case PaymentEvent.Context.FINALIZING_ORDER:
          if (event.result === PaymentEvent.Result.SUCCESS) {
            console.log('Order Finalized')
          }
          break
        case PaymentEvent.Context.RESTORING_ORDERS:
          console.log(event)
          break
        default:
          console.log(`Invalid EventContext: ${event}`)
          break
      }
    })

    // This initializes the internal payment system for the plugin
    initPayments()
  }

  buttonTap() {
    const opts: BuyItemOptions = {
      accountUserName: '[email protected]',
      android: {
        vrPurchase: true,
      },
      ios: {
        quantity: 1,
        simulatesAskToBuyInSandbox: true,
      },
    }

    // This method will kick off the platform purchase flow
    // We are passing the item and an optional object with some configuration
    buyItem(this.item, opts)
  }
}

可以根据需要简化一些事件处理,但这应该足以为您提供在 iOS 上实现应用内购买所需的一切。

结论

在这篇文章中,我们了解了如何

  • 在 AppStore Connect 帐户上设置应用内购买
  • 添加应用内购买项目
  • 如何安装和使用原生脚本插件

请随时 在此 报告您遇到的任何问题,并自信地为您的应用程序提供应用内购买!我将在后续文章中介绍 Google Play 商店。