全部提交

main
刘涛 2024-01-29 18:49:33 +08:00
commit 3b87d20391
1329 changed files with 69883 additions and 0 deletions

5
.signature Normal file
View File

@ -0,0 +1,5 @@
{
"timestamp": 1691676008,
"signature": "sQXiiJfhs+6yThItVw1B9kgDVKyQPhVE/j5KKYJY3nL/dEGXTA+ue9NudwNAvVGN4AP5PoGfgizEPcKID5vPbEqmyMNc5jSVnSe7di/5xVtzOQTwGVp2P1zKpN7WgqoiIvgiXXv//PnxXkgIVHx1JgxIeggLUwOAH9AYdvV+OSRP31eIQGQIcB9VCp3YD3egXG2LFj2CycUFdwMlza1vZBIc46iYyGT2Jl9rBBXRqSD6RlJPjWeOLqK2oi/syZ1aXfc5DxymLWx9WeRV5r/YH12cu+IyDgMNNNy/2ZUVUI7mvys0t5LWMH/6ANR+TRD9BOVCJcdC/7Gt/7pI0kJpBamRDfbeu2/cvz67lfKsYqOrIi7foaPTKIqLZ5iJobUCaCR19CbdPdL5rSXb1e7bhhSOVPyJnm0SIEhjOpe9+KP+fn8pnzl8jpUPm77uotNLAzQictuCYfBkmq2wwxzAhAnkl398qHU/QHKuDiYAUq+pkpvW5s4e5/KlSyqJus6w",
"publicKey": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQm9qQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FZOEFNSUlCaWdLQ0FZRUFzdUhXYUhsZ0I1cVF4ZEJjTlJKSAordHR4SmoxcVY1NTdvMlZaRE1XaXhYRVBkRTBEMVFkT1JIRXNSS1RscmplUXlERU83ZlNQS0ZwZ1A3MU5TTnJCCkFHM2NFSU45aHNQVDhOVmllZmdWem5QTkVMenFkVmdEbFhpb2VpUnV6OERKWFgvblpmU1JWKytwbk9ySTRibG4KS0twelJlNW14OTc1SjhxZ1FvRktKT0NNRlpHdkJMR2MxSzZZaEIzOHJFODZCZzgzbUovWjBEYkVmQjBxZm13cgo2ZDVFUXFsd0E5Y3JZT1YyV1VpWXprSnBLNmJZNzRZNmM1TmpBcEFKeGNiaTFOaDlRVEhUcU44N0ZtMDF0R1ZwCjVNd1pXSWZuYVRUemEvTGZLelR5U0pka0tldEZMVGdkYXpMYlpzUEE2aHBSK0FJRTJhc0tLTi84UUk1N3UzU2cKL2xyMnZKS1IvU2l5eEN1Q20vQWJkYnJMbXk0WjlSdm1jMGdpclA4T0lLQWxBRWZ2TzV5Z2hSKy8vd1RpTFlzUQp1SllDM0V2UE16ZGdKUzdGR2FscnFLZzlPTCsxVzROY05yNWdveVdSUUJ0cktKaWlTZEJVWmVxb0RvSUY5NHpCCndGbzJJT1JFdXFqcU51M3diMWZIM3p1dGdtalFra3IxVjJhd3hmcExLWlROQWdNQkFBRT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg"
}

722
CHANGELOG-ASSETSTORE.md Normal file
View File

