首页指南参考教程

Expo InAppPurchases

GitHub

npm

用于接受应用内购买的库。


已弃用: 该模块不再维护,并将在未来的 SDK 版本中删除。 开发于 2022 年 6 月暂停,该软件包于 2023 年 8 月被弃用。 我们推荐以下其中一项,两者均与 EAS 构建开发构建 兼容:

react-native-iap,为客户端 Google Play Billing 和 StoreKit API 提供接口
react-native-purchases,它还与 RevenueCat 的服务集成,用于服务器端收据验证等。

expo-in-app-purchases 提供 API 来接受应用内产品的付款。 在内部,这依赖于 Android 上的 Google Play 结算 库和 iOS 上的 StoreKit 框架。

Platform Compatibility

Android DeviceAndroid EmulatoriOS DeviceiOS SimulatorWeb

安装

由于应用商店限制,该模块在 not 中可在 Expo Go 应用 中使用。

你可以创建 开发构建 来使用此包。

Terminal
npx expo install expo-in-app-purchases

If you're installing this in a bare React Native app, you should also follow these additional installation instructions.

设置

iOS

要在 iOS 上使用应用内购买 API,你需要签署 付费应用协议 并设置你的银行和税务信息。 你还需要在 Xcode 中为你的应用启用 应用内购买功能

接下来,在 应用商店连接 中为你的应用创建一个条目并配置你的应用内购买,包括高亮应用内产品的特性和功能的详细信息(例如名称、定价和说明)。 确保每个产品的状态均为 Ready to Submit,否则在测试时将无法从应用内查询。 请务必添加任何必要的元数据来执行此操作,包括上传屏幕截图(这可以是你测试时的任何内容)和查看注释。 你的应用的状态还必须显示 Ready to Submit,但你无需实际提交你的应用或其产品以供审核,以在沙盒模式下测试购买。

现在,你可以在发布应用之前创建 沙箱账户 来测试应用内购买。

有关更多信息,请参阅 Apple 配置应用内购买的工作流程 here

安卓

在 Android 上,你必须首先为你的应用创建一个条目并在 谷歌游戏控制台.dll 中上传发布 APK。 从那里,你可以在 Store Presence > In-app products 下配置应用内购买及其详细信息。

然后,要测试你的购买,你必须将你的应用发布到 Google Play 中的封闭或开放测试轨道。 请注意,测试人员可能需要几个小时才能使用该应用。 确保你邀请的测试人员(包括你自己)选择加入你的应用测试。 在测试的选择加入 URL 上,测试人员将获得关于成为测试人员意味着什么的解释以及选择加入的链接。 此时,他们已全部设置完毕,一旦下载你的应用或从源代码构建,就可以开始购买。 有关测试的更多信息,请关注 这些说明

请注意,应用内购买需要物理设备在两个平台上运行,因此 无法在模拟器上测试

API

import * as InAppPurchases from 'expo-in-app-purchases';

Methods

InAppPurchases.connectAsync()

Connects to the app store and performs all of the necessary initialization to prepare the module to accept payments. This method must be called before anything else, otherwise an error will be thrown.

Returns

  • Promise<void>

Returns a Promise that fulfills when connection is established.

InAppPurchases.disconnectAsync()

Disconnects from the app store and cleans up memory internally. Call this when you are done using the In-App Purchases API in your app.

No other methods can be used until the next time you call connectAsync.

Returns


Returns a Promise that fulfils when disconnecting process is finished.

InAppPurchases.finishTransactionAsync(purchase, consumeItem)

NameTypeDescription
purchaseInAppPurchase

The purchase you want to mark as completed.

consumeItemboolean

Android Only. A boolean indicating whether or not the item is a consumable.


Marks a transaction as completed. This must be called on successful purchases only after you have verified the transaction and unlocked the functionality purchased by the user.

