Unity In-App-Käufe (In-App Purchasing)
Namespace: UnityEngine.Purchasing | Sicherheit: UnityEngine.Purchasing.Security
Paket: com.unity.purchasing
Unity IAP hat einen eigenen Initialisierungspfad über UnityIAPServices.StoreController() → store.Connect(). Es erfordert kein UnityServices.InitializeAsync(), beide können jedoch koexistieren, wenn dein Projekt andere UGS-Dienste verwendet. Wenn Analytics vorhanden ist und InitializeAsync() aufgerufen wird, sendet IAP automatisch Transaktionsereignisse.
Bevor du loslegst
Lies zuerst immer references/pre-check.md. Es durchsucht das Projekt nach IAP-Paketen von Drittanbietern, nativer Google-Abrechnung und vorhandenen Unity IAP-Versionen und leitet dann zum richtigen Pfad weiter. Lies keine andere Referenzdatei und nimm keine Änderungen vor, bis die Weiterleitung geklärt ist.
Detaillierte Referenzen
- Projektscan und Pfadweiterleitung (zuerst lesen): Siehe references/pre-check.md
- API-Signaturen & Codebeispiele: Siehe references/api-notes.md
- Plattformerweiterungen (Apple, Google): Siehe references/platform-notes.md
- Bearbeiten von
IAPProductCatalog.json(Schema, Dezimalserialisierung, Aktualisierung): Siehe references/codeless-catalog.md - Migration v4 → v5: Siehe references/migration-v4-to-v5.md
- Konvertierung von nativer Google BillingClient zu Unity IAP 5: Siehe references/path-convert-native-google-billing.md
- Konvertierung von nativem iOS StoreKit-Plugin zu Unity IAP 5: Siehe references/path-convert-native-storekit.md
- Konvertierung von Essential Kit-Abrechnung zu Unity IAP 5: Siehe references/convert-essentialkit.md
- UniPay (FLOBUK) — Bewertung und Anleitung: Siehe references/convert-unipay.md
- RevenueCat — Konvertierungsbewertung und Anleitung: Siehe references/convert-revenuecat.md
- Adapty — Konvertierungsbewertung und Anleitung: Siehe references/convert-adapty.md
- Hinzufügen von Unity IAP 5 zu einem Projekt ohne bestehendes IAP: Siehe references/path-add-iap-to-new-project.md
- Implementierung von IAP D2C-Funktionen (Zahlungsanbieter von Drittanbietern — Stripe/Coda, erfordert v5.4+): Siehe references/path-implement-iap-d2c.md
Lies Referenzdateien bei Bedarf — nur wenn du bestimmte API-Signaturen, Plattformerweiterungsdetails oder Migrationszuordnungen benötigst.
Initialisierungsablauf
- Rufe
StoreControllerüberUnityIAPServices.StoreController()ab (oder einzelne Dienste überDefaultStore(),DefaultProduct(),DefaultPurchase()) - Abonniere alle erforderlichen Ereignisse (siehe Erforderliche Ereignisabonnements unten) bevor du
Connect()aufrufst await store.Connect()— um eine Verbindung zum Plattform-Store herzustellen- Bei
OnStoreConnectedrufestore.FetchProducts(List<ProductDefinition>)auf, um den Katalog zu laden - Bei
OnProductsFetchedsind die Produkte bereit zur Anzeige und zum Kauf
Verwende Awake() für die Initialisierung — stellt sicher, dass IAP bereit ist, bevor andere Start()-Methoden ausgeführt werden.
Produkttypen: ProductType.Consumable, ProductType.NonConsumable, ProductType.Subscription.
Produkte abrufen
Definiere Produkte als List<ProductDefinition> und übergib sie an store.FetchProducts(). Verwende StoreSpecificIds, wenn sich Produkt-IDs zwischen Apple/Google-Stores unterscheiden. Verwende für komplexe Kataloge CatalogProvider, um Produktsets und store-spezifische IDs zu verwalten.
| Methode | Verhalten |
|---|---|
GetProducts() | Gibt die zwischengespeicherte Produktliste zurück (synchron, veraltet, wenn FetchProducts nicht aufgerufen wurde) |
FetchProducts() | Fragt den Store nach aktuellen Preisen/Verfügbarkeit und aktualisiert den Cache |
GetProductById(id) | Gibt ein einzelnes zwischengespeichertes Produkt anhand der ID zurück |
Diese sind NICHT austauschbar. Rufe immer zuerst FetchProducts() auf, bevor du dich auf GetProducts() verlässt.
Zweistufiger Kaufablauf
IAP v5 verwendet einen obligatorischen zweistufigen Ablauf: Ausstehend → Bestätigen.
store.PurchaseProduct(product)— startet den Kaufdialog der PlattformOnPurchasePendingwird ausgelöst — du erhältst einePendingOrder- Validiere die Quittung, gewähre dem Spieler den Inhalt
store.ConfirmPurchase(pendingOrder)— schließt die Transaktion abOnPurchaseConfirmedwird ausgelöst — empfängt den BasistypOrder; Mustervergleich mitConfirmedOrder(Erfolg) vs.FailedOrder(Bestätigung fehlgeschlagen)
Du MUSST ConfirmPurchase(pendingOrder) aufrufen, nachdem du den Inhalt gewährt hast. Nicht bestätigte Käufe werden beim nächsten App-Start erneut zugestellt, um verlorene Käufe zu vermeiden.
Deduplizierung: OnPurchasePending kann mehrmals für denselben Kauf ausgelöst werden (z. B. bei Neustart der App vor Bestätigung). Überprüfe immer, ob der Inhalt bereits gewährt wurde.
Verbrauchsgüter: Bestätigte Verbrauchsgüterkäufe werden NICHT von FetchPurchases zurückgegeben. Verwalte die Gewährung von Verbrauchsgütern selbst (z. B. in Cloud Save oder Economy).
Aufgeschobene Käufe: OnPurchaseDeferred wird für Ask-to-Buy (iOS) und aufgeschobene Google Play-Käufe ausgelöst. Gewähre KEINEN Inhalt — warte auf OnPurchasePending, wenn der Kauf genehmigt wurde.
Transaktionen wiederherstellen
store.RestoreTransactions(callback) stellt Dauerkäufe und Abonnements erneut zu. Jeder wiederhergestellte Kauf löst OnPurchasePending aus.
Erforderlich auf iOS für die Einhaltung des Apple App Store — füge einen „Käufe wiederherstellen"-Button hinzu.
Apple-Abonnements ohne Verlängerung (Non-Renewable Subscriptions) können NICHT über RestoreTransactions wiederhergestellt werden. Verfolge diese serverseitig.
Quittungsvalidierung
| Plattform | Ansatz |
|---|---|
| Google Play | CrossPlatformValidator mit GooglePlayTangle.Data() — lokale Validierung unterstützt |
| Apple (StoreKit 2) | Lokale Validierung ist ein No-Op (keine Operation). Verwende order.Info.Apple?.jwsRepresentation für serverseitige Validierung |
Generiere Tangle-Daten über Services > In-App Purchasing > Receipt Validation Obfuscator im Unity Editor.
Berechtigungsprüfung
Verwende dies, wenn du keine Order hast und den Status eines bestimmten Produkts erfahren möchtest (ersetzt product.hasReceipt aus v4). Wenn du bereits die Order hast, überprüfe stattdessen ihren Typ: PendingOrder entspricht EntitledUntilConsumed (Verbrauchsgüter) oder EntitledButNotFinished (Dauerkäufe/Abonnements), ConfirmedOrder entspricht FullyEntitled.
Rufe store.CheckEntitlement(product) auf und verarbeite store.OnCheckEntitlement. Überprüfe entitlement.Status == EntitlementStatus.FullyEntitled.
EntitlementStatus-Werte: FullyEntitled, EntitledUntilConsumed, EntitledButNotFinished, NotEntitled, Unknown.
Vorhandene Käufe abrufen
store.FetchPurchases() ruft alle aktuellen Käufe aus dem Store ab. Nützlich beim App-Start.
| Methode | Verhalten |
|---|---|
GetPurchases() | Gibt die zwischengespeicherte Kaufliste zurück |
FetchPurchases() | Fragt den Store nach aktuellen Käufen ab und überschreibt die zwischengespeicherte Liste |
FetchPurchases() ersetzt bei jedem Aufruf die gesamte zwischengespeicherte Liste. Nur Dauerkäufe und Abonnements werden zurückgegeben.