@ -0,0 +1,722 @@
# PLEASE NOTE this changelog is no longer maintained. See [CHANGELOG.md](CHANGELOG.md) for the current Unity IAP changelog.
## [2.2.7] - 2021-01-27
### Changed
- Amazon - Include SDK version 2.0.76. Continuing to investigate sensitivity to slow-network conditions.
### Fixed
- GooglePlay - Purchasing silently failing, showing `Failed to purchase unknown product {0}: System.Collections.Generic.List``1[UnityEngine.AndroidJavaObject]` in log, not calling `IStoreListener.OnPurchaseFailed`, after prior purchase when offline, after Initializing, until app has been restarted.
- GooglePlay - `IStoreController.FetchAdditionalProducts` cleared receipts inappropriately.
- Apple - Exception seen when purchasing and initializing with existing purchases (e.g. Non-Consumables) on devices set to Thai language. Internal logging of `DateTime` used `CurrentCulture` instead of `InvariantCulture`. Removed logs.
## [2.2.6] - 2021-01-14
### Changed
- GooglePlay - OnSetupFailed called immediately when Unity IAP fails to connect to the underlying service. To handle users who are logged-out of Google Play we stop the initialization process quickly.
### Fixed
- GooglePlay - ConfirmPendingPurchase failed to acknowledge purchases after purchase and app restart.
- GooglePlay - ProcessPurchase unexpectely called when player backgrounded and foregrounded app before the initialization phase finished.
- GooglePlay - Initialization incorrectly reported as failing, while race-condition returned fetched product metadata simultaneously.
- Apple - "ArgumentOutOfRangeException: Not a valid calendar for the given culture" during Apple receipt validation (`CrossPlatformValidator.Validate` > `AppleValidator.Validate` > `AppleReceiptParser.Parse`) on devices set to Thai locale.
## [2.2.5] - 2020-12-14
### Fixed
- GooglePlay - Fails to initialize when the player has made no purchases
- GooglePlay - Missing ProcessPurchase callback at app start when the transaction is (1) purchased, (2) processed by the app with a ProcessPurchaseResult.Pending result, (3) the app is terminated, and (4) the app is restarted
- GooglePlay - NullReferenceException from "FillPurchases" (logged internal API) when returning from background, unpredictably
- Apple - Unity IAP 2.2.2's Apple Silicon fix not included in release; continuous integration pipeline fixed
- `StandardPurchasingModule.appStore` returns `AppStore.MacAppStore` for Mac App Store, `AppStore.AppleAppStore` for iOS App Store, and `AppStore.WinRT` for Windows Desktop. (No change to
`AppStore.SamsungApps`, `AppStore.AmazonAppStore`, or `AppStore.GooglePlay`.)
## [2.2.4] - 2020-12-03
### Fixed
- GooglePlay - `IStoreListener.ProcessPurchase` called more than once for any purchase which is not consumed, i.e. when `ProcessPurchaseResult.Pending` is returned, by fixing a race-condition.
### Changed
- GooglePlay - To receive `ProcessPurchase` calls after foregrounding the app, when a purchase is made outside the app (e.g. in the Play Store app), please upgrade the core package via the Package Manager to `com.unity.purchasing@2.2.1` or higher.
## [2.2.3] - 2020-12-01
### Fixed
- GooglePlay - `IStoreListener.OnInitialized` is now called after all purchases have been fetched from the store.
- GooglePlay - `IStoreListener.OnPurchaseFailed` would not be called in projects where the purchased product's ID differed from its Store Specific ID.
- GooglePlay - All receipts were corrupt after a purchase of a Consumable, until the next Android `Activity.onResume` lifecycle event, if the user had previously bought a Subscription.
- GooglePlay - Fix `MissingMethodException` seen in projects using `com.unity.purchasing@2.0.3` through `2.2.0` when a user launches their game after having previously purchased a Product.
## [2.2.2] - 2020-11-20
### Fixed
- Mac App Store - Support for Apple Silicon, `arm64` slice added to binary
- GooglePlay - ProductMetadata.localizedPrice no longer floors fractions, e.g. "$19.99" was "$19.00"
- GooglePlay - Fix several purchasing-flow issues
- OnPurchaseFailed not called after canceled purchase
- Exceptions shown in logcat after normal purchase
- Purchases of consumables left incomplete, resulting in "product already owned" errors
- GooglePlay - Fix initialization when [Android] "Player Settings > Publishing Settings > Minification: Proguard" is enabled. "AndroidJavaException: java.lang.ClassNotFoundException: com.android.billingclient.api.PurchasesUpdatedListener"
## [2.2.1] - 2020-11-13
### Fixed
- GooglePlay - ProductMetadata.localizedPrice always `0`
- GooglePlay - "Main" thread warning seen in IStoreListener.OnInitialized and related callbacks.
### Added
- GooglePlay - Subscription metadata is now available in `GoogleProductMetadata` from `ProductMetadata.GetGoogleProductMetadata()` via `IStoreController.products`.
- For example, use `GoogleProductMetadata googleMetadata = storeController.product.all[0].metadata.GetGoogleProductMetadata();` now instead of the deprecated, `IGooglePlayStoreExtensions.GetProductJSONDictionary`.
- string originalJson - Note, a single SkuDetails JSON, instead of multiple from `GetProductJSONDictionary`
- string subscriptionPeriod
- string freeTrialPeriod
- string introductoryPrice
- string introductoryPricePeriod
- int introductoryPriceCycles
## [2.2.0] - 2020-11-06
### Changed
- GooglePlay - Upgrades to Google Play Billing Library v3.0.1. This replaces the Google Play AIDL implementation.
- The transaction identifier is always purchaseToken. This replaces the v2.1.0 orderId behavior. See `IGooglePlayConfiguration` changes below.
- Adds new and deprecates `IGooglePlayStoreExtensions` APIs
- Deprecated - disabled.
- `IGooglePlayStoreExtensions.IsOwned`
- `IGooglePlayStoreExtensions.SetLogLevel`
- `IGooglePlayStoreExtensions.GetProductJSONDictionary` - use the `ProductMetadata` of `product.metadata` from `IStoreController.products`
- Deprecated - will be removed in future release.
- `IGooglePlayStoreExtensions.FinishAdditionalTransaction`
- New variant (signature)
- `IGooglePlayStoreExtensions.UpgradeDowngradeSubscription(string oldSku, string newSku, int desiredProrationMode)` - allow refined proration mode for subscription upgrade or downgrade as described in the [Google ProrationMode documentation](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode)
- New methods
- `IGooglePlayStoreExtensions.ConfirmSubscriptionPriceChange(string productId, Action<bool> callback)` - prompt users to confirm a price change for their subscription
- `IGooglePlayStoreExtensions.SetDeferredPurchaseListener(Action<Product> action)` - listen for new pending out-of-app purchases, consider notifying users here
- `IGooglePlayStoreExtensions.SetObfuscatedAccountId(string accountId)` - to help Google detect and reduce irregular activities when making a purchase
- `IGooglePlayStoreExtensions.SetObfuscatedProfileId(string profileId)` - to help Google detect and reduce irregular activities when making a purchase
- deprecates `IGooglePlayConfiguration` APIs
- Deprecated - disabled.
- `IGooglePlayConfiguration.SetPublicKey`
- `IGooglePlayConfiguration.aggressivelyRecoverLostPurchases`
- `IGooglePlayConfiguration.UsePurchaseTokenForTransactionId`
### Fixed
- IAP Catalog - GooglePlay - pricing template when exporting to CSV, now sets autofill pricing to `false` instead of `true`
- GooglePlay - Subscription receipts will update, e.g. after an upgrade or downgrade, whenever the player pauses or resumes their app. See this change reflected in the `product.receipt` of `IStoreController.products`.
### Added
- Apple Macos - Support for building IL2CPP on MacOS
## [2.1.1] - 2020-10-23
### Fixed
- Amazon - Fix build failure caused by duplicate classes
- Amazon - Fix ResponseReceiver flaw reported by Amazon APK audit caused by permission attribute location in AndroidManifest.xml
## [2.1.0] - 2020-10-14
### Future
- GooglePlay - Transaction IDs for all Google Play transactions will be switched to use Google's Purchase Token in a future version of Unity IAP. Google's Order ID previously was used when possible. This version introduces a feature to switch to Purchase Token now, and also to automatically use Purchase Token if `aggressivelyRecoverLostPurchases = true`.
### Changed
- GooglePlay - Live payments using `aggressivelyRecoverLostPurchases = true` - switched to Google's Purchase Token from using Google's Order ID to represent all transaction IDs. Automatically sets `Product.transactionID` to GooglePlay `purchaseToken` when `aggressivelyRecoverLostPurchases` is `true`. Continues to use `orderId`, otherwise. CLARIFICATION: To reinforce the preferred usage of `aggressivelyRecoverLostPurchases`, a de-duplicating backend purchase verification server is recommended to be added to a game's transaction verification pipeline when using this feature. Without such a server the recovered purchases may not be easily or safely de-duplicated by a client.
- When upgrading from previous versions of Unity IAP, and if enabled `bool IGooglePlayConfiguration.aggressivelyRecoverLostPurchases`, any purchases your users have made will be processed again by Unity IAP; ProcessPurchase will be called for all these purchases.
- Afterwards, for future purchases, this change reduces future duplicate processing calls; ProcessPurchase should no longer be called after an interrupted purchase for an item already purcahsed by the user.
- Update purchase verification servers to treat orderId and purchaseToken as the same ID. Extract the purchaseToken from the JSON receipt, or fetch the orderId using a purchaseToken and the server API [`purchases.products` Google Play Developer API](https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.products).
- Override this behavior with `UsePurchaseTokenForTransactionId`, below.
- GooglePlay Security - Add GooglePlayReceipt.orderID and obsolete GooglePlayReceipt.transactionID for the local receipt validator, for clarity.
- GooglePlay - Reduce the frequency of double-processing when a purchase is canceled, if using `aggressivelyRecoverLostPurchases = true`. Always records purchaseToken in TransactionLog when a transaction is completed.
### Added
- GooglePlay - Ability to override the `Product.transactionID` and use either Google's Purchase Token, or the legacy Order ID when possible, with `UsePurchaseTokenForTransactionId`.
- Call `void IGooglePlayConfiguration.UsePurchaseTokenForTransactionId(bool usePurchaseToken)` to disable the default behavior
- a) `false` to use the `orderId`, when possible; this is the legacy and non-unique transaction ID behavior. This must switch to the purchaseToken when the orderId is not available from Google, which is when `aggressivelyRecoverLostPurchases = true`.
- b) `true` to always use the unique purchaseToken in transactionID. NOTE: this is the preferred option, and it will be the only behavior available in a future version of Unity IAP.
- **Background:** The GooglePlay purchaseToken is the unique identifier for all GooglePlay purchases; it is always available for all purchase types and all purchase records. The GooglePlay orderId is not available for all purchase types, notably sandbox and promo code, and also is currently not available for those purchase records which are returned for `aggressivelyRecoverLostPurchases = true` recovered purchases: the Google Play Billing history API used by this feature does not return orderId and therefore cannot be set as the Product.transactionID at that time. Historically, Unity IAP chose to prefer orderId for transactionID in its original implementation. And when the orderId was missing from purchase records (sandbox test purchases, and other no-money purchases), Unity IAP would use the purchaseToken as the transactionID.
- **Impact:** Since Unity IAP version 1.23.3 this resulted in non-unique transactionIDs for purchases made which were "aggressively" restored: two distinct ProcessPurchase calls for one purchase could be generated, where Product.transactionID would change between two values (orderId and purchaseToken) and be non-unique. With this version, Unity IAP is starting a transition to only using purchaseToken, and avoids the impact for any new purchases made by a user.
### Fixed
- Receipt Validation Obfuscator - Compilation of `GoolgPlayTangle.cs` and `AppleTangle.cs` files. The generated files have been restored to their pre-2.0.0 location.
- GooglePlay - 2020.2 support, removing usage of obsolete UnityEngine.VR.VRSettings API.
## [2.0.0] - 2020-07-15
### Removed
- UnityChannel / Xiaomi - Completed deprecation, removing related APIs: `UnityEngine.Store`, `IUnityChannelExtensions`, `IUnityChannelConfiguration`.
- CloudMoolah - Removed.
- Tizen - Removed.
- UDP package is no longer installed as a prerequisite
### Added
- UWP - Additional logging during initialization to diagnose developer portal misconfigurations. See https://docs.microsoft.com/en-us/windows/uwp/monetize/in-app-purchases-and-trials#how-to-use-product-ids-for-add-ons-in-your-code for a broad discussion of Windows.ApplicationModel.Store configuration.
- UDP - if not installed or up-to-date, a menu will prompt you to install or update it upon selecting UDP support features. (See below)
### Fixed
- Reduced logging during initialization and purchasing
- Amazon - Removed KeyNotFoundException after purchase failure
- UDP - Removed one NullPointerException vulnerability
- GooglePlay developerPayload spurious JSON parsing exception in log
### Changed
- IAP Updater "Updater Settings..." button now reads "More Information..." to be more accurate
- UDP store implementation is still available, but must be installed in a separate module, available in either Asset Store or Package manager. The UDP module will need to be updated manually. (See above)
- Visibility of INativeStores is now public, mainly to support the new UDP package's needs
- Resource files - The Product Catalog, Android Target Billing Mode, and Receipt Obfuscator Tangle files will be moved out of the plugins folder.
### Important upgrade note
- **Upgrading from prior Unity IAP?** - Unity may generate a _bad Android build_ once, immediately after installing the upgrade to this version of Unity IAP. Unity will be misconfigured to incorrectly include multiple Andriod app store Java implementations. So **if a dialog appears asking permission to update e.g. the "SamsungApps.aar" file's metadata, during the first build after the upgrade to this version of Unity IAP,** then click Yes, cancel the build, and rebuild. This dialog undesirably defeats Unity IAP's system for including one Android app store (Window > Unity IAP > Android > Target {app store}), resulting in the inclusion of Android Java code for two app stores. Android app stores such as Google Play and Samsung Apps may block publication of an APK which is detected to include Java code for two app store. Restarting Unity after upgrading will also avoid this dialog.
## [1.23.5] - 2020-08-12
### Fixed
- GooglePlay - Fixed `IGooglePlayConfiguration.aggressivelyRecoverLostPurchases == false` (default) to reward players for currently in-flight purchases only, and not historical purchases, when the player cleans their device's TransactionLog, starts and cancels a purchase, and restarts the app.
## [1.23.4] - 2020-07-13
### Added
- Security - Supports receipts from GooglePlay which omit `packageName`. These as are seen from v1.23.2's purchase-recovery features.
- The purchasing receipt's `packageName` is omitted by a GooglePlay historical purchase query APIs used by v1.23.2. When the RSASSA-PKCS1-v1_5 signature is valid and the receipt's `packageName` is not included, the `appBundleId` / `googleBundleId` input into `UnityEngine.Purchasing.Security.CrossPlatformValidator` is ignored. To avoid replay attacks we encourage developers continue heuristically scrutinizing the returned `purchaseTime` and `productId` values found in decoded receipts.
### Removed
- Analytics - For publication to Kids Category on Google Play and Apple App Store, removed `SystemInfo.deviceUniqueIdentifier` collection and sharing with `ecommerce.iap.unity3d.com` server.
## [1.23.3] - 2020-06-28
### Changed
- GooglePlay - Default the failed-purchase recovery behavior to be disabled, which was introduced in `1.23.2`, to address players deleting their game's TransactionLog and receiving multiple products for a single purchase. Opt-in to the `1.23.2` behavior with `bool IGooglePlayConfiguration.aggressivelyRecoverLostPurchases = true;`, when also using a game server capable of validating each transaction and deduplicate based upon `Product.transactionID`, to reward players one time for a single purchase and support quickly recovering from interrupted-purchases.
- When a Google Play purchase is made the transaction can become out of synchronization with the Google Play server, appearing to be both failed on the game, and contradictorily successful on the Google Play store — an email message indicating purchase success may be received by the player. This desynchronization occurs when a purchase is interrupted while the native purchasing dialog is displayed to the player. Enable this feature to more aggressively detect these lost purchases.
- NOTICE: It is strongly recommended this feature be used with an off-device transaction de-duplication mechanism to avoid double-rewarding the player. An example is a game server which records Product.transactionID for each successful purchase and reports to the game whether a new transaction has already been processed for this player during a previous gameplay session. The scenario this occurs is when a player purchases a product, uninstalls and reinstalls their game — erasing Unity IAPs on-device TransactionLog de-duplication database — and then the player attempts and aborts a re-purchase by cancelling it. The purchase cancellation is one trigger for this recovery feature which may result in recovering and notifying a duplicate success to the game for only the initial purchase. The game could then deny rewarding the player for this detected duplicate purchase.
- KNOWN-ISSUE: CrossPlatformValidator may show these historically-restored transactions as invalid.
## [1.23.2] - 2020-06-17
### Added
- GooglePlay - Improves the chance of successfully purchasing a Consumable or NonConsumable when the _purchase flow_ is interrupted. Also addresses the dialog, "Your order is still being processed".
- Unity IAP will now detect this _purchasing_ failure. It will call the `IStoreListener.OnPurchaseFailed` API, initially. Then it will query Google Play for purchase success during the current app session until network is restored, and it will continue querying in the next app session, after a restart. It will finally call the `IStoreListener.ProcessPurchase` API if it finds a successful, unaccounted purchase.
- Addresses the case where (1) a consumable or nonconsumable purchase flow is started and (2) a network disruption occurs, or the app is sent to the background and the purchasing Activity is canceled, or the app is terminated.
- GooglePlay - Improves the chance of successfully repurchasing a Consumable whose successful transaction failed however to be _completed_ during the current app session.
- Unity IAP will now detect this _consumption_ failure. It will automatically retry completing the purchase until it succeeds. Note that `DuplicateTransaction` may still be reported while the retry is ongoing, until the user's product is repurchasable again. See below for new APIs to monitor the consumption flow.
- Addresses the case where (1) a Consumable purchase calls `IStoreListener.ProcessPurchase`, then (2) the transaction is completed by returning `ProcessPurchaseResult.Complete` from `IStoreListener.ProcessPurchase` or by directly calling `IStoreController.ConfirmPendingPurchase` [internally this always records the transaction identifier to the TransactionLog], and finally (3) an interruption (network or exit) aborts the transaction consumption. Only restarting the app or refunding the purchase would reliably resolve this case.
- GooglePlay - Adds an `"isOwned" : <boolean>` sub-entry to the `Product.receipt`'s `"Payload"` JSON entry in order to help developers understand this product's current ownership state.
- Contains `true` if the product is owned by the user. And please note that `true` may also indicate that Unity IAP is actively retrying consumption. Its boolean value will be `false` if the product is available for repurchase, or if we do not yet know Google Play's current status for this product. To clarify the receipt structure, `"isOwned"` is located in the Google Play-specific escaped-JSON sub-document. Sample `Product.receipt`, abbreviated: `{"Payload":"{\"json\": ..., \"signature\": ..., \"isOwned\":true}}"`. See the Google Play section of the [Unity IAP Receipt receipt documentation](https://docs.unity3d.com/Manual/UnityIAPPurchaseReceipts.html) for more on the receipt JSON structure.
- GooglePlay - Adds `boolean IGooglePlayStoreExtensions.IsOwned(Product)` API to conveniently extract the new ownership state, above, from the Google Play JSON receipt.
- Returns `true` if the product is still owned by the user. Returns `false` if the product is available for repurchase. Example:
```extensionProvider.GetExtension<IGooglePlayStoreExtensions>()```
```.IsOwned(storeController.products.WithID("100.gold.coins"));```.
- GooglePlay - Adds `void IGooglePlayStoreExtensions.SetLogLevel(int level)` API to reduce logging.
- `level` defaults to the legacy value of `0` and configures the Google Play Java store integration to emit debug, info, warning, and error logs. Setting `1` will restrict logging to emit only warnings and errors. Example: `extensionProvider.GetExtension<IGooglePlayStoreExtensions>().SetLogLevel(1)`.
- GooglePlay - After the purchasing dialog, "You already own this product" from Google Play is shown, the `IStoreListener.OnPurchaseFailed` API is calls with an error of `PurchaseFailureReason.DuplicateTransaction`.
- Unity IAP now treats "You already own this product" as a successful purchase, and _also_ calls `IStoreListener.ProcessPurchase`. Note: This amends the related behavior introduced in 1.23.1.
- Addresses the scenario where (1) a Consumable is purchased, and during purchasing (2) the Google Play store is interrupted by e.g. a network disruption. (3) Unity IAP correctly calls `IStoreListener.OnPurchaseFailed`, reporting the interruption as a purchase failure. (4) The user restores the network, attempts to re-purchase, Google Play shows "You already own this product", and Unity IAP reports the message as an error, calling `IStoreListener.OnPurchaseFailed` again. (4.1) Repeated re-purchase attempts fail, also potentially failing even after restarting the app.
## [1.23.1] - 2019-11-18
### Added
- UWP - Additional logging during initialization to diagnose developer portal misconfigurations. See https://docs.microsoft.com/en-us/windows/uwp/monetize/in-app-purchases-and-trials#how-to-use-product-ids-for-add-ons-in-your-code for a broad discussion of Windows.ApplicationModel.Store configuration.
### Fixed
- GooglePlay - Fix offline purchases inconsistently generating OnPurchaseFailed callbacks. Changes 1.22.0 "Fixed GooglePlay store consumable products already owned error due to network issues." - developers may choose to handle the `PurchaseFailureReason.DuplicateTransaction` for a ProductType.Consumable by rewarding the user with the product, and presuming that Unity IAP will automatically complete the transaction.
- Improved compatibility with Unity 5.3 and 5.4.
## [1.23.0] - 2019-10-16
### Added
- UDP - Upgrade to version 1.2.0: new installer to manage previously-installed versions in Project; new UI for UDP Settings window; injection of SDK version information into app manifest; premium game support; user permissions aligned between Unity editor and UDP console; improved security around the transmission of telemetry data (the data you see in your reporting dashboard) between the repacked games and the UDP backend.
### Changed
- UnityChannel / Xiaomi - Please use Unity Distributation Platform (UDP) for Xiaomi functionality. Removed UnityChannel.unitypackage from installer. Disabled and deprecated related APIs: `UnityEngine.Store`, `IUnityChannelExtensions`, `IUnityChannelConfiguration`.
- Tizen - NOTICE Tizen Store support will be removed in an upcoming release.
### Fixed
- Improved installer compatibility with Unity 2018.4 and 2019.x
- GooglePlay - Automatic product restoration across devices when logged into the same Google account.
- GooglePlay - SubscriptionInfo.getSubscriptionInfo() KeyNotFoundException when parsing receipts which omit expected fields.
- GooglePlay - IStoreListener.OnInitializeFailed / IStoreCallback.OnSetupFailed should return InitializationFailureReason.AppNotKnown error when user changes password off-device - user must login. Previously erroneously generated infinite error 6 codes when fetching purchase history after password change.
- OverflowException when initializing if device locale used the comma (“,”) character as decimal separator.
## [1.22.1] - 2019-08-13
### Fixed
- GooglePlay - SubscriptionInfo.getSubscriptionInfo() KeyNotFoundException when parsing receipts which omit expected fields.
- GooglePlay - IStoreListener.OnInitializeFailed / IStoreCallback.OnSetupFailed should return InitializationFailureReason.AppNotKnown error when user changes password off-device - user must login. Previously erroneously generated infinite error 6 codes when fetching purchase history after password change.
- OverflowException when initializing if device locale used the comma (“,”) character as decimal separator.
## [1.22.0] - 2019-03-18
### Added
- Added Unity Distribution Portal (UDP) module as an Android build target. Unity Distribution Portal streamlines your distribution process. UDP allows you to only build one version of your game, centralize the management of your marketing assets and metadata, and submit your content to multiple app stores, all in the same workflow. For more details, please refer to https://docs.unity3d.com/Packages/com.unity.purchasing.udp@1.0/manual/index.html.
- Added extension function for Apple store to expose products' sku details
- Added support for developer to include accountId in getBuyIntentExtraParams, this data helps Google analyze fraud attempts and prevent fraudulent transactions.
- Added GooglePlay store extension function to support restore purchases.
- Added GooglePlay store extension function to support consume(finish transaction) a purchase manually.
### Fixed
- Fixed UWP build errors.
- Fixed errors when initializing with two purchasing modules on WebGL & Windows Standalone.
- Fixed not "re-importing required assets" when switching build targets with IAP.
- Re-enabled Facebook IAP implementation for non-Gameroom Canvas apps.
- Fixed GooglePlay store consumable products already owned error due to network issues.
- Fixed wrong product id when cancel a subscription product purchase.
## [1.21.0] - 2018-08-14
- Limited release, for closed beta of UDP.
## [1.20.1] - 2018-10-5
### Added
- Added a callback function that allows developers to check the state of the upgrade/downgrade process of subscriptions on GooglePlay.
### Fixed
- Google Daydream - Correctly Displays IAP Prompt in 3d VR version instead of native 2D.
- Fixed issue where IAP catalog prevented deletion of Price under Google Configuration.
- Amazon Store - Fixed bug where Amazon store could not correctly parse currencies for certain countries.
- MacOS - Fixed bug that causes non-consumables to auto-restore on MacOS apps after re-install, instead of requiring the the Restore button to be clicked.
- Updated Android Response Code to return correct message whenever an activity is cancelled.
- Fixed Mono CIL linker error causing initialization failure in Unity 5.3
- Fixed inefficient Apple Receipt Parser that was slowing down when a large number of transactions were parsed on auto-restore.
## [1.20.0] - 2018-06-29
### Added
- API for developers to check SkuDetails for all GooglePlay store products, including those that have not been purchased.
- Error Code Support for Amazon.
- Support upgrade/downgrade Subscription Tiers for GooglePlayStore.
- Support Subscription status check (valid/invalid) for Amazon Store.
### Changed
- Location of Product Catalog from Assets/Plugins/UnityPurchasing/Resources folder to Assets/Resources.
- Amazon Receipt with enriched product details and receipt details.
### Fixed
- Issue where Unknown products (including non-consumables) were consumed during initialization.
- ArgumentException where currency was set to null string when purchase was made.
## [1.19.0] - 2018-04-17
### Added
- For GooglePlay store, `developerPayload` has been encoded to base64 string and formatted to a JSON string with two other information of the product. When extract `developerPayload` from the product receipt, firstly decode the json string and get the `developerPayload` field base64 string, secondly decode the base64 string to the original `developerPayload`.
- `SubscriptionManager` - This new class allows developer to query the purchased subscription product's information. (available for AppleStore and GooglePlay store)
- For GooglePlay store, this class can only be used on products purchased using IAP 1.19.0 SDK. Products purchased on previous SDKs do not have the fields in the "developerPayload" that are needed to parse the subscription information.
- If the "Payload" json string field in the product's json string receipt has a "skuDetails" filed, then this product can use `SubscriptionManager` to get its subscription information.
- Added the `StoreSpecificPurchaseErrorCode` enum. Currently contains values for all Apple and Google Play error codes that are returned directly from the store.
- Added the `ITransactionHistoryExtensions` extension. Developers can call `GetLastPurchaseFailureDescription()` and `GetLastStoreSpecificPurchaseErrorCode()` to get extended debugging/error information.
- Codeless IAP - Adds an `Automatically initialize UnityPurchasing` checkbox to the IAP Catalog. Checking this box will cause IAP to automatically initialize on game start using the products contained in the catalog.
## [1.18.0] - 2018-03-27
### Added
- Unity IAP E-Commerce - [Closed Beta] Supports new "managed store" functionality. Contact <iapsupport@unity3d.com> to learn more.
## [1.17.0] - 2018-02-21
### Added
- Unity IAP Promo - [Beta] Supports new Unity Ads feature to advertise IAPs inside advert placements.
### Changed
- Codeless IAP - Allow developers to use both IAPButton and IAPListener simultaneously. Broadcasts ProcessPurchase and OnPurchaseFailed to all productId-matching IAPButtons and to all IAPListeners. Allow multiple IAPListeners to be set using the AddListener method. Note: This change may increase the chance one rewards users multiple times for the same purchase.
## [1.16.0] - 2018-01-25
### Changed
- GooglePlay - Gradle builds will 'just work'. Internalized Proguard warning-suppression configurations. (Moved `proguard-user.txt.OPTIONAL.txt` into GooglePlay.aar, effectively.)
- Replaced Apple Application Loader product catalog exporter with Apple XML Delivery product catalog exporter, because submitting IAP via Application Loader is now deprecated
### Added
- Security - Adds the `IAppleExtensions.GetTransactionReceiptForProduct` method that returns the most recent iOS 6 style transaction receipt for a given product. This is used to validate Ask-to-buy purchases. [Preliminary documentation](https://docs.google.com/document/d/1YM0Nyy-kTEM2YGpOxVj20kUBtyyNKndaXWslV0RF_V8) is available.
- Apple - Adds an optional callback, `IAppleConfiguration.SetApplePromotionalPurchaseInterceptorCallback`, that intercepts Apple Promotional purchases in iOS and tvOS. Developers who implement the callback should call `IAppleExtensions.ContinuePromotionalPurchases` to resume the purchase flow. [Preliminary documentation](https://docs.google.com/document/d/1wQDRYoQnTYoDWw4G64V-V6EZbczpkq0moRf27GKeUuY) is available.
- Xiaomi - Add support for retrieving developer payload. [Preliminary documentation](https://docs.google.com/document/d/1V0oCuCbb7ritK8BTAMQjgMmDTrsascR2MDoUPXPAUnw) is available.
### Fixed
- Removed Debug log from UnityIAP StandardPurchasingModule
- Xiaomi - Remove unnecessary Android WRITE_EXTERNAL_STORAGE permission.
## [1.15.0] - 2017-11-13
### Added
- IAP Updates - GUI to control plugin updates in Window > Unity IAP > IAP Updates menu. Supports viewing changelog, skipping this update, disabling automatic updates, and showing current version number. Writes preferences to Assets/Plugins/UnityPurchasing/Resources/IAPUpdaterPreferences.json.
# Changed
- IAP Demo - Improved UI and cleaned up code in the IAP Demo sample scene
- Version Log - Changed logging of Unity IAP version (e.g. "1.15.0") to be only at runtime and not while in the Editor
### Fixed
- Facebook - Correctly handles situations where the number of available products exceeds the Facebook server response page size
- Updater will no longer prompt for updates when Unity is running in batch mode
- Gradle - Include and relocate sample Proguard configuration file to Assets/Plugins/UnityPurchasing/Android/proguard-user.txt.OPTIONAL.txt; was missing from 1.13.2
- Security - Upgrades project to autogenerate UnityChannelTangle class if missing when GooglePlayTangle obfuscated secret receipt validation support class is present.
- UnityIAPUpdater - Fix a FormatException sensitivity for DateTime parsing
- Xiaomi Catalog - Fix a NullReferenceException seen when exporting an empty catalog
- Xiaomi Receipt Validation - Fix missing UnityChannelTangle class for Unity IAP projects which used receipt validation
## [1.14.1] - 2017-10-02
### Fixed
- Apple Application Loader product catalog exporter now correctly exports tab-separated values for catalogs containing more than one product
- JSONSerializer - Unity 5.3 build-time regression - missing "type" field on ProductDescription. Field is available in 5.4 and higher.
## [1.14.0] - 2017-09-18
### Added
- Codeless IAP - Added an `IAPListener` Component to extend Codeless IAP functionality. Normally with Codeless IAP, purchase events are dispatched to an `IAPButton` UI Component that is associated with a particular product. The `IAPListener` does not show any UI. It will receive purchase events that do not correspond to any active `IAPButton`.
- The active `IAPListener` is a fallback—it will receive any successful or failed purchase events (calls to `ProcessPurchase` or `OnPurchaseFailed`) that are _not_ handled by an active Codeless `IAPButton` Component.
- When using the `IAPListener`, you should create it early in the lifecycle of your app, and not destroy it. By default, it will set its `GameObject` to not be destroyed when a new scene is loaded, by calling `DontDestroyOnLoad`. This behavior can be changed by setting the `dontDestroyOnLoad` field in the Inspector.
- If you use an `IAPListener`, it should be ready to handle purchase events at any time, for any product. Promo codes, interrupted purchases, and slow store behavior are only a few of the reasons why you might receive a purchase event when you are not showing a corresponding `IAPButton` to handle the event.
- Example use: If a purchase is completed successfully with the platform's app store but the user quits the app before the purchase is processed by Unity, Unity IAP will call `ProcessPurchase` the next time it is initialized—typically the next time the app is run. If your app creates an `IAPListener`, the `IAPListener` will be available to receive this `ProcessPurchase` callback, even if you are not yet ready to create and show an `IAPButton` in your UI.
- Xiaomi - IAP Catalog emitted at build-time to APK when Xiaomi Mi Game Pay is the targeted Android store.
- Xiaomi - Support multiple simultaneous calls to IUnityChannelExtensions.ConfirmPurchase and IUnityChannelExtensions.ValidateReceipt.
### Changed
- CloudMoolah - Upgraded to 2017-07-31 SDK. Compatible with the [2017 Cloud Moolah developer portal](https://dev.cloudmoolah.com/). Add `IMoolahConfiguration.notificationURL`. Removed deprecated `IMoolahExtensions.Login`, `IMoolahExtensions.FastRegister`, `IMoolahExtensions.RequestPayOut`. [Preliminary updated documentation](https://docs.google.com/document/d/1g-wI2gOc208tQCEPOxOrC0rYgZA0_S6qDUGOYyhmmYw) is available.
- Receipt Validation Obfuscator - Improved UI for collecting Google Play License Keys for receipt validation.
- Xiaomi - Removed deprecated MiProductCatalog.prop file generation in favor of MiGameProductCatalog.prop for Xiaomi Mi Game Pay Android targets.
- IAPDemo - Guard PurchaseFailureReason.DuplicateTransaction enum usage to be on Unity 5.6 and higher.
- Internal - Namespace more root-level incidental classes under UnityEngine.Purchasing or UnityEditor.Purchasing as appropriate.
### Fixed
- Invoke the onPurchaseFailed event on a Codeless IAP button if the button is clicked but the store was not initialized correctly
## [1.13.3] - 2017-09-14
### Fixed
- Fixed a bug that caused some iOS 11 promoted in-app purchase attempts to fail when the app was not already running in the background
## [1.13.2] - 2017-09-07
### Added
- Android Gradle - Optional Proguard configuration file to support Gradle release builds on Unity 2017.1+: "Assets/Plugins/Android/proguard-user.txt.OPTIONAL.txt". See contents of file for more detail.
- Installer - Compatibility with Unity 2017.2's Build Settings > Android > Xiaomi Mi Game Center SDK package add button, avoiding duplicate class definitions if previously added to `Packages/manifest.json` (new Package Manager).
### Fixed
- Windows (UWP) Store - Updates error handling for failed purchases to correctly call `OnPurchaseFailed()` with an informative `PurchaseFailureReason`
- Fixed prices that were incorrectly parsed when the device's culture specified a number format using a comma for the decimal separator
- XiaomiMiPay - Limit product identifier length to 40 characters in IAP Catalog, matching store requirements.
- Receipt Validation - Address aggressive class stripping NullReferenceException when validating receipt with preservation in Assets/Plugins/UnityPurchasing/scripts/link.xml.
## [1.13.1] - 2017-08-18
### Fixed
- Android platforms - Fix Unity crash by stack-overflow when using the `UnityPurchasingEditor.TargetAndroidStore(AndroidStore store)` method or the Window > Unity IAP > Android > Xiaomi Mi Game Pay targeting menu.
## [1.13.0] - 2017-07-31
### Added
- iOS and tvOS - Added support for purchases initiated from the App Store using the new API in iOS 11 and tvOS 11. For more information about this feature, watch the ["What's New in StoreKit" video from WWDC 2017](https://developer.apple.com/videos/play/wwdc2017/303/). If you intend to support this feature in your app, it is important that you initialize Unity Purchasing and be prepared to handle purchases as soon as possible when your app is launched.
- Apple platforms - The IAP Catalog tool will now export translations when exporting to the Apple Application Loader format.
- Apple platforms - Add support for controlling promoted items in the App Store through IAppleExtensions. This feature is available on iOS and tvOS 11. Set the order of promoted items in the App Store with IAppleExtensions.SetStorePromotionOrder, or control visiblility with IAppleExtensions.SetStorePromotionVisibility.
```csharp
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
// Set the order of the promoted items
var appleExtensions = extensions.GetExtension<IAppleExtensions>();
appleExtensions.SetStorePromotionOrder(new List<Product>{
controller.products.WithID("sword"),
controller.products.WithID("subscription")
});
}
```
```csharp
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
// Set the visibility of promoted items
var appleExtensions = extensions.GetExtension<IAppleExtensions>();
appleExtensions.SetStorePromotionVisibility(controller.products.WithID("subscription"), AppleStorePromotionVisibility.Hide);
appleExtensions.SetStorePromotionVisibility(controller.products.WithID("100.gold.coins"), AppleStorePromotionVisibility.Default);
}
```
### Changed
- AndroidStore enum - Obsoleted by superset AppStore enum. Cleans up logging mentioning Android on non-Android platforms.
- Codeless IAP - IAP Button notifies just one purchase button for purchase failure, logging additional detail.
### Fixed
- Apple platforms - Catch NullReferenceException thrown during initialization when the app receipt cannot be correctly parsed.
- IAP Catalog - Fix GUI slowdown when typing details for large number of products on Windows.
- Fix internal MiniJSON namespace exposure, regression introduced in 1.11.2.
## [1.12.0] - 2017-07-25
### Added
- XiaomiMiPay - Add Xiaomi Mi Game Pay app store purchasing for Android devices in China. Add the "Unity Channel" support library and service. Unity Channel helps non-China developers access the Unity-supported Chinese app store market by featuring app store user login and payment management. Use Unity Channel directly for login to Xiaomi. Unity IAP internally uses Unity Channel for Xiaomi payment. [Preliminary documentation](https://docs.google.com/document/d/1VjKatN5ZAn6xZ1KT_PIvgylmAKcXvKvf4jgJqi3OuuY) is available. See also [Xiaomi's portal](https://unity.mi.com/) and [Unity's partner guide](https://unity3d.com/partners/xiaomi/guide).
### Fixed
- FacebookStore - Fix login and initialization corner-case abnormally calling RetrieveProducts internally
- Tizen Store - Fix purchasing regression introduced after 1.11.1
- Mac App Store - Fixes "libmono.0.dylib not found" errors at launch if built via Unity 2017.1. See also Known Issues, below.
### Known Issues
- Mac App Store - Incompatible with Unity 2017.1.0f3: exception will be thrown during purchasing. Fixed in Unity 2017.1.0p1.
## [1.11.4] - 2017-06-21
### Fixed
- Apple platforms - Fix a blocking bug when building from Unity 5.3.
## [1.11.3] - 2017-06-20
### Fixed
- Amazon - Purchase attempts for owned non-consumable products are now treated as successful purchases.
## [1.11.2] - 2017-05-30
### Added
- Apple platforms - Parse the app receipt when retrieving product information and attempt to set receipt fields on Product. With this change the hasReceipt field on Apple platforms will work more like it does on non-Apple platforms.
### Fixed
- FacebookStore - Better error handling for cases where store configuration changes after purchases have already been made.
- General - Better momentary memory performance for local receipt validation and other JSON parsing situations.
- Editor menus - Targeted Android store menu checkmark are set and valid more often.
- Installer - Fix error seen during install, `ReflectionTypeLoadException[...]UnityEditor.Purchasing.UnityIAPInstaller.<k_Purchasing>`.
## [1.11.1] - 2017-05-23
### Fixed
- GooglePlay - Fix regression seen during purchasing where GooglePlay Activity forces screen orientation to portrait and turns background black. Restores neutral orientation and transparent background behavior.
## [1.11.0] - 2017-05-01
### Added
- FacebookStore - Facebook Gameroom Payments Lite support. Available on Unity 5.6+ when building for Facebook Platform on Gameroom (Windows) and WebGL. Preliminary documentation is available [here](https://docs.google.com/document/d/1FaYwKvdnMHxkh47YVuXx9dMbc6ZtLX53mtgyAIn6WfU/)
- Apple platforms - Added experimental support for setting "simulatesAskToBuyInSandbox". Please let us know how this impacts ask-to-buy testability for you.
```csharp
extensions.GetExtension<IAppleExtensions>().simulateAskToBuy = true;
```
- Apple platforms - Added support for setting "applicationUsername" field which will be added to every payment request to help the store detect fraud.
```csharp
// Set the applicationUsername to help Apple detect fraud
extensions.GetExtension<IAppleExtensions>().SetApplicationUsername(hashedUsername);
```
### Requirement
- GooglePlay - "Android SDK API Level 24 (7.0)" (or higher) must now be installed. To upgrade, either perform the one-time step of setting the project's "Android Player Settings > Other Settings > Minimum API Level" to 24, building an APK, then resetting to the project's previous value. Or, run the `android` Android SDK Manager tool manually and install "Android 7.0 (API 24)". Addresses build error messages: "Unable to merge android manifests." and "Main manifest has \<uses-sdk android:targetSdkVersion='23'> but library uses targetSdkVersion='24'". Note the Minimum API Level support is unchanged; merely the installation of API 24 SDK is now required for Daydream VR.
### Fixed
- GooglePlay Daydream VR - Uses decoration-free Activity for purchasing
- GooglePlay - Avoids sporadic price serialization exception
- Apple App Stores - Improve handling of the situation where an attempt to finish a transaction fails (if the user is signed out of the store and cancels the sign in dialog, for example). The Apple store implementation will now remember that the transaction should be finished, and attempt to call finishTransaction again if the transaction is retrieved from the queue again. When this happens, the store will call OnPurchaseFailed with the reason "DuplicateTransaction"—this prevents a situation where a call to InitiatePurchase could result in no call to ProcessPurchase or OnPurchaseFailed.
- Amazon - Fix for a crash when loading product metadata for subscription parent products
## [1.10.1] - 2017-03-29
### Fixed
- GooglePlay - Suspending and resuming from app-icon while purchase dialog displayed no longer generates both OnPurchaseFailed then ProcessPurchase messages, only whichever callback is correct.
- Remove cloud JSON exporter that was erroneously showing in the IAP Catalog export list
- Fixed a bug when parsing localized prices when the device's localization does not match the number format rules for the currency
- Resolved DLL name conflict by renaming Assets/Plugins/UnityPurchasing/Bin/Common.dll to Purchasing.Common.dll
- Installer - Suppressed multiple redundant dialogs
## [1.10.0] - 2017-01-23
### Added
- Samsung Galaxy Apps - In-App Purchase SDK v4. Simplifies flow for first-time payment users. See [Samsung Developer IAP Documentation](http://developer.samsung.com/iap) for more.
- Tizen Store - Add support for subscriptions
- StandardPurchasingModule - Add `bool useFakeStoreAlways` property to override native stores with the local debug FakeStore for rapid prototyping. Will not connect to any App Store when enabled.
```csharp
// Enable the FakeStore for all IAP activity
var module = StandardPurchasingModule.Instance();
module.useFakeStoreAlways = true;
```
* Editor Updater - Notify the developer when updates to Unity IAP are available with an actionable dialog. Periodically check the Asset Store version and prompt with an upgrade dialog capable of downloading the latest plugin.
* Editor Installer - Simplify integration of Unity IAP into a Project, avoiding unexpected breakage of the scripting build environment after package installation. Detect and warn if Unity IAP Core Service is "Off" during installation.
### Removed
- Samsung Galaxy Apps - remove In-App Purchase SDK v3 and replaced with v4, above.
### Fixed
- GooglePlay - Fix a problem that occurred when suspending the application during a successful transaction. Previously a consumable product could get stuck in a state where it could not be purchased again until the Google Play cache was cleared.
## [1.9.3] - 2017-01-03
### Added
- Windows Store - support for UWP apps running while logged-out of Windows Store. Now fetches app's product metadata if logged out, and requests user sign in to make purchase or to fetch user's purchase history.
- Editor - diagnostic log at build-time when IAP Service disabled: "Unity IAP plugin is installed, but Unity IAP is not enabled. Please enable Unity IAP in the Services window." Fewer redundant errors.
### Fixed
- Editor - checkmarks refresh for Targeted Android Store after Editor Play/Stop
- Editor - hides spurious Component MenuItems
- Linux Editor - BillingMode.json path case-sensitivity
- IAP Catalog - clearer text for Export button: "App Store Export"
## [1.9.2] - 2016-11-29
### Fixed
- GooglePlay - addresses warning about usage of WebViewClient.onReceivedSslError if CloudMoolah.aar is included
- CloudMoolah - simplify Login API and rename LoginError enum to LoginResultState
- Android - remove READ_PHONE_STATE permission from AndroidManifest.xml simplifying logic around CloudMoolah Register and Login by removing automatic SystemInfo.deviceUniqueIdentifier calls. Developers may now choose to include this permission using this API to collect a user identifer, or provide an alternate long-lived user identifier, in a CloudMoolah supporting game for the Register and Login API password parameter.
## [1.9.1] - 2016-11-17
### Added
- [Beta] Codeless IAP — UI fields show title, price, and description downloaded from the platform store
- IAP Catalog now includes a store ID field for the CloudMoolah store
### Fixed
- IAPButton component now updates product ID list as the IAP Catalog is being edited
- Fixed a problem with opening a project containing the Unity IAP plugin while IAP was disabled in the Services window
- IAPButton inspector field for Product ID now works correctly with Undo
- Set GooglePlay as default Android store AAR fileset. Excludes other store's assets (Java, resource XML, localization), saving ~196kb in default APK. Creates Assets/Plugins/UnityPurchasing/Resources/BillingMode.json in Project. Configure manually with Window > Unity IAP > Android menu, or UnityPurchasingEditor.TargetAndroidStore(AndroidStore).
- CloudMoolah - update Window > Unity IAP > Android menu checkmarks when CloudMoolah selected
## [1.9.0] - 2016-10-31
### Added
- CloudMoolah support. CloudMoolah website [here](http://www.cloudmoolah.com). Preliminary store guide available [here](https://docs.google.com/document/d/1T9CEZe6eNCwgWkq7lLwrEw7rpSbu3_EjcUVgJJL6xA0/edit). Preliminary configuration document available [here](https://docs.google.com/document/d/1dpc3zqsyROeFUVBy9W9pc0sskCPyfhcRnsGxtyITmyQ/edit).
- [Beta] Codeless IAP tools. Implement IAP by adding IAP Buttons to your project (Window > Unity IAP > Create IAP Button) and configure your catalog of IAP products without writing a line of code (Window > Unity IAP > IAP Catalog). Preliminary documentation is available [here](https://docs.google.com/document/d/1597oxEI1UkZ1164j1lR7s-2YIrJyidbrfNwTfSI1Ksc/edit).
- [Beta] Google Play - Support for Daydream VR. Requires Unity 5.4+ "GVR" Technical Preview, enabling VR, and including the Daydream SDK. Additional details [here](https://unity3d.com/partners/google/daydream).
- Samsung Galaxy Store - Added support for receiving auto-recurring subscriptions
- Highlights chosen Android store in menu Window > Unity IAP > Android
### Fixed
- Remove the menu item to select Android store at runtime
- Fix an exception that occurred when parsing prices while culture was set to use commas as a decimal separator
## [1.8.3] - 2016-10-13
### Fixed
- iOS crash when calling PurchasingManager.ConfirmPendingPurchase with a product that does not have a transaction ID
- Ensure tvOS build uses correct stub DLL
- Support transaction receipt logging for all store platforms. Requires corresponding Unity Engine: currently unreleased Unity 5.3/5.4 patch, or Unity 5.5.0b7+.
## [1.8.2] - 2016-09-23
### Fixed
- Tizen Store - Product list not delivered to new app or new user
## [1.8.1] - 2016-08-30
### Fixed
- Windows Store - Windows App Compatibility Kit Supported API failure with exposure of Tizen API.
- Tizen Store - Added sample products and GroupId to `IAPDemo.cs`
## [1.8.0] - 2016-08-23
### Added
- Tizen Store support. Preliminary documentation is available [here](https://docs.google.com/document/d/1A2TidgeV4lY16IcjdU7lX4EIvx6NNfONaph12iT8KyY).
### Fixed
- Google Play - Promo code redemptions not being detected whilst the App is running.
- Google Play - Guard against spurious SecurityException (additional details [here](https://github.com/googlesamples/android-play-billing/issues/26).)
## [1.7.0] - 2016-08-07
### Added
- Samsung Galaxy store support. Preliminary documentation is available [here](https://docs.google.com/document/d/1kUq-AHKyJftUA68xr44mrp7gs_MNxNiQ693s0b7qDdM).
- Google Play - failed purchases - the [Google Play server response code](https://developer.android.com/google/play/billing/billing_reference.html#billing-codes) is now supplied as the [PurchaseFailedEventArgs.message](https://docs.unity3d.com/ScriptReference/Purchasing.PurchaseFailedEventArgs-message.html) property for failed purchases.
- Android - it is now possible to choose the store implementation to use at runtime.
- Make a build containing all store implementations by choosing Window > Unity IAP > Android > "Select store at runtime"
```csharp
// Pass the desired store to the module, e.g. Amazon Apps.
var module = StandardPurchasingModule.Instance(AndroidStore.AmazonAppStore);
```
### Fixed
- Google Play - PurchaseFailureReason.ItemUnavailable and PurchaseFailureReason.BillingUnavailable being reported as 'Unknown' errors.
## [1.6.1] - 2016-07-18
### Fixed
- Google Play - fixed non fatal 'IllegalArgumentException: Receiver not registered' warning appearing in crashlogs.
## [1.6.0] - 2016-7-7
### Added
- Support for redeeming [Google Play promo codes](https://developer.android.com/google/play/billing/billing_promotions.html) for IAPs.
- IAndroidStoreSelection extended configuration for accessing the currently selected Android store.
```csharp
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
Debug.Log(builder.Configure<IAndroidStoreSelection>().androidStore);
```
### Fixed
- Apple Stores - ProcessPurchase not being called on initialize for existing transactions if another storekit transaction observer is added elsewhere in the App. This addresses a number of issues when using third party SDKs, including Facebook's.
- Google Play - sandbox purchases. In Google's sandbox Unity IAP now uses Google's purchase token instead of Order ID to represent transaction IDs.
- iOS not initializing when IAP purchase restrictions are active. IAP will now initialise if restrictions are active, enabling browsing of IAP metadata, although purchases will fail until restrictions are disabled.
- Instantiating multiple ConfigurationBuilders causing purchasing to break on Google Play & iOS.
## [1.5.0] - 2016-5-10
### Added
- Amazon stores - Added NotifyUnableToFulfillUnavailableProduct(string transactionID) to IAmazonExtensions.
You should use this method if your App cannot fulfill an Amazon purchase and you need to call [notifyFulfillment](https://developer.amazon.com/public/apis/earn/in-app-purchasing/docs-v2/implementing-iap-2.0) method with a FulfillmentResult of UNAVAILABLE.
### Fixed
- Google Play - purchase failure event not firing if the Google Play purchase dialog was destroyed when backgrounding and relaunching the App.
### Changed
- Updated to V2.0.61 of Amazon's IAP API.
- Apple stores, Google Play - removed logging of products details on startup.
## [1.4.1] - 2016-4-12
### Fixed
- Amazon stores - "App failed to call Purchasing Fullfillment" error caused by Unity IAP misuse of Amazon's notifyFulfillment mechanism.
### Added
- Editor API call for toggling between Android billing platforms in build scripts; UnityPurchasingEditor.TargetAndroidStore(AndroidStore). See below for usage.
```csharp
using UnityEngine;
using UnityEngine.Purchasing;
using UnityEditor;
// A sample Editor script.
public class MyEditorScript {
void AnEditorMethod() {
// Set the store to Google Play.
UnityPurchasingEditor.TargetAndroidStore(AndroidStore.GooglePlay);
}
}
```
## [1.4.0] - 2016-4-5
### Added
- Amazon Apps & Amazon underground support. Preliminary documentation is available [here](https://docs.google.com/document/d/1QxHRo7DdjwNIUAm0Gb4J3EW3k1vODJ8dGdZZfJwetYk/edit?ts=56f97483).
## [1.3.2] - 2016-4-4
### Fixed
- Apple stores; AppleReceiptValidator not parsing AppleInAppPurchaseReceipt subscriptionExpirationDate and cancellationDate fields.
## [1.3.1] - 2016-3-10
### Changed
- Google Play - Google's auto generated IInAppBillingService types have been moved to a separate Android archive; GoogleAIDL. If other plugins define IInAppBillingService, generating duplicate class errors when building for Android, you can delete this AAR to resolve them.
## [1.3.0] - 2016-3-3
### Added
- Receipt validation & parsing library for Google Play and Apple stores. Preliminary documentation can be found [here](https://docs.google.com/document/d/1dJzeoGPeUIUetvFCulsvRz1TwRNOcJzwTDVf23gk8Rg/edit#)
## [1.2.4] - 2016-2-26
### Fixed
- Demo scene error when running on IL2CPP.
- Fixed Use of app_name in Google Play Android manifest causing build errors when exported to Android studio.
## [1.2.3] - 2016-2-11
### Added
- iOS, Mac & Google Play - support for fetching products incrementally with the IStoreController.FetchAdditionalProducts() method that is new to Unity 5.4. Note you will need to be running Unity 5.4 to use this functionality.
## [1.2.2] - 2016-2-9
### Fixed
- Setting IMicrosoftConfiguration.useMockBillingSystem not correctly toggling the local Microsoft IAP simulator.
- Deprecated WinRT.Name and WindowsPhone8.Name; WindowsStore.Name should be used instead for Universal Windows Platform 8.1/10 builds.
- Unnecessary icons and string resources removed from Android archives.
## [1.2.1] - 2016-1-26
### Fixed
- IAP Demo scene not registering its deferred purchase listener.
## [1.2.0] - 2016-1-15
### Added
- tvOS Support. tvOS behaves identically to the iOS and Mac App Stores and shares IAPs with iOS; any IAPs defined for an iOS App will also work when the app is deployed on tvOS.
- Apple Platforms - a method to check whether payment restrictions are in place; [SKPaymentQueue canMakePayments].
```csharp
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
// Detect if IAPs are enabled in device settings on Apple platforms (iOS, Mac App Store & tvOS).
// On all other platforms this will always return 'true'.
bool canMakePayments = builder.Configure<IAppleConfiguration> ().canMakePayments;
```
### Changed
- Price of fake Editor IAPs from $123.45 to $0.01.
## [1.1.1] - 2016-1-7
### Fixed
- iOS & Mac App Store - Clean up global namespace avoiding symbol conflicts (e.g `Log`)
- Google Play - Activity lingering on the stack when attempting to purchase an already owned non-consumable (Application appeared frozen until back was pressed).
- 'New Game Object' being created by IAP; now hidden in hierarchy and inspector views.
## [1.1.0] - 2015-12-4
### Fixed
- Mac App Store - Base64 receipt payload containing newlines.
- Hiding of internal store implementation classes not necessary for public use.
### Added
- IAppleConfiguration featuring an 'appReceipt' string property for reading the App Receipt from the device, if any;
```csharp
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
// On iOS & Mac App Store, receipt will be a Base64 encoded App Receipt, or null
// if no receipt is present on the device.
// On other platforms, receipt will be a dummy placeholder string.
string receipt = builder.Configure<IAppleConfiguration> ().appReceipt;
```
## [1.0.2] - 2015-11-6
### Added
- Demo scene uses new GUI (UnityEngine.UI).
- Fake IAP confirmation dialog when running in the Editor to allow you to test failed purchases and initialization failures.
## [1.0.1] - 2015-10-21
### Fixed
- Google Play: Application IStoreListener methods executing on non scripting thread.
- Apple Stores: NullReferenceException when a user owns a product that was not requested by the Application during initialization.
- Tizen, WebGL, Samsung TV: compilation errors when building a project that uses Unity IAP.
## [1.0.0] - 2015-10-01
### Added
- Google Play
- Apple App Store
- Mac App Store
- Windows Store (Universal)

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9be20068bd14d40f2a689bba2dbd89af
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

464
CHANGELOG.md Normal file
View File

@ -0,0 +1,464 @@
# Changelog
## [4.9.4] - 2023-08-01
### Changed
- Google Play - Billing Library updated to 5.2.1 (was previously 5.1.0). No new feature support was added, this is simply to add compatibility with Android 14.
- Apple - Using the CrossPlatformValidation (or AppleValidator), receipts will now be validated if their certificate chain is encoded in SHA-256 instead of SHA-1. Old receipts encoded in SHA-1 will still be validated. See [Apple Technical Note](https://developer.apple.com/documentation/technotes/tn3138-handling-app-store-receipt-signing-certificate-changes).
## [4.9.3] - 2023-05-17
### Changed
- Analytics events are now sent when a purchase has been confirmed (`ConfirmPendingTransaction` or `ProcessPurchase` returning `PurchaseProcessingResult.Complete`). This will improve the accuracy of revenue tracking by no longer considering pending purchases.
- Updated `Product.transactionID`, `Product.hasReceipt` and `Product.receipt` documentation to include pending transaction use cases.
- Updated samples to use `IDetailedStoreListener` and its improved `OnPurchaseFailed` callback.
- Added a new `RefreshAppReceipt(Action<string> successCallback, Action<string> errorCallback)` callback containing more information when the errorCallback is invoked in `IAppleExtensions : IStoreListener`.
### Fixed
- `OnPurchaseFailed` will no longer log an error when there's only new IAP Buttons with no IAP Listener.
- Apple - Improved the accuracy of `Product.appleProductIsRestored` when using the restore transaction button. These will now correctly be flagged as true.
- Codeless - `OnPurchaseFailed(Product, PurchaseFailureDescription)` callback was not invoked in `IAP Listener`
## [4.8.0] - 2023-04-12
### Added
- Added new [IAP Button](https://docs.unity3d.com/Packages/com.unity.purchasing@4.8/manual/CodelessIAPButton.html) in the editor. This new button allows for more UI customization. The new button will no longer update the button fields by default.
- Added a new event `OnProductFetched(Product)` to the [IAP Listener](https://docs.unity3d.com/Packages/com.unity.purchasing@4.8/manual/IAPListener.html) and to the [IAP Button](https://docs.unity3d.com/Packages/com.unity.purchasing@4.8/manual/CodelessIAPButton.html) it is called after fetching products from the app stores.
- Added a new `OnPurchaseFailed(Product, PurchaseFailureDescription)` callback containing more information on the failed purchase in `IDetailedStoreListener : IStoreListener`
### Changed
- [IAP Button](https://docs.unity3d.com/Packages/com.unity.purchasing@4.8/manual/IAPButton.html) is now obsolete.
- Google Play - Billing Library update from version 4.0.0 to 5.1.0 [Google Release Notes](https://developer.android.com/google/play/billing/release-notes).
New Google Billing features are not supported yet, they will be included in a future major update.
- Removed the nullable operator `?` from public interfaces and classes.
- `IStoreListener.OnPurchaseFailed` is now obsolete.
- When present, Analytics 4.4.0 and above will now use the new interface `IAnalyticsStandardEventComponent` from Services Cores 1.8.1.
- Upgraded `com.unity.services.core` from 1.5.2 to 1.8.1.
### Fixed
- Samples - Some samples had IAP 4.6.0 `IStoreListener` changes not completely implemented causing compilation errors.
## [4.7.0] - 2023-02-09
### Added
- Added `storeSpecificErrorCode` to `PurchaseFailureDescription.message` when available.
### Fixed
- Unity IAP will consider the call to `UnityPurchasing.initialize` completed before invoking the correct callback `IStoreListener.OnInitialized` or `IStoreListener.OnInitializeFailed`. This prevents these callbacks from being invoked more than once per initialization.
- GooglePlay - Fixed `No such proxy method` exception in our representation of `BillingClientStateListener.onBillingServiceDisconnected()` introduced by Unity IAP 4.6.0
- Apple - Fixed a `NullReferenceException` happening when the receipt isn't found.
### Changed
- Removed `com.unity.services.analytics` from the IAP SDK dependencies
## [4.6.0] - 2023-02-02
### Added
- Added a new restore transaction callback `RestoreTransactions(Action<bool, string> callback)` to obtain the error string when RestoreTransactions is not successful (`IAppleExtensions` and `IGooglePlayStoreExtensions`).
- Added a new initialize failed callback `IStoreListener.OnInitializeFailed(InitializationFailureReason, string)` to obtain the error string when OnInitializeFailed is invoked.
- Added a new setup failed callback `IStoreCallback.OnSetupFailed(InitializationFailureReason, string)` to obtain the error string when OnSetupFailed is invoked.
- Added a new FetchAdditionalProducts. The failCallback contains an error string. `IStoreController.FetchAdditionalProducts(HashSet<ProductDefinition>, Action, Action<InitializationFailureReason, string>)`
- Apple - `Product.appleOriginalTransactionId` : Returns the original transaction ID. This field is only available when the purchase was made in the active session.
- Apple - `Product.appleProductIsRestored` : Indicates whether the product has been restored.
- GooglePlay - `IGooglePlayConfiguration.SetFetchPurchasesExcludeDeferred(bool exclude)` has been added to revert to the previous behaviour. This is not recommended and should only be used if `Deferred` purchases are handled in your `IStoreListener.ProcessPurchase`.
- GooglePlay - `IGooglePlayStoreExtensions.GetPurchaseState(Product product)` has been added to obtain the `GooglePurchaseState` of a product.
- GooglePlay - Added missing values to `GoogleBillingResponseCode` in order to output it in `PurchaseFailureDescription`'s message when available.
- Codeless - Added to the [IAP Button](https://docs.unity3d.com/Packages/com.unity.purchasing@4.6/manual/IAPButton.html) the option to add a script for the On Transactions Restored: `void OnTransactionsRestored(bool success, string? error)`
### Changed
- Upgraded `com.unity.services.core` from 1.3.1 to 1.5.2
- Upgraded `com.unity.services.analytics` from 4.0.1 to 4.2.0
- The old OnInitializeFailed `OnInitializeFailed(InitializationFailureReason error)` was marked `Obsolete`
- The old OnSetupFailed `OnSetupFailed(InitializationFailureReason reason)` was marked `Obsolete`
- The old FetchAdditionalProducts `FetchAdditionalProducts(HashSet<ProductDefinition> additionalProducts, Action successCallback, Action<InitializationFailureReason> failCallback)` was marked `Obsolete`
- The old restore transaction callback `RestoreTransactions(Action<bool> callback)` was marked `Obsolete` (`IAppleExtensions` and `IGooglePlayStoreExtensions`).
- Apple - Transactions received from Apple that are invalid (where the product is not entitled) will no longer output the `Finishing transaction` log. This only affects transactions that never reached the `ProcessPurchase`.
- GooglePlay - The enum `GooglePurchaseState` now recognizes `4` as `Deferred`.
### Fixed
- Analytics - A ServicesInitializationException introduced in Analytics 4.3.0 is now handled properly.
- Analytics - Fixed an issue where transactions events were invalidated when there was no localization data for a product.
- GooglePlay - Fixed a `NullReferenceException` when querying sku details while the BillingClient is not ready.
- GooglePlay - Fixed [Application Not Responding (ANR)](https://developer.android.com/topic/performance/vitals/anr) when foregrounding the application while disconnected from the Google Play Store.
- GooglePlay - Limited the occurence of `PurchasingUnavailable` errors when retrieving products while in a disconnected state to once per connection.
- GooglePlay - `Deferred` purchases are, by default, no longer sent to `IStoreListener.ProcessPurchase` when fetching purchases. This avoids the possibility of granting products that were not paid for. These purchases will only be processed once they become `Purchased`. This can be reverted with `IGooglePlayConfiguration.SetFetchPurchasesExcludeDeferred(bool exclude)` to not exclude them, but `Deferred` purchases will need to be handled in `IStoreListener.ProcessPurchase`.
- Unity IAP will consider the call to `UnityPurchasing.initialize` completed before invoking the correct callback `IStoreListener.OnInitialized` or `IStoreListener.OnInitializeFailed`. This prevents these callbacks from being invoked more than once per initialization.
## [4.5.2] - 2022-10-28
### Fixed
- Removed unused exception variable causing a compiler warning CS0168.
- Telemetry - Calls to telemetry reporting were occasionally tripping a `NullReferenceException`, `IndexOutOfRangeException` or `KeyNotFoundException`, for some users. These exceptions are now caught safely and logged. These failures are also mitigated by moving all Telemetry calls to the main thread. Issue noticed in IAP 4.4.1, but may be older.
- Apple - Optimized memory usage when processing transactions to prevent out of memory crash when processing transactions on launch.
- Batch Mode - Calls to `UnityPurchasingEditor.TargetAndroidStore` to select UDP will now successfully check UDP package installation and log an error instead of throwing a blocking popup when executed as part of a Batch Mode command.
- Analytics - Removed escape characters for receipt JSON which was causing parsing issues in the backend.
- GooglePlay - Fixed a bug causing a crash when retrying to finish a transaction while disconnected
## [4.5.1] - 2022-10-13
### Fixed
- GooglePlay - Fixed deferred purchases being processed when the app is foregrounded. Issue introduced in Unity IAP 4.5.0.
- GooglePlay - Fixed a `NullReferenceException` in `DequeueQueryProducts` happening when launching the app. Issue introduced in Unity IAP 4.2.0.
- Analytics - Fixed a `NullReferenceException` when reporting failed transactions of purchase unavailable products. Issue introduced in Unity IAP 4.2.0.
- Analytics - Legacy Analytics will no longer report events in custom UGS environments, which would cause misreported live sales figures. Issue introduced in Unity IAP 4.2.0.
## [4.5.0] - 2022-09-23
### Added
- Apple - Add support for [Family Sharing](https://developer.apple.com/app-store/subscriptions/#family-sharing).
- API `IAppleConfiguration.SetEntitlementsRevokedListener(Action<List<Product>>` called when entitlement to a products are revoked. The `Action` will be called with the list of revoked products. See documentation "Store Guides" > "iOS & Mac App Stores" for a sample usage.
- API - Product metadata is now available in `AppleProductMetadata` from `ProductMetadata.GetAppleProductMetadata()` via `IStoreController.products`.
- API `AppleProductMetadata.isFamilyShareable` indicated if the product is family shareable.
- `Apple App Store - 11 Family Sharing` sample that showcases how to use Unity IAP to manage family shared purchases.
### Fixed
- GooglePlay - Processing out-of-app purchases such as Promo codes no longer requires the app to be restarted. The
purchase will be processed the next time the app is foregrounded. Technical limitation: In the case of promo codes, if
the app is opened while the code is redeemed, you might receive an additional call
to `IStoreListener.OnPurchaseFailed` with `PurchaseFailureReason.Unknown`. This can be safely ignored.
- GooglePlay - Fixed a `NullReferenceException` that would rarely occur when retrieving products due to a concurrency issue introduced in Unity IAP 4.2.0
## [4.4.1] - 2022-08-11
### Fixed
- GooglePlay - Fixed NullReferenceException and ArgumentException that would rarely occur due to a concurrency issue introduced in Unity IAP 4.2.0
- Amazon - Set android:export to true to support Android API level 31+
## [4.4.0] - 2022-07-11
### Added
- GooglePlay - Google Play Billing Library version 4.0.0.
- The Multi-quantity feature is not yet supported by the IAP package and will come in a future update. **Do not enable `Multi-quantity` in the Google Play Console.**
- Add support for
the [IMMEDIATE_AND_CHARGE_FULL_PRICE](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode#IMMEDIATE_AND_CHARGE_FULL_PRICE)
proration mode. Use `GooglePlayProrationMode.ImmediateAndChargeFullPrice` for easy access.
- The `"skuDetails"` in the receipt json is now an array of the old structure, not just one object. It will only have one element in most cases, so if this is being parsed in your app, treat it like an array and get the first element by default.
### Fixed
- GooglePlay - Fix `IGooglePlayConfiguration.SetDeferredPurchaseListener`
and `IGooglePlayConfiguration.SetDeferredProrationUpgradeDowngradeSubscriptionListener` callbacks sometimes not being
called from the main thread.
- GooglePlay - When configuring `IGooglePlayConfiguration.SetQueryProductDetailsFailedListener(Action<int> retryCount)`, the action will be invoked with retryCount starting at 1 instead of 0.
- GooglePlay - Added a validation when upgrading/downgrading a subscription that calls `IStoreListener.OnPurchaseFailed` with `PurchaseFailureReason.ProductUnavailable` when the old transaction id is empty or null. This can occur when attempting to upgrade/downgrade a subscription that the user doesn't own.
## [4.3.0] - 2022-06-16
### Added
- GooglePlay - API `IGooglePlayConfiguration.SetQueryProductDetailsFailedListener(Action<int>)` called when Unity IAP fails to query product details. The `Action` will be called on each query product details failure with the retry count. See documentation "Store Guides" > "Google Play" for a sample usage.
## [4.2.1] - 2022-06-14
### Fixed
- Downgrade `com.unity.services.core` from 1.4.1 to 1.3.1 due to a new bug found in 1.4.1
## [4.2.0] - 2022-06-13
### Added
- Feature to automatically initialize **Unity Gaming Services** through the catalog UI. Please see the [documentation](https://docs.unity3d.com/Packages/com.unity.purchasing@4.2/manual/UnityIAPInitializeUnityGamingServices.html) for more details.
### Changed
- The In-App Purchasing package now requires **Unity Gaming Services** to have been initialized before it can be used.
For the time being **IAP** will continue working as usual, but will log a warning if **Unity Gaming Services** has not been initialized.
In future releases of this package, initializing **Unity Gaming Services** will be mandatory. Please see the [documentation](https://docs.unity3d.com/Packages/com.unity.purchasing@4.2/manual/UnityIAPInitializeUnityGamingServices.html) for more details.
## [4.2.0-pre.2] - 2022-04-28
### Added
- Support for Unity Analytics TransactionFailed event.
- Sample showcasing how to initialize [Unity Gaming Services](https://unity.com/solutions/gaming-services) using the [Services Core API](https://docs.unity.com/ugs-overview/services-core-api.html)
### Changed
- The Analytics notice in the In-App Purchasing service window has been removed for Unity Editors 2022 and up.
## [4.2.0-pre.1] - 2022-04-07
### Added
- Support for the [new Unity Analytics](https://unity.com/products/unity-analytics) [transaction event](https://docs.unity.com/analytics/AnalyticsSDKAPI.html#Transaction).
- The package will now send telemetry diagnostic and metric events to help improve the long-term reliability and performance of the package.
### Changed
- The minimum Unity Editor version supported is 2020.3.
- The In-App Purchasing service window now links to the [new Unity Dashboard](https://dashboard.unity3d.com/) for Unity Editors 2022 and up.
### Fixed
- GooglePlay - Fixed OnInitializeFailed never called if GooglePlay BillingClient is not ready during initialization.
- GooglePlay - GoogleBilling is allowed to initialize correctly even if the user's Google account is logged out, so long as it is linked. The user will need to log in to their account to continue making purchases.
- Fixed a build error `DirectoryNotFoundException` that occurred when the build platform was iOS or tvOS and the build target was another platform.
## [4.1.5] - 2022-05-17
### Fixed
- GooglePlay - Fixed a null reference exception introduced in Unity IAP 4.1.4 that could happen when cancelling an in-app purchase.
## [4.1.4] - 2022-03-30
### Fixed
- GooglePlay - Fixed issue where if an app is backgrounded while a purchase is being processed,
an `OnPurchaseFailed` would be called with the purchase failure reason `UserCancelled`, even if the purchase was successful.
## [4.1.3] - 2022-01-11
### Fixed
- Removed deprecated UnityWebRequest calls, updating them to use safer ones. This avoids compiler warnings that may occur.
- Fixed a serious edge case where Apple StoreKit receipt parsing might fail, preventing validation. A portion of receipts on iOS could be affected and cause Unity IAP to freeze after the purchase completed, but before the SDK can finalize the purchase. The user will have to uninstall and reinstall your app in order to recover from this. Your customer service will have to refund the user's purchase or apply the purchase in some other way outside of Unity IAP. This bug was accidentally introduced in Unity IAP 4.1.0. To avoid encountering this problem with your app, we suggest you update to this version.
## [4.1.2] - 2021-11-15
### Fixed
- Various internal obsolete warnings have been removed, allowing the project to be compiled with errors as warnings enabled.
## [4.1.1] - 2021-10-28
### Changed
- A default store will be selected for each platform. For Android the default store will be Google. All other platforms already had default stores.
## [4.1.0] - 2021-09-20
### Added
- Apple - Add support for receipt validation with [StoreKit Test](https://developer.apple.com/documentation/Xcode/setting-up-storekit-testing-in-xcode). See the [Receipt Validation Obfuscator manual](https://docs.unity3d.com/Packages/com.unity.purchasing@4.0/manual/UnityIAPValidatingReceipts.html) for a usage recommendation. See also the [sample](https://docs.unity3d.com/Packages/com.unity.purchasing@4.0/manual/Overview.html#learn-more) "05 Local Receipt Validation" for an example.
- GooglePlay - Add support for controlling automatic fetching of purchases at initialization, with `IGooglePlayConfiguration.SetFetchPurchasesAtInitialize(bool)`. Use to help distinguish previously seen purchases from new purchases. Then to fetch previously seen purchases use `IGooglePlayExtensions.RestorePurchases(Action<bool>)`.
### Changed
- Menu items for this package were renamed from *Unity IAP -> In-App Purchasing* and have been moved from *Window > Unity IAP* to *Services > In-App Purchasing*.
- Choosing an Android app store target before building the Android Build Target is now required. A build error will be emitted otherwise. Set this with the Store Selector window (*Services > In-App Purchasing > Switch Store ...*) or the API (`UnityPurchasingEditor.TargetAndroidStore()`). The default Android app store is now AppStore.NotSpecified and is visible in the window as `<Select a targeted store>`. Previously the default app store was the Google Play Store for the Android Build Target. See the [Store Selector documentation](https://docs.unity3d.com/Packages/com.unity.purchasing@4.1/manual/StoreSelector.html) for more
- Apple - Workaround rare crash seen if `nil` `NSLocaleCurrencyCode` is received when extracting localized currency code from `[SKProduct priceLocale]` when fetching products. Substitutes [ISO Unknown Currency code "XXX"](https://en.wikipedia.org/wiki/ISO_4217#X_currencies) into `ProductMetadata.isoCurrencyCode`.
- Removed warning log `Already recorded transaction`.
- Codeless - The default setting for enabling Codeless Auto Initialization in new projects' catalogs is now true instead of false. (As seen in the Catalog Editor as "Automatically initialize UnityPurchasing (recommended)").
### Fixed
- Fixed warning, missing await for async call in ExponentialRetryPolicy.cs
### Removed
- Removed the original and complex Unity IAP sample known as "Example", or "IAP Demo". Please use the recently added [samples](https://docs.unity3d.com/Packages/com.unity.purchasing@4.0/manual/Overview.html#learn-more) for a granular introduction to In-App Purchasing features.
## [4.0.3] - 2021-08-18
### Added
- Added samples to the [Package Manager Details view](https://docs.unity3d.com/Manual/upm-ui-details.html):
- Apple Sample - Restoring Transactions
- Apple Sample - Handling Deferred Purchases
- Apple Sample - Detecting Fraud
- Apple Sample - Getting Introductory Prices
- Apple Sample - Present Code Redemption Sheet
- Apple Sample - Can Make Payments
- Apple Sample - Retrieving Product Receipts
- Apple Sample - Subscription Upgrade Downgrade
- Apple Sample - Promoting Products
- Apple - Added support for fetching the current store promotion order of products on this device with `void IAppleExtensions.FetchStorePromotionOrder(Action<List<Product>> successCallback, Action errorCallback)`
- Apple - Added support for fetching the current store promotion visibility of a product on this device with `void FetchStorePromotionVisibilitySuccess(Product product, AppleStorePromotionVisibility visibility)`
## Fixed
- Apple - Fixed issue with unknown products being processed with `NonConsumable` type.
### Fixed
- GooglePlay - Fixed issue that led to purchases failing with a `ProductUnavailable` error when fetching additional products multiple times in quick succession.
- GooglePlay - Fixed issue that led to purchases failing with a `ProductUnavailable` error when a game had been running for some time.
- GooglePlay - Fixed issue that led to initialization failing with a `NoProductsAvailable` error when the network is interrupted while initializing, requiring the user to restart the app. Now Unity IAP handle initialization with poor network
connectivity by retrying periodically. This retry behavior is consistent with our Apple App Store's, and with the previous version of our Google Play Store's implementations.
### Changed
- Restructured [Manual documentation](https://docs.unity3d.com/Packages/com.unity.purchasing@4.0/manual/index.html) to improve readability.
## [4.0.0] - 2021-07-19
### Added
- Codeless Listener method to access the store configuration after initialization.
- `CodelessIAPStoreListener.Instance.GetStoreConfiguration`
- Several samples to the [Package Manager Details view](https://docs.unity3d.com/Manual/upm-ui-details.html) for com.unity.purchasing:
- Fetching additional products
- Integrating self-provided backend receipt validation
- Local receipt validation
- Google Play Store - Upgrade and downgrade subscriptions
- Google Play Store - Restoring Transactions
- Google Play Store - Confirming subscription price change
- Google Play Store - Handling Deferred Purchases
- Google Play Store - Fraud detection
- Apple App Store - Refreshing app receipts
- Google Play - `GooglePlayProrationMode` enum that represent Google's proration modes and added `IGooglePlayStoreExtensions.UpgradeDowngradeSubscription` using the enum.
### Fixed
- GooglePlay - Fixed [Application Not Responding (ANR)](https://developer.android.com/topic/performance/vitals/anr) error at `Product` initialization. The Google Play `SkuDetailsResponseListener.onSkuDetailsResponse` callback is now quickly handled.
- Amazon - Fixed `Product.metadata.localizedPrice` incorrectly being `0.00` for certain price formats.
- Apple, Mac App Store - Fixes Apple Silicon "arm64" support, missing from unitypurchasing bundle.
### Changed
- Reorganized and renamed APIs:
- `CodelessIAPStoreListener.Instance.ExtensionProvider.GetExtension` to `CodelessIAPStoreListener.Instance.GetStoreExtensions` to match the new `GetStoreConfiguration` API, above
- `IGooglePlayStoreExtensions.NotifyDeferredProrationUpgradeDowngradeSubscription` to `IGooglePlayConfiguration.NotifyDeferredProrationUpgradeDowngradeSubscription`
- `IGooglePlayStoreExtensions.NotifyDeferredPurchase` to `IGooglePlayConfiguration.NotifyDeferredPurchase`
- `IGooglePlayStoreExtensions.SetDeferredProrationUpgradeDowngradeSubscriptionListener` to `IGooglePlayConfiguration.SetDeferredProrationUpgradeDowngradeSubscriptionListener`
- `IGooglePlayStoreExtensions.SetDeferredPurchaseListener` to `IGooglePlayConfiguration.SetDeferredPurchaseListener`
- `IGooglePlayStoreExtensions.SetObfuscatedAccountId` to `IGooglePlayConfiguration.SetObfuscatedAccountId`
- `IGooglePlayStoreExtensions.SetObfuscatedProfileId` to `IGooglePlayConfiguration.SetObfuscatedProfileId`
- Apple - Change the order of execution of the post-process build script, which adds the `StoreKitFramework` such that other post-process build scripts can run after it.
- Changed the __Target Android__ Menu app store selection feature to display a window under `Window > Unity IAP > Switch Store...`. To set the app store for the next build, first use __Build Settings__ to activate the Android build target.
- For the future Unity 2022
- Moved Unity IAP menu items from `Window > Unity IAP > ...` to `Services > In-App Purchasing > ...`
- Updated and added new functionnality to the `Services > In-App Purchasing` window in the `Project Settings`. The `Current Targeted Store` selector and `Receipt Obfuscator` settings are now accessible from this window.
### Removed
- Samsung Galaxy - Removed Samsung Galaxy Store in-app purchasing support. Use the [Unity Distribution Portal](https://unity.com/products/unity-distribution-portal) for the continued support of the Samsung Galaxy Store.
- All related classes and implementations have been removed including `AppStore.SamsungApps`.
- Removed the following obsolete API:
- `CloudCatalogImpl`
- `CloudCatalogUploader`
- `CloudJSONProductCatalogExporter`
- `EventDestType`
- All `GooglePlayReceipt` constructors. Use `GooglePlayReceipt(string productID, string orderID, string packageName, string purchaseToken, DateTime purchaseTime, GooglePurchaseState purchaseState)` instead.
- `IAndroidStoreSelection.androidStore`
- `IDs.useCloudCatalog`
- `IGooglePlayConfiguration.SetPublicKey`
- `IGooglePlayConfiguration.UsePurchaseTokenForTransactionId`
- `IGooglePlayConfiguration.aggressivelyRecoverLostPurchases`
- `IGooglePlayStoreExtensionsMethod.FinishAdditionalTransaction`
- `IGooglePlayStoreExtensionsMethod.GetProductJSONDictionary`
- `IGooglePlayStoreExtensionsMethod.IsOwned`
- `IGooglePlayStoreExtensionsMethod.SetLogLevel`
- `IManagedStoreConfig`
- `IManagedStoreExtensions`
- `IStoreCallback.OnPurchasesRetrieved`. Use `IStoreCallback.OnAllPurchasesRetrieved` instead.
- `Promo`
- `StandardPurchasingModule.Instance(AndroidStore)`. Use `StandardPurchasingModule.Instance(AppStore)` instead.
- `StandardPurchasingModule.androidStore`. Use `StandardPurchasingModule.appStore` instead.
- `StandardPurchasingModule.useMockBillingSystem`. Use `IMicrosoftConfiguration` instead.
- `StoreTestMode`
- `UnityPurchasingEditor.TargetAndroidStore(AndroidStore)`. Use `TargetAndroidStore(AppStore)` instead.
- `WinRT` class. Use `WindowsStore` instead.
- `WindowsPhone8` class. Use `WindowsStore` instead.
## [3.2.3] - 2021-07-08
### Fixed
- GooglePlay - Fix `DuplicateTransaction` errors seen during purchase, after a purchase had previously been Acknowledged with Google.
- GooglePlay - Fix `DuplicateTransaction` errors seen after a user starts a purchase on a game with Unity IAP 1.x or 2.x, quits their game, upgrades their game to include a version of Unity IAP 3.x, and tries to finish consuming / completing that old purchase.
## [3.2.2] - 2021-06-02
### Added
- Sample to the [Package Manager Details view](https://docs.unity3d.com/Manual/upm-ui-details.html) for com.unity.purchasing:
- Buying consumables
### Fixed
- WebGL - While WebGL is not supported with an included app store implementation, the WebGL Player will no longer crash when the `StandardPurchasingModule.Initialize` API is called if Project Settings > Player > WebGL > Publishing Settings > Enable Exceptions > "Explicitly Thrown Exceptions Only" or "None" are set.
- Amazon - Better support for Android R8 compiler. Added minification (Project Settings > Player > Publishing Settings > Minify) "keep" ProGuard rules.
## [3.2.1] - 2021-05-18
### Changed
- Manual and API documentation updated.
## [3.2.0] - 2021-05-17
### Added
- GooglePlay - Automatic resumption of initialization when a user's device initially does not have a Google account, and they correct that Android setting without killing the app, then they resume the app. NOTE this does not impact Unity IAP's behavior when a user removes their Google account after initialization.
- GooglePlay - API `IGooglePlayConfiguration.SetServiceDisconnectAtInitializeListener(Action)` called when Unity IAP fails to connect to the underlying Google Play Billing service. The `Action` may be called multiple times after `UnityPurchasing.Initialize` if a user does not have a Google account added to their Android device. Initialization of Unity IAP will remain paused until this is corrected. Inform the user they must add a Google account in order to be able to purchase. See documentation "Store Guides" > "Google Play" for a sample usage.
- GooglePlay - It is now possible to check if a purchased product is pending or not by calling IsPurchasedProductDeferred() from GooglePlayStoreExtensions.
- UDP - RegisterPurchaseDeferredListener in IUDPExtensions can be used to assign a callback for pending purchases.
### Fixed
- GooglePlay - Receipts for Pending purchases are now UnifiedReceipts and not raw Google receipts. Any parsers you have for these can extract the raw receipt json by parsing the "Payload" field.
- Editor - The Fake Store UI used in Play Mode in the Editor, as well as some unsupported platforms has been restored. A null reference exception when trying to make a purchase no longer occurs.
- UDP - Added a null check when comparing Store-Specific IDs
### Changed:
- Samsung Galaxy - Support is being deprecated when not using Unity Distribution Portal as a target. The feature will be removed soon. Please use the Unity Distribution Portal package with IAP for full Samsung Galaxy support.
## [3.1.0] - 2021-04-15
### Added
- GooglePlay - Google Play Billing Library version 3.0.3.
- Fixes a broken purchase flow when user resumed their app through the Android Launcher after interrupting an ongoing purchase. Now `IStoreListener.OnPurchaseFailed(PurchaseFailureDescription.reason: PurchaseFailureReason.UserCancelled)` is called on resumption. E.g. first the user initiates a purchase, then sees the Google purchasing dialog, and sends their app to the background via the device's Home key. They tap the app's icon in the Launcher, see no dialog, and, finally, the app will now receive this callback.
### Changed
- `string StandardPurchasingModule.k_PackageVersion` is obsolete and will incorrectly report `"3.0.1"`. Please use the new `string StandardPurchasingModule.Version` to read the correct current version of this package.
- Reduced logging, and corrected the severity of several logs.
### Fixed
- tvOS - build errors due to undesirable call to `[[SKPaymentQueue defaultQueue] presentCodeRedemptionSheet]` which will now only be used for iOS 14.
- tvOS, macOS - Builds missing Xcode project In-App Purchasing capability and StoreKit.framework.
- Security - Tangle files causing compilation errors on platforms not supported by Security: non-GooglePlay and non-Apple.
- GooglePlay - Subscription upgrade/downgrade using proration mode [DEFERRED](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode#DEFERRED) (via `IGooglePlayStoreExtensions.UpgradeDowngradeSubscription(string oldSku, string newSku, int desiredProrationMode)`) reported `OnPurchaseFailed` with `PurchaseFailureReason.Unknown`, when the deferred subscription upgrade/downgrade succeeded. This subscription change generates no immediate transaction and no receipt. Now a custom `Action<Product>` can be called when the change succeeds, and is set by the new `SetDeferredProrationUpgradeDowngradeSubscriptionListener` API:
- Adds `IGooglePlayStoreExtensions.SetDeferredProrationUpgradeDowngradeSubscriptionListener(Action<Product> action)`. Sets listener for deferred subscription change events. Deferred subscription changes only take effect at the renewal cycle and no transaction is done immediately, therefore there is no receipt nor token. The `Action<Product>` is the deferred subscription change event. No payout is granted here. Instead, notify the user that the subscription change will take effect at the next renewal cycle.
## [3.0.2] - 2021-03-30
### Added
- Comprehensive manual and API documentation.
## [3.0.1] - 2021-03-08
### Removed
- Pre-release disclaimer.
## [3.0.0] - 2021-03-05
## [3.0.0-pre.7] - 2021-03-03
### Added
- GooglePlay - populate `Product.receipt` for `Action<Product>` parameter returned by `IGooglePlayStoreExtensions.SetDeferredPurchaseListener` callback
### Changed
- WinRT - This feature is now shipped as C# code under assembly definitions instead of .dll files.
- Security - This feature is now shipped as C# code under assembly definitions instead of .dll files.
- Receipt Validation Obfuscator - The Tangle File Obfuscate function is now Editor-only and no longer part of the Runtime Security module.
### Fixed
- Windows Standalone - launches FakeStore when detected by StandardPurchasingModule; disentangled from WinRT
- Security - restored Receipt Validation Obfuscator Editor functionality
- GooglePlay - fix regression, avoiding exception when using IGooglePlayConfiguration while running on a non-Google target
## [3.0.0-pre.6] - 2021-02-09
### Fixed
- WinRT - There was a bad path being pointed to by the .dll's meta file, preventing compilation to this target.
## [3.0.0-pre.5] - 2021-01-12
### Added
- Apple - Support for [auto-renewable subscription Offer Codes](https://developer.apple.com/documentation/storekit/in-app_purchase/subscriptions_and_offers/implementing_offer_codes_in_your_app) on iOS and iPadOS 14 and later via `IAppleExtensions.PresentOfferRedemptionSheet()`. E.g.
```csharp
public void ShowSubscriptionOfferRedemption(IExtensionProvider extensions)
{
var appleExtensions = extensions.GetExtension<IAppleExtensions>();
appleExtensions.PresentOfferRedemptionSheet();
}
```
### Fixed
- Security and WinRT stub dlls and references to Analytics no longer break builds unsupported platforms like PS4, XboxOne, Switch and Lumin. These platforms are still unsupported but will no longer raise errors on build.
### Removed
- Support for Facebook in-app purchasing is no longer provided. All classes and implementations have been removed.
## [3.0.0-pre.4] - 2020-10-09
- Fix builds for UWP
## [3.0.0-pre.3] - 2020-10-09
- First integration into Unity 2021
- Includes changes listed in [CHANGELOG-ASSETSTORE.md](CHANGELOG-ASSETSTORE.md), starting from version 1, ending 2020-10-09
- **This is the first release of the Unified *Unity In App Purchasing*, combining the old package and its Asset Store Components.**
## [2.2.2] - 2021-01-19
- Fixed logs incorrectly formatted showing “purchases({0}): -id of product-”
- Renamed method IStoreCallback.OnPurchasesRetrieved to IStoreCallback.OnAllPurchasesRetrieved, deprecated old method name. This is to fix a problem when refreshing receipts.
## [2.2.1] - 2020-11-19
- Fixed exposure of function calls at runtime used by the Asset Store Package 2.2.0 and up.
## [2.2.0] - 2020-10-22
- Google Billing v3
## [2.1.2] - 2020-09-20
Fix migration tooling's obfuscator file destination path to target Scripts instead of Resources
## [2.1.1] - 2020-08-25
- Fix compilation compatibility with platforms that don't use Unity Analytics (ex: PS4)
- Fix compilation compatibility with "Scripting Runtime Version" option set to ".Net 3.5 Equivalent (Deprecated)" in Unity 2018.4
## [2.1.0] - 2020-06-29
- Source Code provided instead of precompiled dlls.
- Live vs Stub DLLs are now using asmdef files to differentiate their targeting via the Editor
- Fixed errors regarding failing to find assemblies when toggling In-App Purchasing in the Service Window or Purchasing Service Settings
- Fixed failure to find UI assemblies when updating the Editor version.
- Added menu to support eventual migration to In-App Purchasing version 3.
## [2.0.6] - 2019-02-18
- Remove embedded prebuilt assemblies.
## [2.0.5] - 2019-02-08
- Fixed Unsupported platform error
## [2.0.4] - 2019-01-20
- Added editor and playmode testing.
## [2.0.3] - 2018-06-14
- Fixed issue related to 2.0.2 that caused new projects to not compile in the editor.
- Engine dll is enabled for editor by default.
- Removed meta data that disabled engine dll for windows store.
## [2.0.2] - 2018-06-12
- Fixed issue where TypeLoadException occured while using "UnityEngine.Purchasing" because SimpleJson was not found. fogbugzId: 1035663.
## [2.0.1] - 2018-02-14
- Fixed issue where importing the asset store package would fail due to importer settings.
## [2.0.0] - 2018-02-07
- Fixed issue with IAP_PURCHASING flag not set on project load.

10
CHANGELOG.md.meta Normal file
View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 51f03e3b6d8394dd595f181250b943dc
folderAsset: yes
timeCreated: 1424869
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,26 @@
# Testing
### Sandbox testing in Amazon
To use Amazons local Sandbox testing app, generate a JSON description of your product catalog on the devices SD card using the `IAmazonConfiguration` extended configuration:
````
var builder = ConfigurationBuilder.Instance(
StandardPurchasingModule.Instance());
// Define your products.
builder.AddProduct("someConsumable", ProductType.Consumable);
// Write a product description to the SD card
// in the appropriate location.
builder.Configure<IAmazonConfiguration>()
.WriteSandboxJSON(builder.products);
````
When using this method to write product descriptions to the SD card, declare the Android permission to write to external storage in the test apps manifest:
````
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
````
Remove this extra permission before publishing, if appropriate.
Amazon Sandbox is now set up for local testing. For more information, please see Amazon's [App Tester documentation](https://developer.amazon.com/public/apis/earn/in-app-purchasing/docs-v2/installing-and-configuring-app-tester).

View File

@ -0,0 +1,18 @@
# Purchase Receipt
All receipts have the base receipt information found [here](UnityIAPPurchaseReceipts.md).
iOS
---
Payload varies depending upon the device's iOS version.
|iOS version|Payload|
|:---|:---|
|__iOS &gt;= 7__|payload is a base 64 encoded [App Receipt](https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#/apple_ref/doc/uid/TP40010573-CH106-SW1).|
|__iOS &lt; 7__|payload is a [SKPaymentTransaction transactionReceipt](https://developer.apple.com/documentation/storekit/skpaymenttransaction/1617722-transactionreceipt?language=objc).|
Mac App Store
-------------
Payload is a base 64 encoded [App Receipt](https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#/apple_ref/doc/uid/TP40010573-CH106-SW1).

View File

@ -0,0 +1,33 @@
# Testing
To test on Apple stores you must be using an App Store Connect test account, which can be created in App Store Connect.
Sign out of the App Store on the iOS device or laptop, launch your application and you will be prompted to log in when you attempt either a purchase or to restore transactions.
If you receive an initialization failure with a reason of `NoProductsAvailable`, follow this checklist:
* App Store Connect product identifiers must exactly match the product identifiers supplied to Unity IAP
* In-App purchases must be enabled for your application in App Store Connect
* Products must be cleared for sale in App Store Connect
* It may take many hours for newly created App Store Connect products to be available for purchase
* You must agree to the latest App Store Connect developer agreements and have active bank details
# Mac App Store
When building a desktop Mac build you must select `Mac App Store validation` within Unitys build settings.
Once you have built your App, you must update its info.plist file with your bundle identifier and version strings. Right click on the `.app` file and click `show package contents`, locate the `info.plist` file and update the `CFBundleIdentifier` string to your application's bundle identifier.
You must then sign, package and install your application. You will need to run the following commands from an OSX terminal:
````
codesign -f --deep -s "3rd Party Mac Developer Application: " your.app/Contents/Plugins/unitypurchasing.bundle
codesign -f --deep -s "3rd Party Mac Developer Application: " your.app
productbuild --component your.app /Applications --sign "3rd Party Mac Developer Installer: " your.pkg
````
To sign the bundle, you may first need to remove the Contents.meta file if it exists: `your.app/Contents/Plugins/unitypurchasing.bundle/Contents.meta`
In order to install the package correctly you must delete the unpackaged .app file before running the newly created package.
You must then launch your App from the Applications folder. The first time you do so, you will be prompted to enter your iTunes account details, for which you should enter your App Store Connect test user account login. You will then be able to make test purchases against the sandbox environment.

View File

@ -0,0 +1,5 @@
# Backend Receipt Validation
Backend receipt validation helps you prevent users from accessing content they have not purchased.
For server-side content, where content is downloaded once purchased, the validation should take place on the server before the content is released. Unity does not offer support for server-side validation; however, third-party solutions are available, such as Nobuyori Takahashis [IAP project](https://github.com/voltrue2/in-app-purchase).

View File

@ -0,0 +1,63 @@
# IAP Button
IAP Button is a way to purchase or restore products without writing code.
## Adding IAP Button to the Scene
To add an __IAP Button__ to your Scene, in the Unity Editor, select __Window &gt; Unity IAP &gt; Create IAP Button__.
![Creating a Codeless **IAP Button** in the Unity Editor](images/CreateButton.png)
## Handling OnProductFetched
This event will be triggered when IAP retrieves product information from the app stores. It is a good idea to update all text related to the product in the UI with this event such as title, description and price.
**On Product Fetched script example**:
```
public class IAPButtonView : MonoBehaviour
{
[SerializeField]
Text title;
[SerializeField]
TMP_Text price;
public void OnProductFetched(Product product)
{
if (title != null)
{
title.text = product.metadata.localizedTitle;
}
if (price != null)
{
price.text = product.metadata.localizedPriceString;
}
}
}
```
A script like above can be added to the IAPButton to link different views with this event.
## Restore Button
Some app stores, including iTunes, require apps to have a __Restore__ button. Codeless IAP provides an easy way to implement a restore button in your app.
To add a __Restore__ button:
1. Add an __IAP Button__ to your Scene (**Services** &gt; **In-App Purchasing** &gt; **Create IAP Button**).
2. With your __IAP Button__ selected, locate its **IAP Button (Script)** component in the Inspector, then select **Restore** from the **Button Type** drop-down menu (most of the component's other fields will disappear from the Inspector view).
![Modifying an IAP Button to restore purchases](images/CodelessIAPButtonRestoreButton.png)
3. (Optional) You can add a script by clicking the plus (**+**) button to add a script to the **On Transactions Restored (Boolean, String)**.
4. (Optional) Drag the GameObject with the restore transactions script onto the event field in the components Inspector, then select your function from the dropdown menu.
**On Transactions Restored script example**:
```
public void OnTransactionsRestored(bool success, string? error)
{
Debug.Log($"TransactionsRestored: {success} {error}");
}
```
When a user selects this button at run time, the button calls the purchase restoration API for the current store. This functionality works on the iOS App Store, the Mac App Store and the Windows Store. You may want to hide the __Restore__ button on other platforms.
Unity IAP will always invoke the __On Transactions Restored (Boolean, String)__ function on the __Restore IAP Button__ with the result and the associated error message if the restore fails.
If the restore succeeds, Unity IAP invokes the __On Purchase Complete (Product)__ function on the __IAP Button__ associated with that Product.

View File

@ -0,0 +1,17 @@
# Defining Products in scripts
You can declare your Product list programmatically using the [Purchasing Configuration Builder](xref:UnityEngine.Purchasing.ConfigurationBuilder).
You must provide a unique cross-store __Product ID__ and __Product Type__ for each Product:
````
using UnityEngine;
using UnityEngine.Purchasing;
public class MyIAPManager {
public MyIAPManager () {
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
builder.AddProduct("100_gold_coins", ProductType.Consumable);
// Initialize Unity IAP...
}
}
````

View File

@ -0,0 +1,44 @@
# Defining products
## Product ID
Enter a cross-platform unique identifier to serve as the Products default ID when communicating with an app store.
**Important**: The ID may only contain lowercase letters, numbers, underscores, or periods.
## Product Type
Each Product must be of one of the following Types:
| **Type** | **Description** | **Examples** |
|:---|:---|:---|
|__Consumable__| Users can purchase the Product repeatedly. Consumable Products cannot be restored. | * Virtual currencies <br/> * Health potions <br/> * Temporary power-ups. |
|__Non-Consumable__| Users can only purchase the Product once. Non-Consumable Products can be restored. | * Weapons or armor <br/> * Access to extra content <br/> * No ads |
|__Subscription__| Users can access the Product for a finite period of time. Subscription Products can be restored. | * Monthly access to an online game <br/> * VIP status granting daily bonuses <br/> * A free trial |
## Product Metadata
This section defines the metadata associated with your Product for use in an in-game store.
### Descriptions
Use the following fields to add descriptive text for your Product:
| **Field** | **Data type** | **Description** | **Example** |
|:---|:---|:---|:---|
| __Product Locale__ | Enum | Determines the app stores available in your region. | **English (U.S.)** (Google Play, Apple) |
| __Product Title__ | String | The name of your Product as it appears in an app store. | “Health Potion” |
| __Product Description__ | String | The descriptive text for your Product as it appears in an app store, usually an explanation of what the Product is. | “Restores 50 HP.” |
### Payouts
Use this section to add local, fixed definitions for the content you pay out to the purchaser. Payouts make it easier to manage in-game wallets or inventories. By labeling a Product with a name and quantity, developers can quickly adjust in-game counts of certain item types upon purchase (for example, coins or gems).
| **Field** | **Data type** | **Description** | **Example** |
|:---|:---|:---|:---|
| __Payout Type__ | Enum | Defines the category of content the purchaser receives. There are four possible Types. | * Currency <br/> * Item<br/> * Resource <br/> * Other|
| __Payout Subtype__ | String | Provides a level of granularity to the content category. |* “Gold” and “Silver” subtypes of a __Currency__ type <br/> * “Potion” and “Boost” subtypes of an __Item__ type |
| __Quantity__ | Int | Specifies the number of items, currency, and so on, that the purchaser receives in the payout. | * 1 <br/> * &gt;25<br/>* 100|
| __Data__ | | Use this field any way you like as a property to reference in code. | * Flag for a UI element<br/> * Item rarity |
**Note**: You can add multiple Payouts to a single Product.
For more information on the PayoutDefinition class, see the [Scripting Reference](xref:UnityEngine.Purchasing.PayoutDefinition). You can always add Payout information to a Product in a script using this class. For example:
### Store ID Overrides
By default, Unity IAP assumes that your Product has the same identifier (specified in the **ID** field, above) across all app stores. Unity recommends doing this where possible. However, there are occasions when this is not possible, such as when publishing to both iOS and Mac stores, which prohibit developers from using the same product ID across both.

View File

@ -0,0 +1,18 @@
# Getting Started
## Finding and Enabling In-App Purchasing in the Service window
1. Open your Unity project in the Unity Editor.
2. From the menu, go to **Window** > **General** > **Services** to open the **Services** window.
3. Create a Project ID, then connect the project to an organization.
4. Answer the COPPA compliance questions.
5. The **Services** window displays a list of services. Click **In-App Purchasing**.
![Services](images/IAP-ServicesList.png)
6. The **Project Settings** window opens.
![Project Settings](images/IAP-ProjectSettings.png)
7. Click the toggle next to **In-App Purchasing Settings** to **ON**.
This will automatically install the IAP package from the Package Manager, providing you with new features and menu items to help you manage IAP.

View File

@ -0,0 +1,17 @@
# Setting Google Public Key
It is possible to set the Google Public Key in two different places either in the Unity Editor or in the Project Setting in the dashboard.
## In Unity Editor
1. Follow the steps in [Getting Started Guide](GettingStarted.md) to go to the In-App Purchasing service window
2. Follow the steps to enter the Google Public Key in the `Options` section of the In-App Purchasing service window
![GooglePublicKeyServiceWindowImage](images/IAPGooglePublicKey.png)
## In project dashboard
1. Go to the [Unity Dashboard](https://dashboard.unity3d.com/landing)
2. Open the left menu and select `Settings` then `Project Settings` under `Project`
![GooglePublicKeyDashboardSetting](images/IAPGooglePublicKeyDashboardSetting.png) and select the project
3. In the section `In-app purchase (IAP) settings` edit the field `Google License Key`
![GooglePublicKeyDashboard](images/IAPGooglePublicKeyDashboard.png)

View File

@ -0,0 +1,13 @@
# Purchase Receipt
All receipts have the base receipt information found [here](UnityIAPPurchaseReceipts.md).
Google Play
-----------
Payload is a JSON hash with the following keys and values:
|Key|Value|
|:---|:---|
|__json__|A JSON encoded string provided by Google; [`INAPP_PURCHASE_DATA`](http://developer.android.com/google/play/billing/billing_reference.html)|
|__signature__|A signature for the json parameter, as provided by Google; [`INAPP_DATA_SIGNATURE`](http://developer.android.com/google/play/billing/billing_reference.html)|

View File

@ -0,0 +1,19 @@
# How to Test
## Running Fake Store
To run fake store there are two ways:
1. Press Play in the Unity Editor, this will always use the fake store
2. Set `StandardPurchasingModule.Instance().useFakeStoreAlways` to `true`
## Advance Testing
The Fake Store allows the developer to chose between three options for testing purposes. This testing feature can be set with `StandardPurchasingModule.Instance().useFakeStoreUIMode`.
### 1. Default
This option display no dialog.
### 2. StandardUser
This option will show a simple dialog is shown when Purchasing.
### 3. DeveloperUser
This option will show a dialog giving options for failure reason code selection when Initializing/Retrieving Products and when Purchasing.

View File

@ -0,0 +1,36 @@
# IAP Button (Legacy)
IAP Button (Legacy) is obsolete. Please use [IAP Button](CodelessIAPButton.md). This new button allows for more UI customization and new events such as `OnProductFetched(Product)`.
IAP Button is a way to purchase or restore products without writing code.
## Adding IAP Button to the Scene
To add an __IAP Button__ to your Scene, in the Unity Editor, select __Window &gt; Unity IAP &gt; Create IAP Button (Legacy)__.
![Creating a Codeless **IAP Button** in the Unity Editor](images/CreateButton.png)
## Restore Button
Some app stores, including iTunes, require apps to have a __Restore__ button. Codeless IAP provides an easy way to implement a restore button in your app.
To add a __Restore__ button:
1. Add an __IAP Button__ to your Scene (**Services** &gt; **In-App Purchasing** &gt; **Create IAP Button**).
2. With your __IAP Button__ selected, locate its **IAP Button (Script)** component in the Inspector, then select **Restore** from the **Button Type** drop-down menu (most of the component's other fields will disappear from the Inspector view).
![Modifying an IAP Button to restore purchases](images/RestoreButton.png)
3. (Optional) You can add a script by clicking the plus (**+**) button to add a script to the **On Transactions Restored (Boolean, String)**.
4. (Optional) Drag the GameObject with the restore transactions script onto the event field in the components Inspector, then select your function from the dropdown menu.
**On Transactions Restored script example**:
```
public void OnTransactionsRestored(bool success, string? error)
{
Debug.Log($"TransactionsRestored: {success} {error}");
}
```
When a user selects this button at run time, the button calls the purchase restoration API for the current store. This functionality works on the iOS App Store, the Mac App Store and the Windows Store. You may want to hide the __Restore__ button on other platforms.
Unity IAP will always invoke the __On Transactions Restored (Boolean, String)__ function on the __Restore IAP Button__ with the result and the associated error message if the restore fails.
If the restore succeeds, Unity IAP invokes the __On Purchase Complete (Product)__ function on the __IAP Button__ associated with that Product.

View File

@ -0,0 +1,34 @@
# IAP Listeners
Codeless IAP dispatches successful and failed purchase events to an active __IAP Button__ component in the hierarchy. However, there may be times when it is difficult or undesirable to have an active __IAP Button__ when handling a successful purchase. For example, if a purchase is interrupted before completing, Unity IAP attempts to process the purchase again the next time it is initialized. You may want this to happen immediately after the app launches, in which case an __IAP Button__ wouldn't make sense. Codeless IAP includes the __IAP Listener__ component precisely for these cases. An active __IAP Listener__ in the Scene hierarchy receives any purchase events that cannot be dispatched to an __IAP Button__.
To add an __IAP Listener__:
1. In the Unity Editor, select __Services &gt; In-App Purchasing &gt; Create IAP Listener__.
2. Follow the steps for [writing a purchase fulfillment script as a GameObject component](#purchase-fulfillment).
3. Select the __IAP Listener__ in the Scene and locate its **IAP Listener (Script)** component in the Inspector, then click the plus (**+**) button to add a function to the **On Purchase Complete (Product)** list.
4. Drag the GameObject with the purchase fulfillment script onto the event field in the components Inspector, then select your function from the dropdown menu.
![Configuring an __IAP Listener__ to handle processing exceptions](images/IAPListenerScript.png)
## Purchase fulfillment
When your catalog contains at least one Product, you can define __IAP Button__ behavior when the purchase completes or fails.
1. Select your __IAP Button__ in the Scene view, then locate its __IAP Button (Script)__ component in the Inspector.
2. Select the Product to link to the __IAP Button__ from the __Product ID__ drop-down list.
![Selecting a Product to associate with a Codeless **IAP Button**](images/ProductDropdown.png)
3. Create your own function that provides purchase fulfillment, or import an Asset that does this (see code sample, below).
4. Apply your purchase fulfilment script to a GameObject as a component.
![Creating a GameObject with a purchase fulfillment script](images/PurchaseFulfillScript.png)
5. Return to the __IAP Button (Script)__ component in the Inspector, and click the plus (__+__) button to add a function to the __On Purchase Complete (Product)__ list.
6. Drag the GameObject with the purchase fulfillment script onto the __On Purchase Complete (Product)__ event field (illustrated below), then select your function from the dropdown menu.
![Assigning your purchase fulfillment script to an **IAP Button** event field](images/OnPurchaseComplete.png)
**Fulfillment script code sample**:
```
public void GrantCredits (int credits){
userCredits = userCredits + credits;
Debug.Log(“You received “ + credits “ Credits!”);
}
```
Run your game to test the __IAP Button__.

View File

@ -0,0 +1,6 @@
# Initialization
In order to use the **Unity In-App Purchasing** package, **Unity Gaming Services** needs to be initialized first followed by the initialization of **Unity In-App Purchasing**.
The following diagram visually describes steps to initialize Unity In-App Purchasing.
![Initialization flow diagram](images/UGSInitializationFlowDiagram.png)

View File

@ -0,0 +1,8 @@
# Purchase Receipt
All receipts have the base receipt information found [here](UnityIAPPurchaseReceipts.md).
Universal Windows Platform
-------------
Payload is an XML string as [specified by Microsoft](https://docs.microsoft.com/en-us/uwp/api/windows.applicationmodel.store.currentapp.getappreceiptasync?view=winrt-20348#Windows_ApplicationModel_Store_CurrentApp_GetAppReceiptAsync)

View File

@ -0,0 +1,61 @@
## Overview
This document explains how to activate **In-App Purchasing** (IAP).
The Unity IAP package provides coded and codeless approaches that you set up to:
- Allow users to buy items in your games.
- Connect to stores so you can obtain revenue from these purchases.
Here is an overview of the steps to get IAP working in your project:
- Define your in-app purchase strategy for this game.
- Set up your project to use Unity Services.
- Activate IAP to automatically install the package.
- Configure settings.
- Create and catalog your in-game items that you want to sell.
- Use the Codeless IAP button to give users a way to buy items. Then, once you have the logic working, consider customizing the button look and feel or use the scripted IAP for a rich API to enhance this process. ![Demo](images/IAP-DemoButtons.png)
- Connect your app to your chosen app stores, such as Google or Apple.
- Add items to the app stores.
## Next Steps
### Define your In-App Purchase strategy
Your task will be to create items for players to buy and obtain their identifiers.
To make this happen behind the scenes, you must tie Product ID to each item you are selling using a specified format. Some stores require that you customize the **Product ID** for their stores.
#### Planning:
Before you create your products, consider how you will define the following in your stores:
- Your strategy to determine when and how users can buy items.
- Your pricing strategy.
- The types of products (consumable, non-consumable, subscription).
## Store Extensions
Stores may offer unique functionality that does not fit into the normal cross-platform purchase flow. This extended functionality is accessed via the ``IExtensionProvider`` which is provided to your application when Unity IAP initializes successfully.
It is not necessary to use platform-dependent compilation when using extensions; each extension comes with a fake no-op implementation which is used when running on a platform that does not offer the extended functionality.
More information can be found in the `Stores` section of this manual
## Learn more
#### IAP Samples
1. From the **IAP Project Settings Page**, click **Open Package Manager** from **Options**.
2. Navigate to **In App Purchasing**. On the right information panel, find **Samples**.
3. Expand **Samples**, select a sample and then click **Import into Project**. Multiple samples may be included in a project.
4. Open **Project** > **Assets** > **Samples**. View the imported sample's `README` in the **Inspector**. Double-click to open its Unity Scene and click **Play** to interact with the sample.
![Samples](images/IAP-Samples.png)
#### Forum tutorials
[See the Unity forum](https://forum.unity.com/threads/sample-iap-project.529555/).
#### Unity Learn IAP classes
[Refer to the Unity Learn IAP classes](https://learn.unity.com/tutorial/unity-iap) for more guidance.

View File

@ -0,0 +1,30 @@
# Store Selector
## Using Unity Editor
The In-App Purchasing package supplies a tool to select the desired store when building. To access this tool open the Unity Editor and in the top menu click on `Services / Unity IAP / Switch Store...`.
In case Unity does not show a `Services` menu, set the target store using `Services > In-App Purchasing > Switch Store...`.
A new window will appear and in this window there are 4 important fields.
![](images/IAPStoreSelector.png)
#### Current Build Target
This field is not modifiable and shows the current selected build target in `Build Settings` under `File / Build Settings...`.
#### Current Targeted Store
This field is the main feature of this windows. Changing this field will change the store that the In-App Purchasing package will build for.
This field automatically changes to list of *Supported Stores* depending on the *Current Build Target*.
#### Supported Stores
This field is not modifiable and shows the full list of supported stores for the *Current Build Target*.
#### Other Available Stores
This field is not modifiable shows the full list of supported stores for every other build target not selected.
## Using API
In the code there is an option to change the targeted store. The call looks like this:
````
UnityPurchasingEditor.TargetAndroidStore(AndroidStore.AmazonAppStore)
````

View File

@ -0,0 +1,13 @@
Stores supported by Unity IAP
===============
The following is the full list of stores supported by the In-App Purchasing packages with the versions of those stores and links to the stores.
|Store Name|Platform|Version|Website|
|---|---|---|---|
|Google Billing|Android| 5.2.1|[Google Release Notes](https://developer.android.com/google/play/billing/release-notes)|
|Amazon Appstore|Android|2.0.76|[Amazon SDK](https://developer.amazon.com/docs/in-app-purchasing/iap-get-started.html#download-the-iap-sdk)|
|Samsung|Android|Removed use [UDP](https://unity.com/products/unity-distribution-portal) instead| [UDP](https://unity.com/products/unity-distribution-portal)|
|Unity Distribution Portal|Android|2.0.0 and higher|[UDP](https://unity.com/products/unity-distribution-portal)|
|App Store|MacOS / iOS / tvOS|Store Kit v1|[Apple Store Kit](https://developer.apple.com/documentation/storekit)|
|Microsoft Store|Windows||[Microsoft SDK](https://docs.microsoft.com/en-us/windows/uwp/monetize/in-app-purchases-and-trials)|

View File

@ -0,0 +1,65 @@
* Introduction to Unity IAP
* [About Unity IAP](index.md)
* [Stores supported by Unity IAP](StoresSupported.md)
* Set up and integrating Unity IAP
* [Overview](Overview.md)
* [Getting Started](GettingStarted.md)
* Defining products
* [Overview](DefiningProductsOverview.md)
* [Coded](DefiningProductsCoded.md)
* [IAP Catalog](UnityIAPDefiningProducts.md)
* Initialization
* [Overview](InitializationOverview.md)
* [Initialize Unity Gaming Services](UnityIAPInitializeUnityGamingServices.md)
* [Initialize IAP](UnityIAPInitialization.md)
* [Fetching Additional Products](UnityIAPFetchingProductsIncrementally.md)
* Creating a Purchasing Button
* [Browsing Product Metadata](UnityIAPBrowsingMetadata.md)
* [IAP Button](CodelessIAPButton.md)
* [IAP Button (Legacy)](IAPButton.md)
* [Coded](UnityIAPInitiatingPurchases.md)
* The Purchasing Flow
* Processing Purchases
* [Coded](UnityIAPProcessingPurchases.md)
* [IAP Listener](IAPListener.md)
* [Handling Purchase Failures](UnityIAPHandlingPurchaseFailures.md)
* [Purchase Receipts](UnityIAPPurchaseReceipts.md)
* [Restoring Transactions](UnityIAPRestoringTransactions.md)
* Securing Transactions
* [Backend Receipt Validation](BackendReceiptValidation.md)
* [Receipt Obfuscation](UnityIAPValidatingReceipts.md)
* [Store Selector](StoreSelector.md)
* Testing the Integration
* [What is Fake Store?](WhatIsFakeStore.md)
* [How to Test](HowToTest.md)
* Stores
* Google
* [How to Set Up](UnityIAPGoogleConfiguration.md)
* [Setting Google Public Key](GooglePublicKey.md)
* [Extensions and Configuration](UnityIAPGooglePlay.md)
* [Purchase Receipt](GoogleReceipt.md)
* [Testing Integration](Testing.md)
* Amazon
* [How to Set Up](UnityIAPAmazonConfiguration.md)
* [Extensions](UnityIAPAmazonExtendedFunctionality.md)
* [Testing Integration](AmazonTesting.md)
* Apple Store iOS, MacOS & tvOS
* [How to Set Up](UnityIAPAppleConfiguration.md)
* [Extensions and Configuration](UnityIAPiOSMAS.md)
* [Purchase Receipt](AppleReceipt.md)
* [Testing](AppleTesting.md)
* [Family Sharing](UnityIAPAppleFamilySharing.md)
* Microsoft Store (UWP)
* [How to Set Up](UnityIAPWindowsConfiguration.md)
* [Purchase Receipt](MicrosoftReceipt.md)
* [Testing](UnityIAPUniversalWindows.md)
* Implement Custom Store
* [What is a Custom Store](WhatCustomStore.md)
* [Implementing](UnityIAPImplementingAStore.md)
* [Initialization](UnityIAPIStoreInitialization.md)
* [Retrieving products](UnityIAPIStoreRetrievingProducts.md)
* [Handling purchases](UnityIAPIStoreHandlingPurchases.md)
* [Store Modules](UnityIAPModules.md)
* [Registering your store](UnityIAPModuleRegistration.md)
* [Store Configuration](UnityIAPModuleConfiguration.md)
* [Store Extensions](UnityIAPModuleExtension.md)

13
Documentation~/Testing.md Normal file
View File

@ -0,0 +1,13 @@
# Testing
Before publishing your application you must test your in-app purchases on an Android device as an alpha or beta distribution.
Note that while your Alpha or Beta APK must be published to test your IAPs, this does not mean your App has to be publicly visible in the Google Play store.
In order to perform a complete end-to-end test of your in-app purchases, you must do so while signed into a device using a test account.
Please note the following:
* You must upload a signed, release version of your APK to Google Play that is published as an alpha or beta distribution.
* The version number of the APK that you upload must match the version number of the APK that you test with.
* After entering your purchase metadata into the Google Play publisher console. It may take up to 24 hours before the purchase metadata that you entered into the Google Play publisher console will be activated. At that point, you can use your test account to make in-app purchases.

View File

@ -0,0 +1,50 @@
# Configuration for the Amazon Appstore
## Introduction
This guide describes the process of setting up the Amazon Appstore for use with the Unity in-app purchasing (IAP) system. This includes establishing the digital records and relationships that are required to interact with the Unity IAP API, setting up an Amazon developer account, and testing and publishing a Unity IAP application.
As with other platforms, the Amazon store allows for the purchase of virtual goods and managed products. These digital products are identified using a string identifier and an additional type to define durability, with choices including subscription (capable of being subscribed to), consumable (capable of being rebought), and non-consumable (capable of being bought once).
## Amazon Appstore
### Getting started
1. Set up an Amazon developer account at the [Amazon developer portal](https://developer.amazon.com/).
1. Write a game implementing the Unity IAP API. For reference, see the guides on [Unity IAP initialization](Overview.md). Use the Amazon Appstore for apps with no restrictions on IAP items.
### Device setup
1. For Android devices, download and install the [Amazon Appstore](https://www.amazon.com/appstore_android_app).
2. For FireOS devices, the Amazon Appstore should come pre-installed.<br/><br/>**Note**: Though you may freely target FireOS devices, FireOS is not a Unity-supported platform.<br/><br/>
3. Once you have installed the Amazon Appstore, install the [Amazon App Tester](http://www.amazon.com/Amazon-App-Tester/dp/B00BN3YZM2/).
![](images/AmazonConfiguration-AmazonAppTester.png)
1. Set up the Android SDK
1. To install and watch the Android debug log, ensure you have the [Android SDK](https://developer.android.com/studio/install.html) installed. Download the relevant command line tools package from the Android SDK install page and extract them to your computer.
1. Confirm that the SDK recognizes the attached Android device through the command-line adb tool. For example:
````
|[11:07:01] user@laptop:/Applications | $ adb devices
List of devices attached
00DA0807526300W5 device
````
### Unity app setup
Setting up to use Unity's IAP takes a few steps.
1. Import the Unity IAP plug-in. See [Setting up Unity IAP](Overview.md) for more information.
1. [Set the IAP target store to Amazon](StoreSelector.md).
### Amazon Appstore setup
It's not necessary to download Amazon's native IAP plug-in when preparing to use the Amazon stores, as all of the functionality it provides is already included in Unity's IAP service.
1. Add your app. From the Amazon Developer Portal select __Add a New App__.
![](images/AmazonConfiguration-AddNewApp.png)
1. Set up your catalog. Using the product descriptions you prepared earlier, add the items to the Amazon catalog using the Amazon Developer Portal. Navigate to your app's page, and find the __In-App Items section__. Use the __Add a Consumable__, __Add an Entitlement__, or __Add a Subscription__ buttons to set up your catalog.
![](images/AmazonConfiguration-SetUpCatalog.png)

View File

@ -0,0 +1,17 @@
# Extensions
## Extended functionality
### Amazon User ID
To fetch the current Amazon User ID for other Amazon services, use the `IAmazonExtensions`:
````
public void OnInitialized
(IStoreController controller, IExtensionProvider extensions)
{
string amazonUserId =
extensions.GetExtension<IAmazonExtensions>().amazonUserId;
// ...
}
````

View File

@ -0,0 +1,117 @@
# How to Set Up
## Introduction
This guide describes the process of establishing the digital records and relationships necessary for a Unity game to interact with an In-App Purchase Store.
In-App Purchase (IAP) is the process of transacting money for digital goods. A platform's Store allows purchase of Products, representing digital goods. These Products have an Identifier, typically of string datatype. Products have Types to represent their durability: _subscription_, _consumable_ (capable of being rebought), and _non-consumable_ (capable of being bought only once) are the most common.
## Apple App Store
### Getting Started
1. Write a game implementing Unity IAP. See [Unity IAP Initialization](Overview.md).
1. Keep the game's product identifiers on-hand for use in App Store Connect later.
![](images/IAPAppleImage0.png)
### Register the Application
1. In the [Apple Developer Center](https://developer.apple.com/account), navigate to the appropriate Identifiers section.
2. Add a new App ID to create a fundamental application entity with Apple.
**NOTE:** Use an Explicit App ID. Wildcard App IDs (com.example.*) cannot be used for applications that use In-App Purchases.
**NOTE:** The App ID is available to use in App Store Connect after you create it in the Developer Center.
![](images/IAPAppleImage1.png)
3. Navigate to [App Store Connect](https://itunesconnect.apple.com) and create an App, to establish a Store relationship with your game.
![](images/IAPAppleImage2.png)
4. Use the newly created App ID for the app's Bundle ID.
![](images/IAPAppleImage3.png)
### Add In-App Purchases
1. Choose __Features__ and add a new In-App Purchase with the plus ("+") button.
![](images/IAPAppleImage4.png)
2. Choose a [Product Type](DefiningProductsOverview.md#Product-Type).
![](images/IAPAppleImage5.png)
3. Specify the Product Identifier, and complete other fields as requested.
**NOTE:** The "Product ID" here is the same identifier used in the game source code, added to the [Unity IAP ConfigurationBuilder](xref:UnityEngine.Purchasing.ConfigurationBuilder) instance via __AddProduct()__ or __AddProducts()__.
**NOTE:** When targeting multiple Apple device groups (for example, shipping on both iOS and Mac) Apple requires usage of different, unique product identifiers for each distinct device group. Use [Unity IAP's Purchasing.IDs](xref:UnityEngine.Purchasing.IDs) class and define a one-to-many mapping Product IDs to the store-specific identifiers, and pass that mapping in when initializing IAP.
![](images/IAPAppleImage6.png)
4. Result:
![](images/IAPAppleImage7.png)
### Test IAP
1. Create __Sandbox Testers__ using App Store Connect for use on your test device's iTunes Account. To do this, navigate to __App Store Connect &gt; Users and Roles__, and choose the plus ("+") button. You must review [Apple's Sandbox Tester documentation](https://help.apple.com/app-store-connect/#/dev8b997bee1) as there are several additional important usage notes, and you must use a real email address to create Testers.
**TIP:** (*) To simplify managing the email address, use an email service capable of sub-addressing (emailaccount+subaddress@example.com) such as Gmail, iCloud, and Outlook.com. This allows one email account to receive email for multiple sub-addresses.
![](images/IAPAppleImage8.png)
2. Walk through the user creation wizard.
![](images/IAPAppleImage9.png)
3. Build the Xcode project for your game using Unity.
**NOTE:** Ensure the Bundle Identifier in Unity (**Edit** &gt; **Project Settings**, then select the **Other Settings** category, and navigate to the **Bundle Identifier** section) matches that used in App Store Connect.
4. Then, in your game's Xcode project, ensure the Team (Project Navigator &gt; your game Target &gt; General &gt; Identity &gt; Team) is set to that of your Apple Developer account.
![](images/IAPAppleImage10.png)
#### For iOS
1. Using the target iOS device, sign out of any existing Apple ID accounts. Only sign in as the Sandbox Tester when prompted by the app, later. Any subsequent purchases are routed through the Apple Sandbox instead of the Production Store.
![](images/IAPAppleImage11.png)
2. Build and run the game on your iOS device. `UnityPurchasing.Initialize()` succeeds if everything has been correctly configured. See [Unity Purchasing Initialization](xref:UnityEngine.Purchasing.UnityPurchasing)
3. Test the IAP by making a purchase in the game on the device. A modified purchase dialog displays, explaining that this purchase is being performed in the Sandbox Environment. Use the Sandbox User Tester password when prompted for purchase.
WARNING: If the indicator is not present, then an account is charged real money for the product.
![](images/IAPAppleImage12.png)
#### For Mac
1. When building a desktop Mac build, select __Mac App Store Validation__ within Unity's Mac **Player** settings.
2. Once you have built your App, update its `info.plist` file with your bundle identifier and version strings. Right click on the .app file and click __Show Package Contents__, locate the `info.plist` file and update the `CFBundleIdentifier` string to your application's bundle identifier.
3. Sign, package, and install your application. Run the following commands from an OSX terminal, filling in "your.app" and "your.pkg" appropriately.
**TIP:** To sign the bundle, you may first need to remove the Contents.meta file if it exists: `your.app/Contents/Plugins/unitypurchasing.bundle/Contents.meta`
1. `codesign -f --deep -s "3rd Party Mac Developer Application: " your.app/Contents/Plugins/unitypurchasing.bundle`
1. `codesign -f --deep -s "3rd Party Mac Developer Application: " your.app`
1. `productbuild --component your.app /Applications --sign "3rd Party Mac Developer Installer: " your.pkg`
4. To install the package correctly, delete the unpackaged .app file before running the newly created package and installing it.
5. Launch the app from the _Applications_ folder. The first time you do so, you are prompted to enter your iTunes account details, for which you can then make test purchases against the sandbox environment.
See pages on [iOS and Mac Extended Functionality](UnityIAPiOSMAS.md) and [Delivering applications to the Apple Mac Store](https://docs.unity3d.com/Manual/HOWTO-PortToAppleMacStore.html) for additional details on Apple App Store testing and signing.

View File

@ -0,0 +1,40 @@
# [Apple Family Sharing](https://developer.apple.com/app-store/subscriptions/#family-sharing)
## Introduction
Apple allows auto-renewable subscriptions and non-consumable in-app purchases to be shared within a family.
In order to use this feature, Family Sharing must be enabled on a per purchasable basis. See [Turn on Family Sharing for in-app purchases](https://help.apple.com/app-store-connect/#/dev45b03fab9).
### Is Family Shareable
The family shareable status of a product is available through the `isFamilyShareable` field found in the Apple product metadata.
The metadata can be obtained from `ProductMetadata.GetAppleProductMetadata()` via `IStoreController.products`.
````
bool IsProductFamilyShareable(Product product)
{
var appleProductMetadata = product.metadata.GetAppleProductMetadata();
return appleProductMetadata?.isFamilyShareable ?? false;
}
````
### Revoke Entitlement
In order to be handle revoked entitlements, you can specify a listener through the `IAppleConfiguration.SetEntitlementsRevokedListener(Action<List<Product>>`.
This will be called each time products have been revoked with the list of revoked products.
````
void InitializePurchasing()
{
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
builder.Configure<IAppleConfiguration>().SetEntitlementsRevokedListener(EntitlementsRevokeListener);
UnityPurchasing.Initialize(this, builder);
}
void EntitlementsRevokeListener(List<Product> revokedProducts)
{
foreach (var revokedProduct in revokedProducts)
{
Debug.Log($"Revoked product: {revokedProduct.definition.id}");
}
}
````

View File

@ -0,0 +1,11 @@
# Browsing Product Metadata
Unity IAP retrieves localized product metadata during the initialization process, which you can access via the ``IStoreController`` products field.
````
foreach (var product in controller.products.all) {
Debug.Log (product.metadata.localizedTitle);
Debug.Log (product.metadata.localizedDescription);
Debug.Log (product.metadata.localizedPriceString);
}
````

View File

@ -0,0 +1,79 @@
# IAP Catalog
To open the __IAP Catalog__ GUI one of two ways:
* Select __Services &gt; In-App Purchasing &gt; IAP Catalog__.
* Or, with your __IAP Button__ selected, locate its __IAP Button (Script)__ component in the Inspector, then click __IAP Catalog…__.
![Accessing the **IAP Catalog** GUI through an **IAP Button** script component](images/OpenCatalogGUI.png)
## Populating Products in the IAP Catalog
Next, use the GUI to define the following attributes for each Product in your catalog.
* A __Product ID__ with which to communicate to app stores (note that you can override this ID with unique store-specific IDs through the __Advanced__ option).
* A __Product Type__ (__Consumable__, __Non-Consumable__, or __Subscription__).
![Populating Product information in the **IAP Catalog** GUI](images/IAPCatalogGUI.png)
**Note:**
- The __IAP Catalog__ GUI provides additional tools for configuring your Products. Before [exporting a catalog](#Exporting-to-an-app-store) for upload to its respective store, you must populate description and pricing information as well.
- The __IAP Catalog__ acts as a Product catalog dictionary, not as an inventory manager. You must still implement the code that handles conveyance of the purchased content.
## Advanced
This section defines the metadata associated with your Product for use in an in-game store.
### Descriptions
This sections defines the [descriptions of a product](DefiningProductsOverview.md#Descriptions).
![Populating **Descriptions** fields for Products in the **IAP Catalog** GUI](images/ProductDescription.png)
Add __Translations__ for the __Title__ and __Description__ fields by clicking the plus (__+__) icon and selecting an additional locale. You can add as many translations as you like.
### Payouts
This sections defines the [payout of a product](DefiningProductsOverview.md#Payouts).
![Populating **Payouts** fields for Products in the **IAP Catalog** GUI](images/Payouts.png)
### Store ID Overrides
This sections defines the [Store ID overrides of a product](DefiningProductsOverview.md#Store-ID-Overrides).
![Populating **Store ID Overrides** fields for Products in the **IAP Catalog** GUI](images/StoreIdOverride.png)
### Google Configuration (required for Google Play export)
Provide either a Product price, or an ID for a [Pricing Template](https://support.google.com/googleplay/android-developer/answer/6334373) created in Google Play.
![Populating **Google Configuration** fields for Products in the **IAP Catalog** GUI.](images/GoogleConfig.png)
### Apple Configuration (required for Apple export)
Select a **Pricing Tier** from the dropdown menu. Unity supports predefined Apple price points, but not arbitrary values.
__Select a screenshot__ to upload.
For information on screenshot specs, see Apples publisher support documentation.
![Populating **Apple Configuration** fields for Products in the **IAP Catalog** GUI.](images/AppleConfig.png)
### Exporting to an app store
In order for purchases to function, you must configure your catalog on the corresponding app store. To do so, you can export your Product Catalog as a CSV file to Google Play, or as an XML file through Apples Application Loader to the iTunes Store.
#### Google Play
To export your Product Catalog for Google Play:
1. In the __IAP Catalog__ window (__Services &gt; In-App Purchasing &gt; IAP Catalog__), ensure that each Product has the following defined:<br/>* __ID__ <br/>* __Type__ <br/>* __Title__ and __Description__ <br/>* __Price__ or __Pricing Template__ ID
2. Scroll down, and select __App Store Export__.
3. Select __Google Play CSV__.
4. Choose a location in which to save the CSV file.
For complete guidance on uploading your exported catalog to Google Play, see the [Google in-app billing](https://developer.android.com/google/play/billing/billing_admin.html#billing-list-setup) documentation on the [Android Developers website](https://developer.android.com).
#### Apple App Store
To export your Product Catalog for Apple App Store:
1. In the **IAP Catalog** window (**Services** &gt; **In-App Purchasing** &gt; **IAP Catalog**), ensure that each Product has the following defined:<br/>* **ID** <br/>* **Type** <br/>* **Title** and **Description** <br/>* **Price Tier** and **Screenshot path** <br/>*
**Apple SKU** (found in [iTunes Connect](https://itunesconnect.apple.com)) <br/>* **Apple Team ID** (found on [Apples developer website](https://developer.apple.com))
2. Scroll down, and select **App Store Export**.
3. Select **Apple XML Delivery**.
4. Choose a location in which to save the XML file.
For complete guidance on importing through Apples Application Loader, see the [Application Loader](https://itunesconnect.apple.com/docs/UsingApplicationLoader.pdf) documentation on the [iTunes Connect website](https://itunesconnect.apple.com).

View File

@ -0,0 +1,45 @@
# Fetching Additional Products
This step is optional.
If your Application has a very large catalog of available products, you may find it takes too long to fetch them all in one batch.
An alternative is to initialise Unity IAP with an initial set of products, then fetch additional products in batches using the FetchAdditionalProducts method of the IStoreController:
````
/// <summary>
/// This will be called when Unity IAP has finished initialising.
/// </summary>
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
var additional = new HashSet<ProductDefinition>() {
new ProductDefinition("coins.500", ProductType.Consumable),
new ProductDefinition("armour", ProductType.NonConsumable)
};
Action onSuccess = () => {
Debug.Log("Fetched successfully!");
// The additional products are added to the set of
// previously retrieved products and are browseable
// and purchasable.
foreach (var product in controller.products.all) {
Debug.Log(product.definition.id);
}
};
Action<InitializationFailureReason> onFailure = (InitializationFailureReason i) => {
Debug.Log("Fetching failed for the specified reason: " + i);
};
controller.FetchAdditionalProducts(additional, onSuccess, onFailure);
}
````
Once additional products have been fetched they are added to the set of existing products previously retrieved and may be iterated over and purchased.
FetchAdditionalProducts behaves similarly to initialization:
* If network is unavailable it will wait until network become available to retrieve products
* It will fail for the same unrecoverable reasons initialization can fail, such as IAP being disabled in device settings
**You must not call FetchAdditionalProducts while a previous call to it is still pending.**

View File

@ -0,0 +1,84 @@
# How to Set Up
## Introduction
This guide describes the process of establishing the digital records and relationships necessary for a Unity game to interact with an In-App Purchase Store.
In-App Purchase (IAP) is the process of transacting money for digital goods. A platform's Store allows the purchase of Products, representing digital goods. These Products have an Identifier, typically of string datatype. Products have Types to represent their durability: _subscription_, _consumable_ (capable of being rebought), and _non-consumable_ (capable of being bought once) are the most common.
## Google Play Store
### Getting Started
1. Write a game implementing Unity IAP. See [Unity IAP Initialization](Overview.md) and [the Sample IAP Project](https://forum.unity.com/threads/sample-iap-project.529555/).
2. Keep the game's product identifiers on-hand for Google Play Developer Console use later.
![gold50](images/IAPGoogleImage0.png)
3. Build a signed non-Development Build Android APK from your game.
**TIP:** Make sure you safely store your keystore file. The original keystore is always required to update a published Google Play application.
**TIP:** Reuse the Bundle Version Code from your last uploaded APK during local testing to permit side-loading without first being required to upload the changed APK to the Developer Console. See the settings for the Android platform Player.
### Register the Application
From the Google Account that will publish the game, register the Android application with the [Google Play Developer Console](https://play.google.com/apps/publish).
**NOTE:** This guide uses the [Google Play License Testing approach](http://developer.android.com/google/play/billing/billing_testing.html) for testing in-app purchase integration.
1. Choose __Create app__.
![All apps](images/IAPGoogleImage1.png)
2. Give the application an App name and select the appropriate options for your game.
![Create app](images/IAPGoogleImage2.png)
3. Navigate to __Testing/Closed testing__ in the left nav and choose __Create track__. Select your APK and upload it. Also complete the basic Dashboard requirements, upload screenshots and add a Short and Full description. You can also create an Internal test track.
![Closed testing](images/IAPGoogleImage3.png)
### Add In-App Purchases
Now that you have uploaded our first binary, you can add the IAP products.
1. Navigate to __In-app Products__ and choose __Create product__.
![In-app products](images/IAPGoogleImage4.png)
2. Define the __Product ID__ , product details and price. Remember to activate the product after saving.
You can specify a consumable or non-consumable Product Type in __Managed product__. __Subscription__ is also supported by Unity IAP.
**NOTE**: The "Product ID" here is the same identifier used in the game source code, added to the [Unity IAP ConfigurationBuilder] instance via `AddProduct()` or `AddProducts()`, like "gold50".
![50goldcoins](images/IAPGoogleImage5.png)
**WARNING:** multi-quantity is not supported yet and should not be enabled.
### Test IAP
Add your testers to License Testing.
1. Navigate to All Apps on your Google Developer dashboard.
2. Select __Settings/License Testing__. Add each Google Account email address. Save changes.
![License testing](images/IAPGoogleImage6.png)
NOTE: There may be a delay of several hours from the time you publish the APK.
3. When available, share the __Join on Android__ link with testers. Ensure that testers can install the application from the store.
__Note:__ To test updates retaining permission to purchase IAPS's for free, you may side-load applications, updating the existing store-downladed APK install.
![My closed Track](images/IAPGoogleImage7.png)
4. To test the IAP, make a purchase on a device logged in with a Tester Google Account. A modified purchase dialog box appears to confirm the fact this product is under test and is free.
**WARNING**: If this dialog box does not appear, then the Tester Google Account will be charged real money for the product.
![](images/IAPGoogleImage8.png)

View File

@ -0,0 +1,98 @@
# Extensions and Configuration
Consumables
-----------
Unity IAP uses V4 of Google's Billing API, which features the concept of consumable products and explicit consumption API calls.
When you create consumable products in the Google Publisher dashboard, set them to be 'Managed' products. Unity IAP will take care of consuming them after your application has confirmed a purchase.
Extended functionality
----------------------
### Listen for recoverable initialization interruptions
A game may not complete initializing Unity IAP, either successfully or unsuccessfully, in certain circumstances. This can be due to the user having no Google account added to their Android device when the game initializes Unity IAP.
For example: a user first installs the app with the Play Store. Then the user removes their Google account from the device. The user launches the game and Unity IAP does not finish initializing, preventing the user from purchasing or restoring any prior purchases. To fix this, the user can [add a Google account](https://support.google.com/android/answer/7664951) to their device and return to the game.
The `IGooglePlayConfiguration.SetServiceDisconnectAtInitializeListener(Action)` API can be used to listen for this scenario. When this Action is triggered, the game may choose to advise the user through a user interface dialog that a Google account is required for purchasing and restoring prior purchases.
Please refer to this usage sample:
```
using UnityEngine;
using UnityEngine.Purchasing;
using UnityEngine.Purchasing.Extension;
public class GooglePlayInitializationDisconnectListener : IDetailedStoreListener
{
public GooglePlayInitializationDisconnectListener()
{
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
builder.Configure<IGooglePlayConfiguration>().SetServiceDisconnectAtInitializeListener(() =>
{
Debug.Log("Unable to connect to the Google Play Billing service. " +
"User may not have a Google account on their device.");
});
builder.AddProduct("100_gold_coins", ProductType.Consumable);
UnityPurchasing.Initialize(this, builder);
}
public void OnInitialized(IStoreController controller, IExtensionProvider extensions) { }
public void OnInitializeFailed(InitializationFailureReason error) { }
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e)
{
return PurchaseProcessingResult.Complete;
}
public void OnPurchaseFailed(Product i, PurchaseFailureReason p) { }
public void OnPurchaseFailed(Product i, PurchaseFailureDescription p) { }
}
```
### Listen for failed query product details
Querying product details from the Google Play Store can fail due to certain circumstances. When this happens, we retry until successful.
For example: a user first installs the app with the Play Store. Then the user launches the app without having Internet access. The Google Play Store will be unavailable because it requires an Internet connection which will result in failing to query product details. Restoring the Internet connection will fix the problem and the app will resume correctly.
The `IGooglePlayConfiguration.SetQueryProductDetailsFailedListener(Action<int>)` API can be used to listen for this scenario. The action has a parameter which contains the retry count. When this Action is triggered, the app may choose to advise the user through a user interface dialog to verify their Internet connection.
Please refer to this usage sample:
```
using UnityEngine;
using UnityEngine.Purchasing;
using UnityEngine.Purchasing.Extension;
public class QueryProductDetailsFailedListener : IDetailedStoreListener
{
public QueryProductDetailsFailedListener()
{
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
builder.Configure<IGooglePlayConfiguration>().SetQueryProductDetailsFailedListener((int retryCount) =>
{
Debug.Log("Failed to query product details " + retryCount + " times.");
});
builder.AddProduct("100_gold_coins", ProductType.Consumable);
UnityPurchasing.Initialize(this, builder);
}
public void OnInitialized(IStoreController controller, IExtensionProvider extensions) { }
public void OnInitializeFailed(InitializationFailureReason error) { }
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e)
{
return PurchaseProcessingResult.Complete;
}
public void OnPurchaseFailed(Product i, PurchaseFailureReason p) { }
public void OnPurchaseFailed(Product i, PurchaseFailureDescription p) { }
}
```

View File

@ -0,0 +1,28 @@
Handling purchase failures
====================
Purchases may fail for a number of reasons, including network failure, payment failure or device settings. You may wish to check the reason for a purchase failure and prompt the user to take action, though note that not all stores provide fine-grained failure information.
````
/// <summary>
/// Called when a purchase fails.
/// IStoreListener.OnPurchaseFailed is deprecated,
/// use IDetailedStoreListener.OnPurchaseFailed instead.
/// </summary>
public void OnPurchaseFailed (Product i, PurchaseFailureReason p)
{
if (p == PurchaseFailureReason.PurchasingUnavailable) {
// IAP may be disabled in device settings.
}
}
/// <summary>
/// Called when a purchase fails.
/// </summary>
public void OnPurchaseFailed (Product i, PurchaseFailureDescription p)
{
if (p.reason == PurchaseFailureReason.PurchasingUnavailable) {
// IAP may be disabled in device settings.
}
}
````

View File

@ -0,0 +1,13 @@
Handling purchases
==================
Your Store's Purchase method is called when the user opts to make a purchase. Your store should take the user through the checkout process and call either the ``OnPurchaseSucceeded`` or ``OnPurchaseFailed`` method of the ``IStoreCallback``.
Your store should supply a receipt and unique transaction ID; if the application has not already processed a purchase with the supplied tranasaction ID, Unity IAP will invoke the application's ``ProcessPurchase`` method.
Finishing Transactions
----------------------
When the application acknowledges that a transaction has been processed, or if the transaction has already been processed, Unity IAP invokes your stores FinishTransaction method.
Stores should use FinishTransaction to perform any housekeeping following a purchase, such as closing transactions or consuming consumable products.

View File

@ -0,0 +1,11 @@
Initialization
==============
Your stores ``Initialize`` method is called by Unity IAP with an ``IStoreCallback`` that your store uses to communicate back to Unity IAP asynchronously.
````
void Initialize(IStoreCallback callback) {
// Keep a reference to the callback for communicating with Unity IAP.
this.callback = callback;
}
````

View File

@ -0,0 +1,15 @@
Retrieving products
===================
When your store's ``RetrieveProducts`` method is called it should fetch the latest product metadata and, optionally, ownership status for the current user.
When this process completes your store should call the ``OnProductsRetrieved`` method of the ``IStoreCallback`` supplied to your store upon initialisation, supplying a collection of ``ProductDescription`` that represent the items available for purchase.
Where products are owned by the user, your store may fill in the receipt and transaction ID fields of ``ProductDescription``; Unity IAP will invoke the applications ``ProcessPurchase`` method for any transactions the application has not already processed.
Note that if the user is offline your store should retry until the user regains connectivity, taking care to avoid impacting game performance through aggressive polling.
Handling errors
---------------
If products cannot be retrieved due to an unrecoverable error, such as the developer making an error with their store configuration, you should call the ``OnSetupFailed`` method of the ``IStoreCallback``, indicating the ``InitializationFailureReason`` responsible.

View File

@ -0,0 +1,32 @@
Implementing a Store
====================
Your store must implement the IStore interface, the methods of which are detailed in following sections.
````
using UnityEngine.Purchasing.Extension;
public class MyStore : IStore
{
private IStoreCallback callback;
public void Initialize (IStoreCallback callback)
{
this.callback = callback;
}
public void RetrieveProducts (System.Collections.ObjectModel.ReadOnlyCollection<UnityEngine.Purchasing.ProductDefinition> products)
{
// Fetch product information and invoke callback.OnProductsRetrieved();
}
public void Purchase (UnityEngine.Purchasing.ProductDefinition product, string developerPayload)
{
// Start the purchase flow and call either callback.OnPurchaseSucceeded() or callback.OnPurchaseFailed()
}
public void FinishTransaction (UnityEngine.Purchasing.ProductDefinition product, string transactionId)
{
// Perform transaction related housekeeping
}
}
````

View File

@ -0,0 +1,86 @@
# Initialization
You must provide an implementation of the ``IDetailedStoreListener`` interface which Unity IAP uses to inform your application of purchase-related events.
Call the ``UnityPurchasing.Initialize`` method to start the initialization process, supplying your listener implementation and configuration.
Note that initialization will not fail if the network is unavailable; Unity IAP will continue attempting to initialize in the background. Initialization will only fail if Unity IAP encounters an unrecoverable problem such as a misconfiguration or IAP being disabled in device settings.
Consequently Unity IAP may take an arbitrary period of time to initialize; indefinitely if the user is in airplane mode. You should design your store accordingly by preventing users from attempting to make purchases if initialization has not completed successfully.
````
using UnityEngine;
using UnityEngine.Purchasing;
using UnityEngine.Purchasing.Extension;
public class MyIAPManager : IDetailedStoreListener {
private IStoreController controller;
private IExtensionProvider extensions;
public MyIAPManager () {
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
builder.AddProduct("100_gold_coins", ProductType.Consumable, new IDs
{
{"100_gold_coins_google", GooglePlay.Name},
{"100_gold_coins_mac", MacAppStore.Name}
});
UnityPurchasing.Initialize (this, builder);
}
/// <summary>
/// Called when Unity IAP is ready to make purchases.
/// </summary>
public void OnInitialized (IStoreController controller, IExtensionProvider extensions)
{
this.controller = controller;
this.extensions = extensions;
}
/// <summary>
/// Called when Unity IAP encounters an unrecoverable initialization error.
///
/// Note that this will not be called if Internet is unavailable; Unity IAP
/// will attempt initialization until it becomes available.
/// </summary>
public void OnInitializeFailed (InitializationFailureReason error)
{
}
/// <summary>
/// Called when a purchase completes.
///
/// May be called at any time after OnInitialized().
/// </summary>
public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e)
{
return PurchaseProcessingResult.Complete;
}
/// <summary>
/// Called when a purchase fails.
/// IStoreListener.OnPurchaseFailed is deprecated,
/// use IDetailedStoreListener.OnPurchaseFailed instead.
/// </summary>
public void OnPurchaseFailed (Product i, PurchaseFailureReason p)
{
}
/// <summary>
/// Called when a purchase fails.
/// </summary>
public void OnPurchaseFailed (Product i, PurchaseFailureDescription p)
{
}
}
````
### Automatically initializing `UnityPurchasing`
The IAP SDK must initialize in order for in-app purchasing to work. This occurs automatically when the first instance of a Codeless __IAP Button__ or [__IAP Listener__](IAPListener.md) loads at run time. However, you may need to initialize the SDK before an IAP Button or IAP Listener appears in your game. In these cases, check __Automatically initialize UnityPurchasing (recommended)__ at the bottom of the __IAP Catalog__ window. This ensures that [```UnityPurchasing```](xref:UnityEngine.Purchasing.UnityPurchasing) initializes immediately when the application starts, and eliminates dependencies on the codeless instances lifecycles.
![Enabling auto-initialization for the SDK through the **IAP Catalog** GUI](images/AutoInitialize.png)
In order to work, your catalog must contain at least one Product.
**Note**: You can use auto-initialize together with IAP Buttons or Listeners. In this case, the SDK initializes when the game starts instead of when the first instance of an IAP Button or Listener loads in the Scene. However, you should not enable auto-initialize if you also initialize manually in a script, as this may cause errors.

View File

@ -0,0 +1,63 @@
# Initialize Unity Gaming Services
Call `UnityServices.InitializeAsync()` to initialize all **Unity Gaming Services** at once.
It returns a `Task` that enables you to monitor the initialization's progression.
#### Example
```cs
using System;
using Unity.Services.Core;
using Unity.Services.Core.Environments;
using UnityEngine;
public class InitializeUnityServices : MonoBehaviour
{
public string environment = "production";
async void Start()
{
try
{
var options = new InitializationOptions()
.SetEnvironmentName(environment);
await UnityServices.InitializeAsync(options);
}
catch (Exception exception)
{
// An error occurred during services initialization.
}
}
}
```
### Automatic initialization for Codeless IAP
If you are using the Codeless IAP, you may instead enable **Unity Gaming Services** automatic initialization by checking the **Automatically initialize Unity Gaming Services** checkbox at the bottom of the **IAP Catalog** window.
This ensures that **Unity Gaming Services** initializes immediately when the application starts.
![Enabling auto-initialization for the Unity Gaming Services through the **IAP Catalog** GUI](images/AutoInitializeUGS.png)
To use this feature **Automatically initialize UnityPurchasing (recommended)** must be enabled. If you do not see these checkboxes inside the **IAP Catalog**, it may be because you have not yet added products in the catalog window.
This initializes **Unity Gaming Services** with the default `production` environment.
This way of initializing **Unity Gaming Services** might not be compatible with all other services as they might require special initialization options.
If the use of initialization options is needed, **Unity Gaming Services** should be initialized with the coded API as described above.
## Warning message
If you attempt to use the **Unity IAP** service without first initializing **Unity Gaming Services**, you will receive the following warning message:
```
Unity In-App Purchasing requires Unity Gaming Services to have been initialized before use.
Find out how to initialize Unity Gaming Services by following the documentation https://docs.unity.com/ugs-overview/services-core-api.html#InitializationExample
or download the 06 Initialize Gaming Services sample from Package Manager > In-App Purchasing > Samples.
```
## Technical details
The `InitializeAsync` methods affect the currently installed service packages in your Unity project.
Note that this method is not supported during edit time.
___
For more information, please see the [Services Core API documentation](https://docs.unity.com/ugs-overview/services-core-api.html#Services_Core_API).
Download the `06 Initialize Gaming Services` from `Package Manager > In-App Purchasing > Samples` for a concrete example.

View File

@ -0,0 +1,13 @@
# Coded
When the user wants to buy a product call the ``InitiatePurchase`` method of the ``IStoreController``, identifying the product the user wants to buy.
````
// Example method called when the user presses a 'buy' button
// to start the purchase process.
public void OnPurchaseClicked(string productId) {
controller.InitiatePurchase(productId);
}
````
Your application will be notified asynchronously of the result, either with an invocation of ``ProcessPurchase`` for successful purchases or ``OnPurchaseFailed`` for failures.

View File

@ -0,0 +1,11 @@
Store Configuration
===================
Your store may require developers to supply additional configuration information during initialization, for which your module can register a configuration instance that implements the ``IStoreConfiguration`` interface:
````
var config = new MyConfiguration(); // Implements IStoreConfiguration
BindConfiguration<MyConfiguration>(new MyConfiguration());
````
When developers request an instance of your configuration type, Unity IAP first tries to cast your store implementation to the configuration type. Only if that cast fails will any instance bound via ``BindConfiguration`` will be used.

View File

@ -0,0 +1,22 @@
Store Extensions
================
Your store may offer additional functionality that does not fit into the cross platform purchase flow, for example the ability to refresh app receipts on Apples stores.
You should create an interface that defines the extended functionality, itself implementing the ``IStoreExtension`` interface:
````
/// <summary>
/// Functionality specific to my store.
/// </summary>
public interface IMyExtensions : IStoreExtension
{
// Hypothetical method for a store that provides User IDs.
String GetUserStoreId();
}
````
Applications request extended functionality via the ``IExtensionProvider``. When they do so Unity IAP first tries to cast the active store implementation to the requested type.
If that cast fails, Unity IAP will provide any instance registered via a call your store module has provided via ``RegisterExtension``, or null if no instance has been provided.
Modules should provide instances for the extension interfaces they define even when running on unsupported platforms, so as to avoid forcing application developers to use platform dependent compilation.

View File

@ -0,0 +1,19 @@
Registering your store
======================
Call the ``RegisterStore`` method supplying a name for your store and your implementation, which must implement the IStore interface.
````
public override void Configure() {
RegisterStore(“GooglePlay”, InstantiateMyStore());
}
private void InstantiateMyStore() {
if (Application.platform == RuntimePlatform.Android) {
return new MyAlternativeGooglePlayImplementation ();
}
return null;
}
````
The store name must match the name developers use when defining products for your store so Unity IAP uses the correct product identifiers when addressing your store.

View File

@ -0,0 +1,14 @@
Store Modules
=============
Store modules extend the ``AbstractPurchasingModule`` class, acting as factories Unity IAP can use to obtain an instance of your store along with any configuration and extensions.
Developers can supply multiple modules to Unity IAP, allowing them to use your custom store implementation alongside the default Unity-provided stores:
````
ConfigurationBuilder.Instance (MyCustomModule.Instance(), StandardPurchasingModule.Instance ());
````
Where two or more modules have implementations available for a given platform, precedence is given in order the modules were supplied to the ``ConfigurationBuilder``; any implementation provided by ``MyCustomModule`` will be used in preference to ``StandardPurchasingModule``.
Note that a module can support multiple stores; the ``StandardPurchasingModule`` handles all of Unity IAPs default store implementations.

View File

@ -0,0 +1,34 @@
# Processing Purchases
The `ProcessPurchase` function of your store listener is called when a purchase completes. Your application should fulfil whatever the user has bought; for example, unlocking local content or sending purchase receipts to a server to update a server-side game model.
A result is returned to indicate whether or not your Application has finished processing the purchase:
|Result|Description|
|:---|:---|
|__PurchaseProcessingResult.Complete__|The application has finished processing the purchase and should not be informed of it again.|
|__PurchaseProcessingResult.Pending__|The application is still processing the purchase and ProcessPurchase will be called again the next time the Application starts, unless the `ConfirmPendingPurchase` function of `IStoreController` is called.|
Note that ProcessPurchase may be called at any point following a successful initialization. If your application crashes during execution of the ``ProcessPurchase`` handler, then it is invoked again the next time Unity IAP initializes, so you may wish to implement your own additional de-duplication.
## Reliability
Unity IAP requires explicit acknowledgement of purchases to ensure that purchases are reliably fulfilled in the event of network outages or application crashes. Any purchases that complete while the application is offline will be sent to the application on next initialization.
### Completing purchases immediately
When `PurchaseProcessingResult.Complete` is returned, Unity IAP finishes the transaction immediately (as shown in the diagram below).
You **must not** return `PurchaseProcessingResult.Complete` if you are selling consumable products and fulfilling them from a server (for example, providing currency in an online game).
If you do, there is a risk that consumable purchases will be lost if your Application is uninstalled before the cloud save takes place.
![Completing immediately](images/PurchaseProcessingResult.Complete.png)
### Saving purchases to the cloud
If you are saving consumable purchases to the cloud, you **must** return `PurchaseProcessingResult.Pending` and call `ConfirmPendingPurchase` only when you have successfully persisted the purchase.
When returning `Pending`, Unity IAP keeps transactions open on the underlying store until confirmed as processed, ensuring consumable purchases are not lost even if a user reinstalls your application while a consumable is in this state.
![Pending Purchases](images/PurchaseProcessingResult.Pending.png)

View File

@ -0,0 +1,9 @@
# Purchase Receipts
Unity IAP provides purchase receipts as a JSON hash containing the following keys and values:
|Key|Value|
|:---|:---|
|__Store__|The name of the store in use, such as **GooglePlay** or **AppleAppStore**|
|__TransactionID__|This transactions unique identifier, provided by the store|
|__Payload__|Varies by platform, details below.|

View File

@ -0,0 +1,24 @@
# Restoring Transactions
When a user reinstalls your application they should be granted any Non-Consumable or renewable Subscription products they already own. App stores maintain a permanent record of each user's Non-Consumable and renewable Subscription products which Unity IAP can retrieve. Non-renewing subscriptions on Apple platforms cannot be restored. If you use non-renewing subscription products on Apple platforms, it is up to you to keep a record of the active subscriptions and sync the subscription between devices.
On platforms that support it (e.g. Google Play and Universal Windows Applications) Unity IAP automatically restores any products the user owns during the first initialization following reinstallation; the ``ProcessPurchase`` method of your ``IStoreListener`` will be called for each owned item.
On Apple platforms users must enter their password to retrieve previous transactions so your application must provide users with a button letting them do so. During this process the ``ProcessPurchase`` method of your ``IStoreListener`` will be invoked for any items the user already owns.
````
/// <summary>
/// Your IStoreListener implementation of OnInitialized.
/// </summary>
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
extensions.GetExtension<IAppleExtensions> ().RestoreTransactions ((result, error) => {
if (result) {
// This does not mean anything was restored,
// merely that the restoration process succeeded.
} else {
// Restoration failed. `error` contains the failure reason.
}
});
}
````

View File

@ -0,0 +1,13 @@
# Testing
## Simulator
Unity IAP features support for Microsoft's In App Purchase simulator, which allows you to test IAP purchase flows on devices before publishing your application.
The simulator can be enabled when configuring Unity IAP before initialization, as follows:
````
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
builder.Configure<IMicrosoftConfiguration>().useMockBillingSystem = true;
````
Make sure you disable the mock billing system before publishing your application.

View File

@ -0,0 +1,177 @@
# Receipt Obfuscation
If the content that the user is purchasing already exists on the device, the application simply needs to make a decision about whether to unlock it.
Unity IAP provides tools to help you hide unpurchased content and to validate and parse receipts through Google Play and Apple stores.
## Obfuscating encryption keys
Receipt validation is performed using known encryption keys. For your application, this is an encrypted Google Play public key, and/or Apple's certificates.
If a user can replace these, they can defeat your receipt validation checks, so it is important to make it difficult for a user to easily find and modify these keys.
Unity IAP provides a tool that can help you obfuscate your encryption keys within your Application. This confuses or jumbles the keys so that it is much harder for a user to acces them. In the Unity menu bar, go to __Services__ > __In-App Purchasing__ > __IAP Receipt Validation Obfuscator__.
![The Obfuscator window](images/IAPObfuscator.png)
This window encodes Apple's root certificate, [StoreKit Test certificate](https://developer.apple.com/documentation/Xcode/setting-up-storekit-testing-in-xcode) (which are bundled with Unity IAP) and your Google Play public key (copied by you from the application's [Google Play Developer Console's Services &amp; APIs](https://developer.android.com/google/play/licensing/setting-up.html) page) into different C# classes: __AppleTangle__, __AppleStoreKitTestTangle__, and __GooglePlayTangle__. These are added to your project for use in the next section.
Note that you do not have to provide a Google Play public key if you are only targeting Apple's stores, and vice versa.
## Validating receipts
Use the `CrossPlatformValidator` class for validation across both Google Play and Apple stores.
You must supply this class with either your Google Play public key or one of Apple's certificates, or both if you wish to validate across both platforms. Note that you cannot supply both Apple root and ["StoreKit Test"](https://developer.apple.com/documentation/Xcode/setting-up-storekit-testing-in-xcode)(*) certificates, and instead should pass only one, choosing that with a run-time or build-time switch.
The `CrossPlatformValidator` performs two checks:
* Receipt authenticity is checked via signature validation.
* The application bundle identifier on the receipt is compared to the one in your application. An **InvalidBundleId** exception is thrown if they do not match.
Note that the validator only validates receipts generated on Google Play and Apple platforms. Receipts generated on any other platform, including fakes generated in the Editor, throw an __IAPSecurityException__.
Be sure that your `CrossPlatformValidator` object has been created in time for processing your purchases. Note that during the initialization of Unity IAP, it is possible that pending purchases from previous sessions may be fetched from the store and processed. If you are using a persistent object of this type, create it before initializing Unity IAP.
If you try to validate a receipt for a platform that you haven't supplied a secret key for, a __MissingStoreSecretException__ is thrown.
````
public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e)
{
bool validPurchase = true; // Presume valid for platforms with no R.V.
// Unity IAP's validation logic is only included on these platforms.
#if UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX
// Prepare the validator with the secrets we prepared in the Editor
// obfuscation window.
var validator = new CrossPlatformValidator(GooglePlayTangle.Data(),
AppleTangle.Data(), Application.identifier);
try {
// On Google Play, result has a single product ID.
// On Apple stores, receipts contain multiple products.
var result = validator.Validate(e.purchasedProduct.receipt);
// For informational purposes, we list the receipt(s)
Debug.Log("Receipt is valid. Contents:");
foreach (IPurchaseReceipt productReceipt in result) {
Debug.Log(productReceipt.productID);
Debug.Log(productReceipt.purchaseDate);
Debug.Log(productReceipt.transactionID);
}
} catch (IAPSecurityException) {
Debug.Log("Invalid receipt, not unlocking content");
validPurchase = false;
}
#endif
if (validPurchase) {
// Unlock the appropriate content here.
}
return PurchaseProcessingResult.Complete;
}
````
### Choose an Apple certificate: Apple Root or StoreKit Test
(*) Unity IAP supports receipt validation of purchases made with the StoreKit Test store simulation.
Apple's Xcode 12 offers the ["StoreKit Test"](https://developer.apple.com/documentation/Xcode/setting-up-storekit-testing-in-xcode) suite of features for developers to more conveniently test IAP, without the need to use an Apple App Store Connect Sandbox configuration.
Use the `AppleStoreKitTestTangle` class in place of the usual `AppleTangle` class, when constructing the `CrossPlatformValidator` for receipt validation. Note that both tangle classes are generated by the **Receipt Validation Obfuscator**.
````
public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e)
{
bool validPurchase = true;
#if UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX
// Choose one Apple certificate. NOTE AppleStoreKitTestTangle requires
// the active Xcode Scheme set to use a StoreKit Configuration file.
// Here we use a symbol, defined either in code or Project Settings >
// Player > Scripting Define Symbols, to choose which Apple IAP system
// we intend to test with in Xcode, next.
#if !DEBUG_STOREKIT_TEST
var validator = new CrossPlatformValidator(GooglePlayTangle.Data(),
AppleTangle.Data(), Application.identifier);
#else
var validator = new CrossPlatformValidator(GooglePlayTangle.Data(),
AppleStoreKitTestTangle.Data(), Application.identifier);
#endif
try {
validator.Validate(e.purchasedProduct.receipt);
} catch (IAPSecurityException) {
validPurchase = false;
}
#endif
if (validPurchase) { }
return PurchaseProcessingResult.Complete;
}
````
### Deep validation
It is important you check not just that the receipt is valid, but also what information it contains. A common technique by users attempting to access content without purchase is to supply receipts from other products or applications. These receipts are genuine and do pass validation, so you should make decisions based on the product IDs parsed by the __CrossPlatformValidator__.
## Store-specific details
Different stores have different fields in their purchase receipts. To access store-specific fields, `IPurchaseReceipt` can be downcast to two different subtypes: `GooglePlayReceipt` and `AppleInAppPurchaseReceipt`.
````
var result = validator.Validate(e.purchasedProduct.receipt);
Debug.Log("Receipt is valid. Contents:");
foreach (IPurchaseReceipt productReceipt in result) {
Debug.Log(productReceipt.productID);
Debug.Log(productReceipt.purchaseDate);
Debug.Log(productReceipt.transactionID);
GooglePlayReceipt google = productReceipt as GooglePlayReceipt;
if (null != google) {
// This is Google's Order ID.
// Note that it is null when testing in the sandbox
// because Google's sandbox does not provide Order IDs.
Debug.Log(google.transactionID);
Debug.Log(google.purchaseState);
Debug.Log(google.purchaseToken);
}
AppleInAppPurchaseReceipt apple = productReceipt as AppleInAppPurchaseReceipt;
if (null != apple) {
Debug.Log(apple.originalTransactionIdentifier);
Debug.Log(apple.subscriptionExpirationDate);
Debug.Log(apple.cancellationDate);
Debug.Log(apple.quantity);
}
}
````
## Parsing raw Apple receipts
Use the `AppleValidator` class to extract detailed information about an Apple receipt. Note that this class only works with iOS App receipts from version 7.0 onwards, not Apple's deprecated transaction receipts.
````
#if UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
// Get a reference to IAppleConfiguration during IAP initialization.
var appleConfig = builder.Configure<IAppleConfiguration>();
var receiptData = System.Convert.FromBase64String(appleConfig.appReceipt);
AppleReceipt receipt = new AppleValidator(AppleTangle.Data()).Validate(receiptData);
Debug.Log(receipt.bundleID);
Debug.Log(receipt.receiptCreationDate);
foreach (AppleInAppPurchaseReceipt productReceipt in receipt.inAppPurchaseReceipts) {
Debug.Log(productReceipt.transactionIdentifier);
Debug.Log(productReceipt.productIdentifier);
}
#endif
````
The `AppleReceipt` type models Apple's ASN1 receipt format. See [Apple's documentation](https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#/apple_ref/doc/uid/TP40010573-CH106-SW1) for an explanation of its fields.

View File

@ -0,0 +1,137 @@
# How to Set Up
## Introduction
This guide describes the process of establishing the digital records and relationships necessary for a Unity game to interact with an In-App Purchase Store.
In-App Purchase (IAP) is the process of transacting money for digital goods. A platform's Store allows purchase of Products representing digital goods. These Products have an Identifier, typically of string datatype. Products have Types to represent their durability: _subscription_, _consumable_ (capable of being rebought), and _non-consumable_ (capable of being bought once) are the most common.
## Windows Store
### Introduction
Windows App Development offers both local and remote Windows Store client-server IAP testing.
This page covers local testing with the emulator and a simulated billing system, then Windows Store testing which limits app publication visibility to those with the app's link.
**NOTE**: This guide targets Windows 10 Universal SDK. Other Windows targets are available.
**NOTE**: Unity versions 5.6+ support IL2CPP Windows builds. Using Unity IAP for IL2CPP on Windows with earlier versions of Unity generates a compilation error.
### Getting started
1. Write a game implementing Unity IAP. See [Unity IAP Initialization](Overview.md).
1. Keep the game's product identifiers on-hand for use in Microsoft's Windows Dev Center Dashboard to perform remote Windows Store testing later.
![](images/IAPWindowsImage0.png)
### Test IAP locally
Microsoft offers a simulated billing system, permitting local testing of IAP. This removes the need to configure anything on the Windows Dev Center or communicate with the the Windows Store via the app for initial integration testing.
[Configuring local testing](UnityIAPUniversalWindows.md) is far simpler than for remote Store testing, although it requires temporary code changes to the app which need to be removed before app publication.
To test IAP locally:
1. Enable the simulated billing system in code where Unity IAP is initialized with its ConfigurationBuilder instance.
**WARNING**: Remove these code changes after testing, before publishing to the Store; otherwise the app will not transact any real money via IAP!
![](images/IAPWindowsImage1.png)
2. Build the application in Unity for __Universal Windows Platform__.
3. Open the application in Visual Studio and run the Local Machine target for x86.
4. Test IAP.
5. Remove the simulated billing system from code.
### Register the App on the Windows Store
Once basic IAP functionality has been tested locally, you can more confidently begin working with the Windows Store. This test confirms that the app has all necessary IAPs registered correctly to permit purchasing.
For testing IAP and publication use the [Windows Dev Center](https://dev.windows.com/en-us/publish) and configure the app with a limited visibility. This limits the app's visibility to those who have its direct link.
**NOTE**: Testing on the Store also requires Certification, which may serve as an obstacle to testing. It is therefore important to complete testing locally before proceeding to testing with Windows Store.
1. In the Dev Center [create a new app](https://dev.windows.com/en-us/overview).
![](images/IAPWindowsImage2.png)
2. Reserve the app name.
![](images/IAPWindowsImage3.png)
3. To test IAP with the Windows Store, the Windows Dev Center needs the published app. Click __Pricing and availability__ and limit the app's Store visibility so that it is only available to users who have the app's direct link.
![](images/IAPWindowsImage4.png)
4. In "Distribution and visibility" see a list of the Store's available [publication behaviors](https://msdn.microsoft.com/en-us/library/windows/apps/mt148548.aspx#dist_vis). Select __Hide this app in the Store__.
![](images/IAPWindowsImage5.png)
5. Collect the direct link. This will be used to install the app on a Windows 10 device for [testing](https://msdn.microsoft.com/en-us/library/windows/apps/mt148561.aspx).
![](images/IAPWindowsImage6.png)
6. Submit the app for Certification.
Submissions may take many hours to complete, and blocking issues may be raised by Microsoft Certification, which you will need to address before the submission passes successfully.
### Add In-App Products on the Store
Add each IAP, setting the price to be "free" so that no money will be transacted during testing. After the test is completed, reconfigure the IAP with the desired price and republish it. See [IAP Submissions](https://msdn.microsoft.com/en-us/library/windows/apps/mt148551.aspx).
1. In the new app's "App overview" page, click __Create a new IAP__ .
![](images/IAPWindowsImage7.png)
2. Enter the product ID.
![](images/IAPWindowsImage8.png)
3. Configure the type, price, and language.
**NOTE**: For **Pricing and availability** choose **free** for testing purposes to avoid incurring unnecessary financial charges. When you're finished with testing, update and re-submit each IAP with the desired price in preparation for release to the public.
![](images/IAPWindowsImage9.png)
Select **Properties** to set the type.
![](images/IAPWindowsImage10.png)
Select **Pricing and availability** to set the price choosing **Free** as explained above.
![](images/IAPWindowsImage11.png)
Select **Manage languages** and declare the supported languages.
![](images/IAPWindowsImage12.png)
Select the declared language when returned to the IAP overview.
![](images/IAPWindowsImage13.png)
Populate the Title, Description and Icon.
![](images/IAPWindowsImage14.png)
4. Submit the IAP for Certification.
As with apps, IAP submissions may take many hours to complete, and blocking issues may be raised by Microsoft Certification which you will need to address before the submission passes successfully.
![](images/IAPWindowsImage15.png)
### Test IAP with the Store
These steps follow a branch of the beta test process made possible with Windows Store. This involves limiting the visibility of the app itself, negating discovery by the public through the "Search Store" function. See Windows Dev Centre resources on [beta testing](https://msdn.microsoft.com/en-us/library/windows/apps/xaml/mt188751.aspx) and [targeted distribution](https://msdn.microsoft.com/en-us/library/windows/apps/mt185377.aspx) for more information.
1. Confirm both the app and IAPs have completed Certification.
2. Install the app on a Windows 10 device via the direct link, generated above.
3. Test IAP.
4. After passing test, update the IAP with the desired public pricing, update the app visibility settings to share with the general public, and submit both kinds of changes for final Certification.

View File

@ -0,0 +1,280 @@
Extensions and Configuration
====================
Extended functionality
----------------------
### Reading the App Receipt
An [App Receipt](https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html) is stored on the device's local storage and can be read as follows:
````
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
string receipt = builder.Configure<IAppleConfiguration>().appReceipt;
````
### Checking for payment restrictions
In App Purchases may be restricted in a device's settings, which can be checked for as follows:
````
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
bool canMakePayments = builder.Configure<IAppleConfiguration>().canMakePayments;
````
### Restoring transactions
On Apple platforms users must enter their password to retrieve previous transactions so your application must provide users with a button letting them do so. During this process the `ProcessPurchase` method of your `IStoreListener` will be invoked for any items the user already owns.
````
/// <summary>
/// Your IStoreListener implementation of OnInitialized.
/// </summary>
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
extensions.GetExtension<IAppleExtensions> ().RestoreTransactions ((result, error) => {
if (result) {
// This does not mean anything was restored,
// merely that the restoration process succeeded.
} else {
// Restoration failed. `error` contains the failure reason.
}
});
}
````
### Refreshing the App Receipt
Apple provides a mechanism to fetch a new App Receipt from their servers, typically used when no receipt is currently cached in local storage; [SKReceiptRefreshRequest](https://developer.apple.com/library/ios/documentation/StoreKit/Reference/SKReceiptRefreshRequest_ClassRef/index.html#/apple_ref/occ/cl/SKReceiptRefreshRequest).
Note that this will prompt the user for their password.
Unity IAP makes this method available as follows:
````
/// <summary>
/// Your IStoreListener implementation of OnInitialized.
/// </summary>
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
extensions.GetExtension<IAppleExtensions> ().RefreshAppReceipt (receipt => {
// This handler is invoked if the request is successful.
// Receipt will be the latest app receipt.
Console.WriteLine(receipt);
},
() => {
// This handler will be invoked if the request fails,
// such as if the network is unavailable or the user
// enters the wrong password.
});
}
````
### Ask to Buy
iOS 8 introduced a new parental control feature called [Ask to Buy](https://developer.apple.com/library/ios/technotes/tn2259/_index.html#/apple_ref/doc/uid/DTS40009578-CH1-UPDATE_YOUR_APP_FOR_ASK_TO_BUY).
Ask to Buy purchases defer for parent approval. When this occurs, Unity IAP sends your app a notification as follows:
````
/// This is called when Unity IAP has finished initialising.
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
extensions.GetExtension<IAppleExtensions>().RegisterPurchaseDeferredListener(product => {
Console.WriteLine(product.definition.id);
});
}
````
#### Enable "Ask-to-Buy" simulation in the Sandbox App Store
The sample class below demonstrates how to access `IAppleExtensions` in order to enable Ask-to-Buy simulation in the Sandbox App Store:
```
using UnityEngine;
using UnityEngine.Purchasing;
public class AppleSimulateAskToBuy : MonoBehaviour {
public void SetSimulateAskToBuy(bool shouldSimulateAskToBuy) {
if (Application.platform == RuntimePlatform.IPhonePlayer) {
IAppleExtensions extensions = IAPButton.IAPButtonStoreManager.Instance.ExtensionProvider.GetExtension<IAppleExtensions>();
extensions.simulateAskToBuy = shouldSimulateAskToBuy;
}
}
}
```
When the purchase is approved or rejected, your store's normal `ProcessPurchase` or `OnPurchaseFailed` listener methods are invoked.
### Transaction Receipts
Sometimes consumable Ask to Buy purchases don't show up in the App Receipt, in which case you cannot validate them using that receipt. However, iOS provides a Transaction Receipt that contains all purchases, including Ask to Buy. Access the most recent Transaction Receipt string for a given `Product` using `IAppleExtensions`.
**Note**: Transaction Receipts are not available for Mac builds. Requesting a Transaction Receipt on a Mac build results in an empty string.
```
using System;
using UnityEngine;
using UnityEngine.Purchasing;
using UnityEngine.Purchasing.Extension;
public class AskToBuy : MonoBehaviour, IDetailedStoreListener
{
// Unity IAP objects
private IStoreController m_Controller;
private IAppleExtensions m_AppleExtensions;
public AskToBuy ()
{
var builder = ConfigurationBuilder.Instance (StandardPurchasingModule.Instance ());
builder.AddProduct ("100_gold_coins", ProductType.Consumable, new IDs {
{ "100_gold_coins_google", GooglePlay.Name },
{ "100_gold_coins_mac", MacAppStore.Name }
});
UnityPurchasing.Initialize (this, builder);
}
/// <summary>
/// This will be called when Unity IAP has finished initialising.
/// </summary>
public void OnInitialized (IStoreController controller, IExtensionProvider extensions)
{
m_Controller = controller;
m_AppleExtensions = extensions.GetExtension<IAppleExtensions> ();
// On Apple platforms we need to handle deferred purchases caused by Apple's Ask to Buy feature.
// On non-Apple platforms this will have no effect; OnDeferred will never be called.
m_AppleExtensions.RegisterPurchaseDeferredListener (OnDeferred);
}
/// <summary>
/// This will be called when a purchase completes.
/// </summary>
public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e)
{
if (Application.platform == RuntimePlatform.IPhonePlayer ||
Application.platform == RuntimePlatform.tvOS) {
string transactionReceipt = m_AppleExtensions.GetTransactionReceiptForProduct (e.purchasedProduct);
Console.WriteLine (transactionReceipt);
// Send transaction receipt to server for validation
}
return PurchaseProcessingResult.Complete;
}
/// <summary>
/// Called when a purchase fails.
/// IStoreListener.OnPurchaseFailed is deprecated,
/// use IDetailedStoreListener.OnPurchaseFailed instead.
/// </summary>
public void OnPurchaseFailed (Product i, PurchaseFailureReason p)
{
Debug.Log ("OnPurchaseFailed for ProductID: " + item.definition.id);
Debug.Log ("PurchaseFailureReason: " + p);
}
/// <summary>
/// Called when a purchase fails.
/// </summary>
public void OnPurchaseFailed (Product i, PurchaseFailureDescription p)
{
Debug.Log ("OnPurchaseFailed for ProductID: " + item.definition.id);
Debug.Log ("PurchaseFailureReason: " + p.reason);
Debug.Log ("More Details: " + p.message;
}
/// <summary>
/// iOS Specific.
/// This is called as part of Apple's 'Ask to buy' functionality,
/// when a purchase is requested by a minor and referred to a parent
/// for approval.
///
/// When the purchase is approved or rejected, the normal purchase events
/// will fire.
/// </summary>
/// <param name="item">Item.</param>
private void OnDeferred (Product item)
{
Debug.Log ("Purchase deferred: " + item.definition.id);
}
}
```
Unlike App Receipts, you cannot validate Transaction Receipts locally. Instead, you must send the receipt string to a remote server for validation. If you already use a remote server to validate App Receipts, send Transaction Receipts to the same Apple endpoint, to receive a JSON response.
Example JSON response:
```
{
"receipt": {
"original_purchase_date_pst": "2017-11-15 15:25:20 America/Los_Angeles",
"purchase_date_ms": "1510788320209",
"unique_identifier": "0ea7808637555b2c633eb07aa1cb0894c821a6f9",
"original_transaction_id": "1000000352597239",
"bvrs": "0",
"transaction_id": "1000000352597239",
"quantity": "1",
"unique_vendor_identifier": "01B57C2E-9E91-42FF-9B0D-4983175D6694",
"item_id": "1141751870",
"original_purchase_date": "2017-11-15 23:25:20 Etc/GMT",
"product_id": "100.gold.coins",
"purchase_date": "2017-11-15 23:25:20 Etc/GMT",
"is_trial_period": "false",
"purchase_date_pst": "2017-11-15 15:25:20 America/Los_Angeles",
"bid": "com.unity3d.unityiap.demo",
"original_purchase_date_ms": "1510788320209"
},
"status": 0
}
```
## Intercepting Apple promotional purchases
Apple allows you to promote [in-game purchases](https://developer.apple.com/app-store/promoting-in-app-purchases/#:~:text=inside%20your%20app.-,Overview,approved%20and%20ready%20to%20promote.&text=When%20a%20user%20doesn't,to%20download%20the%20app%20first.) through your apps product page. Unlike conventional in-app purchases, Apple promotional purchases initiate directly from the App Store on iOS and tvOS. The App Store then launches your app to complete the transaction, or prompts the user to download the app if it isnt installed.
The `IAppleConfiguration` `SetApplePromotionalPurchaseInterceptor` callback method intercepts Apple promotional purchases. Use this callback to present parental gates, send analytics events, or perform other functions before sending the purchase to Apple. The callback uses the `Product` that the user attempted to purchase. You must call `IAppleExtensions.ContinuePromotionalPurchases()` to continue with the promotional purchase. This will initiate any queued-up payments.
If you do not set the callback, promotional purchases go through immediately and call `ProcessPurchase` with the result.
**Note**: Calling these APIs on other platforms has no effect.
```
private IAppleExtensions m_AppleExtensions;
public void Awake() {
var module = StandardPurchasingModule.Instance();
var builder = ConfigurationBuilder.Instance(module);
// On iOS and tvOS we can intercept promotional purchases that come directly from
// the App Store.
// On other platforms this will have no effect; OnPromotionalPurchase will never be
// called.
builder.Configure<IAppleConfiguration>().
SetApplePromotionalPurchaseInterceptorCallback(OnPromotionalPurchase);
Debug.Log("Setting Apple promotional purchase interceptor callback");
}
public void OnInitialized(IStoreController controller, IExtensionProvider extensions) {
m_AppleExtensions = extensions.GetExtension<IAppleExtensions>();
foreach (var item in controller.products.all) {
if (item.availableToPurchase) {
// Set all these products to be visible in the user's App Store
m_AppleExtensions.SetStorePromotionVisibility(item, AppleStorePromotionVisibility.Show);
}
}
}
private void OnPromotionalPurchase(Product item) {
Debug.Log("Attempted promotional purchase: " + item.definition.id);
// Promotional purchase has been detected.
// Handle this event by, e.g. presenting a parental gate.
// Here, for demonstration purposes only, we will wait five seconds before continuing
// the purchase.
StartCoroutine(ContinuePromotionalPurchases());
}
private IEnumerator ContinuePromotionalPurchases() {
Debug.Log("Continuing promotional purchases in 5 seconds");
yield return new WaitForSeconds(5);
Debug.Log("Continuing promotional purchases now");
m_AppleExtensions.ContinuePromotionalPurchases (); // iOS and tvOS only
}
```

View File

@ -0,0 +1,3 @@
# What is a Custom Store
A custom store is a store that the In-App Purchasing package doesn't support out of the out of the box. It allows developers to create their own stores and build on top of the existing infrastructure of the package.

View File

@ -0,0 +1,3 @@
# What is Fake Store?
Fake Store isn't a store that exists in production, it is used to tests your apps quickly inside the editor.

25
Documentation~/filter.yml Normal file
View File

@ -0,0 +1,25 @@
apiRules:
- exclude:
# exclude mentions of samples in Scripting API docs
uidRegex: ^Samples\.Purchasing\..*
type: Namespace
- exclude:
# exclude mentions of tests in Scripting API docs
uidRegex: ^Tests
type: Namespace
- exclude:
# exclude mentions of tests in Scripting API docs
uidRegex: ^test
type: Namespace
- exclude:
# exclude mentions of tests in Scripting API docs
uidRegex: Tests
type: Type
- exclude:
# exclude mentions of tests in Scripting API docs
uidRegex: ^UnityEditor.Purchasing.EditorTests
type: Namespace
- exclude:
# exclude mentions of tests in Scripting API docs
uidRegex: ^UnityEngine.Purchasing.RuntimeTests
type: Namespace

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Some files were not shown because too many files have changed in this diff Show More