On Android, this will either "acknowledge" or "consume" the purchase depending on the value of consumeItem. Acknowledging indicates that this is a one time purchase (e.g. premium upgrade), whereas consuming a purchase allows it to be bought more than once. You cannot buy an item again until it's consumed. Both consuming and acknowledging let Google know that you are done processing the transaction. If you do not acknowledge or consume a purchase within three days, the user automatically receives a refund, and Google Play revokes the purchase.

On iOS, this will mark the transaction as finished and prevent it from reappearing in the purchase listener callback. It will also let the user know their purchase was successful.

consumeItem is ignored on iOS because you must specify whether an item is a consumable or non-consumable in its product entry in App Store Connect, whereas on Android you indicate an item is consumable at runtime.

Make sure that you verify each purchase to prevent faulty transactions and protect against fraud before you call finishTransactionAsync. On iOS, you can validate the purchase's transactionReceipt with the App Store as described here. On Android, you can verify your purchase using the Google Play Developer API as described here.

Example

if (!purchase.acknowledged) {
  await finishTransactionAsync(purchase, false); // or true for consumables
}

Returns


InAppPurchases.getBillingResponseCodeAsync()

Returns the last response code. This is more descriptive on Android since there is native support for retrieving the billing response code.

On Android, this will return IAPResponseCode.ERROR if you are not connected or one of the billing response codes found here if you are.

On iOS, this will return IAPResponseCode.OK if you are connected or IAPResponseCode.ERROR if you are not. Therefore, it's a good way to test whether or not you are connected and it's safe to use the other methods.

Example

const responseCode = await getBillingResponseCodeAsync();
 if (responseCode !== IAPResponseCode.OK) {
  // Either we're not connected or the last response returned an error (Android)
}

Returns


Returns a Promise that fulfils with an number representing the IAPResponseCode.

InAppPurchases.getProductsAsync(itemList)

NameTypeDescription
itemListstring[]

The list of product IDs whose details you want to query from the app store.


Retrieves the product details (price, description, title, etc) for each item that you inputted in the Google Play Console and App Store Connect. These products are associated with your app's specific Application/Bundle ID and cannot be retrieved from other apps. This queries both in-app products and subscriptions so there's no need to pass those in separately.

You must retrieve an item's details before you attempt to purchase it via purchaseItemAsync. This is a prerequisite to buying a product even if you have the item details bundled in your app or on your own servers.

If any of the product IDs passed in are invalid and don't exist, you will not receive an IAPItemDetails object corresponding to that ID. For example, if you pass in four product IDs in but one of them has a typo, you will only get three response objects back.

Example

// These product IDs must match the item entries you created in the App Store Connect and Google Play Console.
// If you want to add more or edit their attributes you can do so there.

const items = Platform.select({
  ios: [
    'dev.products.gas',
    'dev.products.premium',
    'dev.products.gold_monthly',
    'dev.products.gold_yearly',
  ],
  android: ['gas', 'premium', 'gold_monthly', 'gold_yearly'],
});

 // Retrieve product details
const { responseCode, results } = await getProductsAsync(items);
if (responseCode === IAPResponseCode.OK) {
  this.setState({ items: results });
}

Returns


Returns a Promise that resolves with an IAPQueryResponse containing IAPItemDetails objects in the results array.

InAppPurchases.getPurchaseHistoryAsync(options)

NameTypeDescription
options
(optional)
IAPPurchaseHistoryOptions

An optional PurchaseHistoryOptions object.


Retrieves the user's purchase history.

Please note that on iOS, StoreKit actually creates a new transaction object every time you restore completed transactions, therefore the purchaseTime and orderId may be inaccurate if it's a restored purchase. If you need the original transaction's information you can use originalPurchaseTime and originalOrderId, but those will be 0 and an empty string respectively if it is the original transaction.

You should not call this method on launch because restoring purchases on iOS prompts for the user’s App Store credentials, which could interrupt the flow of your app.

Returns


Returns a Promise that fulfills with an IAPQueryResponse that contains an array of InAppPurchase objects.

InAppPurchases.purchaseItemAsync(itemId, details)

NameTypeDescription
itemIdstring

The product ID of the item you want to buy.

