Kauf von Verbrauchsartikeln in Xamarin.iOS
Verbrauchsartikel sind am einfachsten zu implementieren, da es keine "Wiederherstellungsanforderung" gibt. Sie sind nützlich für Produkte wie In-Game-Währungen oder ein einmaliges Funktionalitätsstück. Benutzer können Verbrauchsartikel immer wieder kaufen.
Integrierte Produktbereitstellung
Der Beispielcode, der dieses Dokument begleitet, veranschaulicht integrierte Produkte – die Produkt-IDs sind in der Anwendung hartcodiert, da sie eng mit dem Code gekoppelt sind, der das Feature nach der Zahlung "entsperrt". Der Einkaufsprozess kann wie folgt dargestellt werden:
Der grundlegende Workflow lautet:
Die App fügt der Warteschlange eine
SKPayment
hinzu. Falls erforderlich, wird der Benutzer zur Eingabe seiner Apple-ID aufgefordert und zur Bestätigung der Zahlung aufgefordert.StoreKit sendet die Anforderung zur Verarbeitung an den Server.
Wenn die Transaktion abgeschlossen ist, antwortet der Server mit einem Transaktionsbeleg.
Die
SKPaymentTransactionObserver
Unterklasse empfängt den Beleg und verarbeitet sie.Die Anwendung aktiviert das Produkt (durch Aktualisieren
NSUserDefaults
oder einen anderen Mechanismus), und ruft dann StoreKitsFinishTransaction
auf.
Es gibt einen anderen Workflowtyp – Server-Zugestellte Produkte – die weiter unten im Dokument erläutert werden (siehe Abschnitt Belegüberprüfung und Server-Zugestellte Produkte).
Beispiel für Verbrauchsartikel
Das Beispiel enthält ein Projekt namens Verbrauchsartikel , das eine grundlegende "Spielwährung" (als "Affenguthaben" bezeichnet) implementiert. Das Beispiel zeigt, wie zwei In-App-Kaufprodukte implementiert werden, damit der Benutzer so viele "Affenguthaben" wie gewünscht kaufen kann – in einer echten Anwendung würde es auch eine Möglichkeit geben, sie auszugeben!
Die Anwendung wird in diesen Screenshots angezeigt – jeder Kauf fügt dem Guthaben des Benutzers weitere "Affenguthaben" hinzu:
Die Interaktionen zwischen benutzerdefinierten Klassen, StoreKit und dem App Store sehen wie folgt aus:
ViewController-Methoden
Zusätzlich zu den Eigenschaften und Methoden, die zum Abrufen von Produktinformationen erforderlich sind, benötigt der Ansichtscontroller zusätzliche Benachrichtigungsbeobachter, um kaufbezogene Benachrichtigungen abzuhören. Dies sind nur NSObjects
dies, die in ViewWillAppear
bzw ViewWillDisappear
. entfernt werden.
NSObject succeededObserver, failedObserver;
Der Konstruktor erstellt außerdem die SKProductsRequestDelegate
Unterklasse ( InAppPurchaseManager
), die wiederum erstellt und registriert die SKPaymentTransactionObserver
( CustomPaymentObserver
).
Der erste Teil der Verarbeitung einer In-App-Kauftransaktion besteht darin, die Taste zu verarbeiten, wenn der Benutzer etwas kaufen möchte, wie im folgenden Code aus der Beispielanwendung gezeigt:
buy5Button.TouchUpInside += (sender, e) => {
iap.PurchaseProduct (Buy5ProductId);
};
buy10Button.TouchUpInside += (sender, e) => {
iap.PurchaseProduct (Buy10ProductId);
};
Der zweite Teil der Benutzeroberfläche behandelt die Benachrichtigung, dass die Transaktion erfolgreich war, in diesem Fall durch Aktualisieren des angezeigten Saldos:
succeededObserver = NSNotificationCenter.DefaultCenter.AddObserver (InAppPurchaseManager.InAppPurchaseManagerTransactionSucceededNotification,
(notification) => {
balanceLabel.Text = CreditManager.Balance() + " monkey credits";
});
Der letzte Teil der Benutzeroberfläche zeigt eine Meldung an, wenn eine Transaktion aus irgendeinem Grund abgebrochen wird. Im Beispielcode wird eine Nachricht einfach in das Ausgabefenster geschrieben:
failedObserver = NSNotificationCenter.DefaultCenter.AddObserver (InAppPurchaseManager.InAppPurchaseManagerTransactionFailedNotification,
(notification) => {
Console.WriteLine ("Transaction Failed");
});
Zusätzlich zu diesen Methoden auf dem Ansichtscontroller erfordert eine Verbrauchsproduktkauftransaktion auch Code für die SKProductsRequestDelegate
und die SKPaymentTransactionObserver
.
InAppPurchaseManager-Methoden
Der Beispielcode implementiert eine Reihe von einkaufsbezogenen Methoden für die InAppPurchaseManager-Klasse, einschließlich der Methode, mit der PurchaseProduct
eine SKPayment
Instanz erstellt wird, und fügt sie zur Verarbeitungswarteschlange hinzu:
public void PurchaseProduct(string appStoreProductId)
{
SKPayment payment = SKPayment.PaymentWithProduct (appStoreProductId);
SKPaymentQueue.DefaultQueue.AddPayment (payment);
}
Das Hinzufügen der Zahlung zur Warteschlange ist ein asynchroner Vorgang. Die Anwendung erhält die Kontrolle wieder, während StoreKit die Transaktion verarbeitet und an die Server von Apple sendet. An diesem Punkt überprüft iOS, ob der Benutzer beim App Store angemeldet ist, und fordert ihn bei Bedarf zur Eingabe einer Apple-ID und eines Kennworts auf.
Wenn sich der Benutzer erfolgreich beim App Store authentifiziert und der Transaktion zustimmt, empfängt der SKPaymentTransactionObserver
StoreKit die Antwort und ruft die folgende Methode auf, um die Transaktion zu erfüllen und abzuschließen.
public void CompleteTransaction (SKPaymentTransaction transaction)
{
var productId = transaction.Payment.ProductIdentifier;
// Register the purchase, so it is remembered for next time
PhotoFilterManager.Purchase(productId);
FinishTransaction(transaction, true);
}
Der letzte Schritt besteht darin, sicherzustellen, dass Sie StoreKit benachrichtigen, dass Sie die Transaktion erfolgreich erfüllt haben, indem Sie folgendes aufrufen FinishTransaction
:
public void FinishTransaction(SKPaymentTransaction transaction, bool wasSuccessful)
{
// remove the transaction from the payment queue.
SKPaymentQueue.DefaultQueue.FinishTransaction(transaction); // THIS IS IMPORTANT - LET'S APPLE KNOW WE'RE DONE !!!!
using (var pool = new NSAutoreleasePool()) {
NSDictionary userInfo = NSDictionary.FromObjectsAndKeys(new NSObject[] {transaction},new NSObject[] {new NSString("transaction")});
if (wasSuccessful) {
// send out a notification that we've finished the transaction
NSNotificationCenter.DefaultCenter.PostNotificationName (InAppPurchaseManagerTransactionSucceededNotification, this, userInfo);
} else {
// send out a notification for the failed transaction
NSNotificationCenter.DefaultCenter.PostNotificationName (InAppPurchaseManagerTransactionFailedNotification, this, userInfo);
}
}
}
Nachdem das Produkt geliefert wurde, muss aufgerufen werden, SKPaymentQueue.DefaultQueue.FinishTransaction
um die Transaktion aus der Zahlungswarteschlange zu entfernen.
SKPaymentTransactionObserver (CustomPaymentObserver)-Methoden
StoreKit ruft die UpdatedTransactions
Methode auf, wenn sie eine Antwort von Apple-Servern empfängt, und übergibt ein Array von SKPaymentTransaction
Objekten für ihren Code zu prüfen. Die Methode durchläuft jede Transaktion und führt eine andere Funktion basierend auf dem Transaktionsstatus aus (wie hier gezeigt):
public override void UpdatedTransactions (SKPaymentQueue queue, SKPaymentTransaction[] transactions)
{
foreach (SKPaymentTransaction transaction in transactions)
{
switch (transaction.TransactionState)
{
case SKPaymentTransactionState.Purchased:
theManager.CompleteTransaction(transaction);
break;
case SKPaymentTransactionState.Failed:
theManager.FailedTransaction(transaction);
break;
default:
break;
}
}
}
Die CompleteTransaction
Methode wurde weiter oben in diesem Abschnitt behandelt – sie speichert die Kaufdetails in NSUserDefaults
, schließt die Transaktion mit StoreKit ab und benachrichtigt die Benutzeroberfläche schließlich, um die Aktualisierung zu aktualisieren.
Kauf mehrerer Produkte
Wenn es in Ihrer Anwendung sinnvoll ist, mehrere Produkte zu kaufen, verwenden Sie die SKMutablePayment
Klasse, und legen Sie das Feld "Menge" fest:
public void PurchaseProduct(string appStoreProductId)
{
SKMutablePayment payment = SKMutablePayment.PaymentWithProduct (appStoreProductId);
payment.Quantity = 4; // hardcoded as an example
SKPaymentQueue.DefaultQueue.AddPayment (payment);
}
Der Code, der die abgeschlossene Transaktion verarbeitet, muss auch die Eigenschaft "Quantity" abfragen, um den Kauf ordnungsgemäß zu erfüllen:
public void CompleteTransaction (SKPaymentTransaction transaction)
{
var productId = transaction.Payment.ProductIdentifier;
var qty = transaction.Payment.Quantity;
if (productId == ConsumableViewController.Buy5ProductId)
CreditManager.Add(5 * qty);
else if (productId == ConsumableViewController.Buy10ProductId)
CreditManager.Add(10 * qty);
else
Console.WriteLine ("Shouldn't happen, there are only two products");
FinishTransaction(transaction, true);
}
Wenn der Benutzer mehrere Mengen kauft, gibt die StoreKit-Bestätigungsbenachrichtigung die Menge, den Einzelpreis und den Gesamtpreis an, den er in Rechnung gestellt wird, wie im folgenden Screenshot gezeigt:
Behandeln von Netzwerkausfällen
In-App-Käufe erfordern eine funktionierende Netzwerkverbindung für StoreKit, um mit den Servern von Apple zu kommunizieren. Wenn keine Netzwerkverbindung verfügbar ist, steht der In-App-Kauf nicht zur Verfügung.
Produktanforderungen
Wenn das Netzwerk beim Erstellen einer SKProductRequest
Klasse nicht verfügbar ist, wird die RequestFailed
Methode der SKProductsRequestDelegate
Unterklasse ( InAppPurchaseManager
) aufgerufen, wie unten dargestellt:
public override void RequestFailed (SKRequest request, NSError error)
{
using (var pool = new NSAutoreleasePool()) {
NSDictionary userInfo = NSDictionary.FromObjectsAndKeys(new NSObject[] {error},new NSObject[] {new NSString("error")});
// send out a notification for the failed transaction
NSNotificationCenter.DefaultCenter.PostNotificationName (InAppPurchaseManagerRequestFailedNotification, this, userInfo);
}
}
Der ViewController lauscht dann auf die Benachrichtigung und zeigt eine Meldung in den Kaufschaltflächen an:
requestObserver = NSNotificationCenter.DefaultCenter.AddObserver (InAppPurchaseManager.InAppPurchaseManagerRequestFailedNotification,
(notification) => {
Console.WriteLine ("Request Failed");
buy5Button.SetTitle ("Network down?", UIControlState.Disabled);
buy10Button.SetTitle ("Network down?", UIControlState.Disabled);
});
Da eine Netzwerkverbindung auf mobilen Geräten vorübergehend sein kann, können Anwendungen den Netzwerkstatus mithilfe des SystemConfiguration-Frameworks überwachen und es erneut versuchen, wenn eine Netzwerkverbindung verfügbar ist. Verweisen Sie auf Apples oder die Verwendung.
Kauftransaktionen
Die StoreKit-Zahlungswarteschlange speichert und leitet Einkaufsanfragen nach Möglichkeit weiter, sodass die Auswirkungen eines Netzwerkausfalls abhängig davon variieren, wann das Netzwerk während des Kaufvorgangs fehlgeschlagen ist.
Wenn während einer Transaktion ein Fehler auftritt, hat die SKPaymentTransactionObserver
Unterklasse ( CustomPaymentObserver
) die UpdatedTransactions
Methode aufgerufen, und die SKPaymentTransaction
Klasse befindet sich im Status "Fehlgeschlagen".
public override void UpdatedTransactions (SKPaymentQueue queue, SKPaymentTransaction[] transactions)
{
foreach (SKPaymentTransaction transaction in transactions)
{
switch (transaction.TransactionState)
{
case SKPaymentTransactionState.Purchased:
theManager.CompleteTransaction(transaction);
break;
case SKPaymentTransactionState.Failed:
theManager.FailedTransaction(transaction);
break;
default:
break;
}
}
}
Die FailedTransaction
Methode erkennt, ob der Fehler aufgrund eines Benutzerabbruchs aufgetreten ist, wie hier gezeigt:
public void FailedTransaction (SKPaymentTransaction transaction)
{
//SKErrorPaymentCancelled == 2
if (transaction.Error.Code == 2) // user cancelled
Console.WriteLine("User CANCELLED FailedTransaction Code=" + transaction.Error.Code + " " + transaction.Error.LocalizedDescription);
else // error!
Console.WriteLine("FailedTransaction Code=" + transaction.Error.Code + " " + transaction.Error.LocalizedDescription);
FinishTransaction(transaction,false);
}
Auch wenn eine Transaktion fehlschlägt, muss die FinishTransaction
Methode aufgerufen werden, um die Transaktion aus der Zahlungswarteschlange zu entfernen:
SKPaymentQueue.DefaultQueue.FinishTransaction(transaction);
Der Beispielcode sendet dann eine Benachrichtigung, sodass der ViewController eine Meldung anzeigen kann. Anwendungen sollten keine zusätzliche Meldung anzeigen, wenn der Benutzer die Transaktion abgebrochen hat. Weitere Fehlercodes, die auftreten können, sind:
FailedTransaction Code=0 Cannot connect to iTunes Store
FailedTransaction Code=5002 An unknown error has occurred
FailedTransaction Code=5020 Forget Your Password?
Applications may detect and respond to specific error codes, or handle them in the same way.
Behandeln von Einschränkungen
Mit dem Feature "Einstellungen > allgemeine > Einschränkungen" von iOS können Benutzer bestimmte Features ihres Geräts sperren.
Sie können abfragen, ob der Benutzer In-App-Käufe über die SKPaymentQueue.CanMakePayments
Methode tätigen darf. Wenn dies "false" zurückgibt, kann der Benutzer nicht auf den In-App-Einkauf zugreifen. StoreKit zeigt dem Benutzer automatisch eine Fehlermeldung an, wenn ein Kauf versucht wird. Durch Überprüfen dieses Werts kann Ihre Anwendung stattdessen die Kaufschaltflächen ausblenden oder eine andere Aktion ausführen, um dem Benutzer zu helfen.
In der InAppPurchaseManager.cs
Datei umschließt die CanMakePayments
Methode die StoreKit-Funktion wie folgt:
public bool CanMakePayments()
{
return SKPaymentQueue.CanMakePayments;
}
Verwenden Sie zum Testen dieser Methode das Feature "Einschränkungen" von iOS, um In-App-Käufe zu deaktivieren:
Dieser Beispielcode von ConsumableViewController
reacts to CanMakePayments
returning false by displaying AppStore Disabled text on the disabled buttons.
// only if we can make payments, request the prices
if (iap.CanMakePayments()) {
// now go get prices, if we don't have them already
if (!pricesLoaded)
iap.RequestProductData(products); // async request via StoreKit -> App Store
} else {
// can't make payments (purchases turned off in Settings?)
// the buttons are disabled by default, and only enabled when prices are retrieved
buy5Button.SetTitle ("AppStore disabled", UIControlState.Disabled);
buy10Button.SetTitle ("AppStore disabled", UIControlState.Disabled);
}
Die Anwendung sieht so aus, wenn das Feature " In-App-Käufe " eingeschränkt ist – die Kaufschaltflächen sind deaktiviert.
Produktinformationen können weiterhin angefordert werden, wenn CanMakePayments
"false" ist, sodass die App weiterhin Preise abrufen und anzeigen kann. Dies bedeutet, dass, wenn wir die CanMakePayments
Überprüfung aus dem Code entfernt haben, die Kaufschaltflächen weiterhin aktiv sind, aber wenn ein Kauf versucht wird, wird dem Benutzer eine Meldung angezeigt, dass In-App-Käufe nicht zulässig sind (generiert durch StoreKit, wenn auf die Zahlungswarteschlange zugegriffen wird):
Reale Anwendungen können einen anderen Ansatz für die Behandlung der Einschränkung haben, z. B. das Ausblenden der Schaltflächen insgesamt und vielleicht eine detailliertere Meldung als die Warnung, die Von StoreKit automatisch angezeigt wird.