details
(optional)
IAPPurchaseItemOptions

Android Only. Details for billing flow.


Initiates the purchase flow to buy the item associated with this productId. This will display a prompt to the user that will allow them to either buy the item or cancel the purchase. When the purchase completes, the result must be handled in the callback that you passed in to setPurchaseListener.

Remember, you have to query an item's details via getProductsAsync and set the purchase listener before you attempt to buy an item.

Apple and Google both have their own workflows for dealing with subscriptions. In general, you can deal with them in the same way you do one-time purchases but there are caveats including if a user decides to cancel before the expiration date. To check the status of a subscription, you can use the Google Play Developer API on Android and the Status Update Notifications service on iOS.

Returns


Returns a Promise that resolves when the purchase is done processing. To get the actual result of the purchase, you must handle purchase events inside the setPurchaseListener callback.

Event Subscriptions

InAppPurchases.setPurchaseListener(callback)

NameTypeDescription
callback(result: IAPQueryResponse<InAppPurchase>) => void

The callback function you want to run when there is an update to the purchases.


Sets a callback that handles incoming purchases. This must be done before any calls to purchaseItemAsync are made, otherwise those transactions will be lost. You should set the purchase listener globally, and not inside a specific screen, to ensure that you receive incomplete transactions, subscriptions, and deferred transactions.

Purchases can either be instantiated by the user (via purchaseItemAsync) or they can come from subscription renewals or unfinished transactions on iOS (e.g. if your app exits before finishTransactionAsync was called).

Note that on iOS, the results array will only contain one item: the one that was just purchased. On Android, it will return both finished and unfinished purchases, hence the array return type. This is because the Google Play Billing API detects purchase updates but doesn't differentiate which item was just purchased, therefore there's no good way to tell but in general it will be whichever purchase has acknowledged set to false, so those are the ones that you have to handle in the response. Consumed items will not be returned however, so if you consume an item that record will be gone and no longer appear in the results array when a new purchase is made.

Example

// Set purchase listener
 setPurchaseListener(({ responseCode, results, errorCode }) => {
  // Purchase was successful
  if (responseCode === IAPResponseCode.OK) {
    results.forEach(purchase => {
      if (!purchase.acknowledged) {
        console.log(`Successfully purchased ${purchase.productId}`);
        // Process transaction here and unlock content...

        // Then when you're done
        finishTransactionAsync(purchase, true);
      }
    });
  } else if (responseCode === IAPResponseCode.USER_CANCELED) {
    console.log('User canceled the transaction');
  } else if (responseCode === IAPResponseCode.DEFERRED) {
    console.log('User does not have permissions to buy but requested parental approval (iOS only)');
  } else {
    console.warn(`Something went wrong with the purchase. Received errorCode ${errorCode}`);
  }
});

Returns

  • void

Interfaces

IAPItemDetails

Details about the purchasable item that you inputted in App Store Connect and Google Play Console.

IAPItemDetails Properties

NameTypeDescription
descriptionstring

User facing description about the item.

Example

Currency used to trade for items in the game

pricestring

The price formatted with the local currency symbol. Use this to display the price, not to make calculations.

Example

$1.99

priceAmountMicrosnumber

The price in micro-units, where 1,000,000 micro-units equal one unit of the currency. Use this for calculations.

Example

1990000

priceCurrencyCodestring

The local currency code from the ISO 4217 code list.

Example

USD, CAN, RUB

productIdstring

The product ID representing an item inputted in App Store Connect and Google Play Console.

Example

gold

subscriptionPeriod
(optional)
string

The length of a subscription period specified in ISO 8601 format. In-app purchases return P0D. On iOS, non-renewable subscriptions also return P0D.

Example

P0D, P6W, P3M, P6M, P1Y

titlestring

The title of the purchasable item. This should be displayed to the user and may be different from the productId.

Example

Gold Coin

typeIAPItemType

The type of the purchase. Note that this is not very accurate on iOS as this data is only available on iOS 11.2 and higher and non-renewable subscriptions always return IAPItemType.PURCHASE.


Only for:
Android

IAPPurchaseItemOptions

The purchaseItemAsync billing context on Android.

IAPPurchaseItemOptions Properties

NameTypeDescription
accountIdentifiers
(optional)
{ obfuscatedAccountId: string, obfuscatedProfileId: string }

Account identifiers, both need to be provided to work with Google Play Store.

isVrPurchaseFlow
(optional)
boolean

Whether the purchase is happening in a VR context.

oldPurchaseToken
(optional)
string

The purchaseToken of the purchase that the user is upgrading or downgrading from. This is mandatory for replacing an old subscription such as when a user upgrades from a monthly subscription to a yearly one that provides the same content. You can get the purchase token from getPurchaseHistoryAsync.


IAPQueryResponse

The response type for queries and purchases.

IAPQueryResponse Properties

NameTypeDescription
errorCode
(optional)
IAPErrorCode

IAPErrorCode that provides more detail on why an error occurred. null unless responseCode is IAPResponseCode.ERROR.

responseCodeIAPResponseCode

The response code from a query or purchase.

results
(optional)
QueryResult[]

The array containing the InAppPurchase or IAPItemDetails objects requested depending on the method.


InAppPurchase

InAppPurchase Properties

NameTypeDescription
acknowledgedboolean

Boolean indicating whether this item has been "acknowledged" via finishTransactionAsync.

orderIdstring

A string that uniquely identifies a successful payment transaction.

originalOrderId
(optional)
stringOnly for:
iOS

Represents the original order ID for restored purchases.

originalPurchaseTime
(optional)
stringOnly for:
iOS

Represents the original purchase time for restored purchases.

packageName
(optional)
stringOnly for:
Android

The application package from which the purchase originated.

Example

com.example.myapp

productIdstring

The product ID representing an item inputted in Google Play Console and App Store Connect.

Example

gold

purchaseStateInAppPurchaseState

The state of the purchase.

purchaseTimenumber

The time the product was purchased, in milliseconds since the epoch (Jan 1, 1970).

purchaseToken
(optional)
stringOnly for:
Android

A token that uniquely identifies a purchase for a given item and user pair.

transactionReceipt
(optional)
stringOnly for:
iOS

The App Store receipt found in the main bundle encoded as a Base64 String.


Types

IAPPurchaseHistoryOptions

NameTypeDescription
useGooglePlayCache
(optional)
booleanOnly for:
Android

A boolean that indicates whether or not you want to make a network request to sync expired/consumed purchases and those on other devices.

  • If set to true, this method returns purchase details only for the user's currently owned items (active subscriptions and non-consumed one-time purchases). If set to false, it will make a network request and return the most recent purchase made by the user for each product, even if that purchase is expired, canceled, or consumed.
  • The return type if this is false is actually a subset of when it's true. This is because Android returns a PurchaseHistoryRecord which only contains the purchase time, purchase token, and product ID, rather than all of the attributes found in the InAppPurchase type.
Default: true

QueryResult

Acceptable values are: InAppPurchase, IAPItemDetails.

Enums

IAPErrorCode

Abstracts over the Android Billing Response Codes and iOS SKErrorCodes.

UNKNOWN

IAPErrorCode.UNKNOWN = 0

An unknown or unexpected error occurred. See SKErrorUnknown on iOS, ERROR on Android.

PAYMENT_INVALID

IAPErrorCode.PAYMENT_INVALID = 1

The feature is not allowed on the current device, or the user is not authorized to make payments. See SKErrorClientInvalid, SKErrorPaymentInvalid, and SKErrorPaymentNotAllowed on iOS, FEATURE_NOT_SUPPORTED on Android.

SERVICE_DISCONNECTED

IAPErrorCode.SERVICE_DISCONNECTED = 2

Play Store service is not connected now. See SERVICE_DISCONNECTED on Android.

SERVICE_UNAVAILABLE

IAPErrorCode.SERVICE_UNAVAILABLE = 3

Network connection is down. See SERVICE_UNAVAILABLE on Android.

SERVICE_TIMEOUT

IAPErrorCode.SERVICE_TIMEOUT = 4

The request has reached the maximum timeout before Google Play responds. See SERVICE_TIMEOUT on Android.

BILLING_UNAVAILABLE

IAPErrorCode.BILLING_UNAVAILABLE = 5

Billing API version is not supported for the type requested. See BILLING_UNAVAILABLE on Android.

ITEM_UNAVAILABLE

IAPErrorCode.ITEM_UNAVAILABLE = 6

Requested product is not available for purchase. See SKErrorStoreProductNotAvailable on iOS, ITEM_UNAVAILABLE on Android.

DEVELOPER_ERROR

IAPErrorCode.DEVELOPER_ERROR = 7

Invalid arguments provided to the API. This error can also indicate that the application was not correctly signed or properly set up for In-app Billing in Google Play. See DEVELOPER_ERROR on Android.

ITEM_ALREADY_OWNED

IAPErrorCode.ITEM_ALREADY_OWNED = 8

Failure to purchase since item is already owned. See ITEM_ALREADY_OWNED on Android.

ITEM_NOT_OWNED

IAPErrorCode.ITEM_NOT_OWNED = 9

Failure to consume since item is not owned. See ITEM_NOT_OWNED on Android.

CLOUD_SERVICE

IAPErrorCode.CLOUD_SERVICE = 10

Apple Cloud Service connection failed or invalid permissions. See SKErrorCloudServicePermissionDenied, SKErrorCloudServiceNetworkConnectionFailed and SKErrorCloudServiceRevoked on iOS.

PRIVACY_UNACKNOWLEDGED

IAPErrorCode.PRIVACY_UNACKNOWLEDGED = 11

The user has not yet acknowledged Apple’s privacy policy for Apple Music. See SKErrorPrivacyAcknowledgementRequired on iOS.

UNAUTHORIZED_REQUEST

IAPErrorCode.UNAUTHORIZED_REQUEST = 12

The app is attempting to use a property for which it does not have the required entitlement. See SKErrorUnauthorizedRequestData on iOS.

INVALID_IDENTIFIER

IAPErrorCode.INVALID_IDENTIFIER = 13

The offer identifier or price specified in App Store Connect is no longer valid. See SKErrorInvalidSignature, SKErrorInvalidOfferPrice, SKErrorInvalidOfferIdentifier on iOS.

MISSING_PARAMS

IAPErrorCode.MISSING_PARAMS = 14

Parameters are missing in a payment discount. See SKErrorMissingOfferParams on iOS.

IAPItemType

PURCHASE

IAPItemType.PURCHASE = 0

One time purchase or consumable.

SUBSCRIPTION

IAPItemType.SUBSCRIPTION = 1

Subscription.

IAPResponseCode

OK

IAPResponseCode.OK = 0

Response returned successfully.

USER_CANCELED

IAPResponseCode.USER_CANCELED = 1

User canceled the purchase.

ERROR

IAPResponseCode.ERROR = 2

An error occurred. Check the errorCode for additional details.

Only for:
iOS

DEFERRED

IAPResponseCode.DEFERRED = 3

Purchase was deferred.

InAppPurchaseState

PURCHASING

InAppPurchaseState.PURCHASING = 0

The transaction is being processed.

PURCHASED

InAppPurchaseState.PURCHASED = 1

The App Store successfully processed payment.

FAILED

InAppPurchaseState.FAILED = 2

The transaction failed.

Only for:
iOS

RESTORED

InAppPurchaseState.RESTORED = 3

This transaction restores content previously purchased by the user. Read the originalTransaction properties to obtain information about the original purchase.

Only for:
iOS

DEFERRED

InAppPurchaseState.DEFERRED = 4

The transaction has been received, but its final status is pending external action such as the Ask to Buy feature where a child initiates a new purchase and has to wait for the family organizer's approval. Update your UI to show the deferred state, and wait for another callback that indicates the final status.

Expo 中文网 - 粤ICP备13048890号