StoreKit Overview and Retrieving Product Info in Xamarin.iOS
Interfejs użytkownika do zakupu w aplikacji jest wyświetlany na poniższych zrzutach ekranu. Przed rozpoczęciem każdej transakcji aplikacja musi pobrać cenę i opis produktu do wyświetlenia. Następnie po naciśnięciu przycisku Kup aplikacja wysyła żądanie do sklepu StoreKit, które zarządza oknie dialogowym potwierdzenia i identyfikatorem Apple ID. Przy założeniu, że transakcja zakończy się powodzeniem, zestaw StoreKit powiadamia kod aplikacji, który musi przechowywać wynik transakcji i zapewnić użytkownikowi dostęp do zakupu.
Klasy
Implementowanie zakupów w aplikacji wymaga następujących klas z platformy StoreKit:
SKProductsRequest — żądanie sklepu StoreKit dla zatwierdzonych produktów do sprzedaży (App Store). Można skonfigurować przy użyciu wielu identyfikatorów produktów.
- SKProductsRequestDelegate — deklaruje metody obsługi żądań produktów i odpowiedzi.
- SKProductsResponse — odesłanie do delegata ze sklepu StoreKit (App Store). Zawiera elementy SKProducts zgodne z identyfikatorami produktu wysłanymi z żądaniem.
- SKProduct — produkt pobrany z zestawu StoreKit (skonfigurowany w programie iTunes Połączenie). Zawiera informacje o produkcie, takie jak Identyfikator produktu, Tytuł, Opis i Cena.
- SKPayment — utworzono przy użyciu identyfikatora produktu i dodano go do kolejki płatności w celu wykonania zakupu.
- SKPaymentQueue — przesłane do firmy Apple żądania płatności w kolejce. Powiadomienia są wyzwalane w wyniku przetworzenia każdej płatności.
- SKPaymentTransaction — reprezentuje ukończoną transakcję (żądanie zakupu przetworzone przez sklep App Store i wysłane z powrotem do aplikacji za pośrednictwem sklepu StoreKit). Transakcja może zostać zakupiona, przywrócona lub nieudana.
- SKPaymentTransactionObserver — niestandardowa podklasa, która odpowiada na zdarzenia generowane przez kolejkę płatności StoreKit.
- Operacje zestawu StoreKit są asynchroniczne — po uruchomieniu skProductRequest lub do kolejki zostanie dodana skPayment, kontrolka zostanie zwrócona do kodu. Zestaw StoreKit wywoła metody w podklasie SKProductsRequestDelegate lub SKPaymentTransactionObserver, gdy odbiera dane z serwerów firmy Apple.
Na poniższym diagramie przedstawiono relacje między różnymi klasami StoreKit (klasy abstrakcyjne muszą być zaimplementowane w aplikacji):
Te klasy zostały szczegółowo wyjaśnione w dalszej części tego dokumentu.
Testowanie
Większość operacji StoreKit wymaga rzeczywistego urządzenia do testowania. Pobieranie informacji o produkcie (tj. cena i opis) będzie działać w symulatorze, ale operacje zakupu i przywracania zwróci błąd (na przykład FailedTransaction Code=5002 Wystąpił nieznany błąd).
Uwaga: Zestaw StoreKit nie działa w symulatorze systemu iOS. Podczas uruchamiania aplikacji w symulatorze systemu iOS zestaw StoreKit rejestruje ostrzeżenie, jeśli aplikacja próbuje pobrać kolejkę płatności. Testowanie magazynu musi odbywać się na rzeczywistych urządzeniach.
Ważne: nie loguj się przy użyciu konta testowego w aplikacji Ustawienia. Możesz użyć aplikacji Ustawienia, aby wylogować się z dowolnego istniejącego konta Apple ID, a następnie poczekać, aż zostanie wyświetlony monit w ramach sekwencji zakupów w aplikacji, aby zalogować się przy użyciu testowego identyfikatora Apple ID.
Jeśli spróbujesz zalogować się do rzeczywistego sklepu przy użyciu konta testowego, zostanie on automatycznie przekonwertowany na rzeczywisty identyfikator Apple ID. To konto nie będzie już możliwe do użycia do testowania.
Aby przetestować kod StoreKit, musisz wylogować się ze swojego zwykłego konta testowego iTunes i zalogować się przy użyciu specjalnego konta testowego (utworzonego w programie iTunes Połączenie), które jest połączone ze sklepem testowym. Aby wylogować się z bieżącego konta, odwiedź stronę Ustawienia > iTunes i App Store, jak pokazano poniżej:
następnie zaloguj się przy użyciu konta testowego, gdy zażądasz go za pomocą zestawu StoreKit w aplikacji:
Aby utworzyć użytkowników testowych w programie iTunes Połączenie kliknij pozycję Użytkownicy i role na stronie głównej.
Wybieranie testerów piaskownicy
Zostanie wyświetlona lista istniejących użytkowników. Możesz dodać nowego użytkownika lub usunąć istniejący rekord. Portal nie umożliwia obecnie wyświetlania ani edytowania istniejących użytkowników testowych, dlatego zaleca się przechowywanie dobrego rekordu każdego utworzonego użytkownika testowego (zwłaszcza przypisanego hasła). Po usunięciu użytkownika testowego nie można ponownie użyć adresu e-mail dla innego konta testowego.
Nowi użytkownicy testowi mają podobne atrybuty do rzeczywistego identyfikatora Apple ID (takiego jak nazwa, hasło, tajne pytanie i odpowiedź). Zachowaj rekord wszystkich wprowadzonych tutaj szczegółów. W polu Wybierz sklep iTunes Store określi, która waluta i język zakupów w aplikacji będą używane podczas logowania się jako ten użytkownik.
Pobieranie informacji o produkcie
Pierwszym krokiem sprzedaży produktu zakupu w aplikacji jest jego wyświetlenie: pobieranie bieżącej ceny i opisu ze sklepu App Store w celu wyświetlenia.
Niezależnie od tego, jakiego typu produkty sprzedaje aplikacja (Eksploatacyjne, Nieożywne lub Typ subskrypcji), proces pobierania informacji o produkcie do wyświetlenia jest taki sam. Kod InAppPurchaseSample, który towarzyszy temu artykułowi, zawiera projekt o nazwie Eksploatacyjne , który pokazuje sposób pobierania informacji produkcyjnych na potrzeby wyświetlania. Pokazano w nim, jak:
- Utwórz implementację metody abstrakcyjnej
SKProductsRequestDelegate
i zaimplementuj metodę abstrakcyjnąReceivedResponse
. Przykładowy kod wywołuje tę klasęInAppPurchaseManager
. - Sprawdź zestaw StoreKit, aby sprawdzić, czy płatności są dozwolone (przy użyciu metody
SKPaymentQueue.CanMakePayments
). - Utwórz wystąpienie
SKProductsRequest
elementu przy użyciu identyfikatorów produktów zdefiniowanych w programie iTunes Połączenie. Jest to wykonywane w metodzie przykładuInAppPurchaseManager.RequestProductData
. - Wywołaj metodę Start w obiekcie
SKProductsRequest
. Spowoduje to wywołanie asynchroniczne na serwerach ze sklepu App Store. Delegat (InAppPurchaseManager
) zostanie wywołany z powrotem z wynikami. - Metoda Delegata (
InAppPurchaseManager
)ReceivedResponse
aktualizuje interfejs użytkownika przy użyciu danych zwracanych ze sklepu App Store (ceny produktów i opisy lub komunikaty dotyczące nieprawidłowych produktów).
Ogólna interakcja wygląda następująco ( StoreKit jest wbudowany w system iOS, a sklep App Store reprezentuje serwery firmy Apple):
Przykład wyświetlania informacji o produkcie
Przykładowy kod eksploatacyjnych pokazuje sposób pobierania informacji o produkcie. Na głównym ekranie przykładu są wyświetlane informacje dotyczące dwóch produktów pobranych ze sklepu App Store:
Przykładowy kod umożliwiający pobranie i wyświetlenie informacji o produkcie zostało wyjaśnione bardziej szczegółowo poniżej.
ViewController, metody
Klasa ConsumableViewController
będzie zarządzać wyświetlaniem cen dla dwóch produktów, których identyfikatory produktów są zakodowane na stałe w klasie.
public static string Buy5ProductId = "com.xamarin.storekit.testing.consume5credits",
Buy10ProductId = "com.xamarin.storekit.testing.consume10credits";
List<string> products;
InAppPurchaseManager iap;
public ConsumableViewController () : base()
{
// two products for sale on this page
products = new List<string>() {Buy5ProductId, Buy10ProductId};
iap = new InAppPurchaseManager();
}
Na poziomie klasy powinien być również zadeklarowany obiekt NSObject, który będzie używany do konfigurowania obserwatora NSNotificationCenter
:
NSObject priceObserver;
W metodzie ViewWillAppear obserwator jest tworzony i przypisywany przy użyciu domyślnego centrum powiadomień:
priceObserver = NSNotificationCenter.DefaultCenter.AddObserver (
InAppPurchaseManager.InAppPurchaseManagerProductsFetchedNotification,
(notification) => {
// display code goes here, to handle the response from the App Store
}
Na końcu ViewWillAppear
metody wywołaj metodę RequestProductData
, aby zainicjować żądanie StoreKit. Po utworzeniu tego żądania zestaw StoreKit asynchronicznie skontaktuje się z serwerami firmy Apple, aby uzyskać informacje i podawać je z powrotem do aplikacji. Jest to osiągane przez podklasę SKProductsRequestDelegate
( InAppPurchaseManager
), która jest wyjaśniona w następnej sekcji.
iap.RequestProductData(products);
Kod wyświetlający cenę i opis po prostu pobiera informacje ze skProduct i przypisuje je do kontrolek UIKit (zwróć uwagę, że wyświetlamy LocalizedTitle
element i LocalizedDescription
— StoreKit automatycznie rozpoznaje prawidłowy tekst i ceny na podstawie ustawień konta użytkownika). Poniższy kod należy do utworzonego powyżej powiadomienia:
priceObserver = NSNotificationCenter.DefaultCenter.AddObserver (
InAppPurchaseManager.InAppPurchaseManagerProductsFetchedNotification,
(notification) => {
// display code goes here, to handle the response from the App Store
var info = notification.UserInfo;
if (info.ContainsKey(NSBuy5ProductId)) {
var product = (SKProduct) info.ObjectForKey(NSBuy5ProductId);
buy5Button.Enabled = true;
buy5Title.Text = product.LocalizedTitle;
buy5Description.Text = product.LocalizedDescription;
buy5Button.SetTitle("Buy " + product.Price, UIControlState.Normal); // price display should be localized
}
}
ViewWillDisappear
Na koniec metoda powinna zapewnić usunięcie obserwatora:
NSNotificationCenter.DefaultCenter.RemoveObserver (priceObserver);
METODY SKProductRequestDelegate (InAppPurchaseManager)
Metoda jest wywoływana RequestProductData
, gdy aplikacja chce pobrać ceny produktów i inne informacje. Analizuje ona kolekcję identyfikatorów produktu w prawidłowy typ danych, a następnie tworzy element SKProductsRequest
z informacjami. Wywołanie metody Start powoduje wysyłanie żądania sieciowego do serwerów firmy Apple. Żądanie zostanie uruchomione asynchronicznie i wywoła ReceivedResponse
metodę delegata po pomyślnym zakończeniu.
public void RequestProductData (List<string> productIds)
{
var array = new NSString[productIds.Count];
for (var i = 0; i < productIds.Count; i++) {
array[i] = new NSString(productIds[i]);
}
NSSet productIdentifiers = NSSet.MakeNSObjectSet<NSString>(array);
productsRequest = new SKProductsRequest(productIdentifiers);
productsRequest.Delegate = this; // for SKProductsRequestDelegate.ReceivedResponse
productsRequest.Start();
}
System iOS automatycznie wyśle żądanie do wersji "piaskownicy" lub "produkcyjnej" sklepu App Store w zależności od profilu aprowizacji uruchomionego przez aplikację — więc podczas tworzenia lub testowania aplikacji żądanie będzie miało dostęp do każdego produktu skonfigurowanego w programie iTunes Połączenie (nawet tych, które nie zostały jeszcze przesłane lub zatwierdzone przez firmę Apple). Gdy aplikacja jest w środowisku produkcyjnym, żądania StoreKit będą zwracać tylko informacje dotyczące zatwierdzonych produktów.
Metoda ReceivedResponse
przesłonięta jest wywoływana po tym, jak serwery firmy Apple odpowiedziały danymi. Ponieważ jest to wywoływane w tle, kod powinien przeanalizować prawidłowe dane i użyć powiadomienia, aby wysłać informacje o produkcie do dowolnych kontrolek ViewControllers, które "nasłuchiwanie" dla tego powiadomienia. Poniższy kod do zbierania prawidłowych informacji o produkcie i wysyłania powiadomienia:
public override void ReceivedResponse (SKProductsRequest request, SKProductsResponse response)
{
SKProduct[] products = response.Products;
NSDictionary userInfo = null;
if (products.Length > 0) {
NSObject[] productIdsArray = new NSObject[response.Products.Length];
NSObject[] productsArray = new NSObject[response.Products.Length];
for (int i = 0; i < response.Products.Length; i++) {
productIdsArray[i] = new NSString(response.Products[i].ProductIdentifier);
productsArray[i] = response.Products[i];
}
userInfo = NSDictionary.FromObjectsAndKeys (productsArray, productIdsArray);
}
NSNotificationCenter.DefaultCenter.PostNotificationName (InAppPurchaseManagerProductsFetchedNotification, this, userInfo);
}
Chociaż nie pokazano na diagramie, RequestFailed
metoda powinna zostać również zastąpiona, aby można było przekazać użytkownikowi opinię na wypadek, gdyby serwery ze sklepu App Store nie są osiągalne (lub wystąpił inny błąd). Przykładowy kod tylko zapisuje w konsoli, ale prawdziwa aplikacja może zdecydować się na wykonanie zapytania względem error.Code
właściwości i zaimplementowanie zachowania niestandardowego (na przykład alertu dla użytkownika).
public override void RequestFailed (SKRequest request, NSError error)
{
Console.WriteLine (" ** InAppPurchaseManager RequestFailed() " + error.LocalizedDescription);
}
Ten zrzut ekranu przedstawia przykładową aplikację natychmiast po załadowaniu (jeśli nie są dostępne żadne informacje o produkcie):
Nieprawidłowe produkty
Element SKProductsRequest
może również zwrócić listę nieprawidłowych identyfikatorów produktów. Nieprawidłowe produkty są zwykle zwracane z powodu jednego z następujących elementów:
Identyfikator produktu został błędnie wtypowany — akceptowane są tylko prawidłowe identyfikatory produktów.
Produkt nie został zatwierdzony — podczas testowania wszystkie produkty, które zostały wyczyszczone do sprzedaży, powinny być zwracane przez obiekt SKProductsRequest
; jednak w środowisku produkcyjnym zwracane są tylko zatwierdzone produkty.
Identyfikator aplikacji nie jest jawny — identyfikatory aplikacji wieloznacznych (z gwiazdką) nie zezwalają na zakup w aplikacji.
Nieprawidłowy profil aprowizacji — jeśli wprowadzisz zmiany w konfiguracji aplikacji w portalu aprowizacji (np. włączanie zakupów w aplikacji), pamiętaj o ponownym wygenerowaniu i użyciu poprawnego profilu aprowizacji podczas kompilowania aplikacji.
Nie ma umowy płatnej aplikacji dla systemu iOS — funkcje StoreKit nie będą działać w ogóle, chyba że istnieje prawidłowa umowa dla Konta dewelopera Apple.
Plik binarny jest w stanie Odrzucone — jeśli w stanie Odrzucono (przez zespół sklepu App Store lub przez dewelopera) istnieje wcześniej przesłany plik binarny, funkcje StoreKit nie będą działać.
Metoda ReceivedResponse
w przykładowym kodzie zwraca nieprawidłowe produkty do konsoli:
public override void ReceivedResponse (SKProductsRequest request, SKProductsResponse response)
{
// code removed for clarity
foreach (string invalidProductId in response.InvalidProducts) {
Console.WriteLine("Invalid product id: " + invalidProductId );
}
}
Wyświetlanie zlokalizowanych cen
Warstwy cenowe określają określoną cenę dla każdego produktu we wszystkich międzynarodowych sklepach App Store. Aby upewnić się, że ceny są wyświetlane poprawnie dla każdej waluty, użyj następującej metody rozszerzenia (zdefiniowanej w pliku SKProductExtension.cs
) zamiast właściwości Price każdego SKProduct
elementu :
public static class SKProductExtension {
public static string LocalizedPrice (this SKProduct product)
{
var formatter = new NSNumberFormatter ();
formatter.FormatterBehavior = NSNumberFormatterBehavior.Version_10_4;
formatter.NumberStyle = NSNumberFormatterStyle.Currency;
formatter.Locale = product.PriceLocale;
var formattedString = formatter.StringFromNumber(product.Price);
return formattedString;
}
}
Kod ustawiający tytuł przycisku używa metody rozszerzenia w następujący sposób:
string Buy = "Buy {0}"; // or a localizable string
buy5Button.SetTitle(String.Format(Buy, product.LocalizedPrice()), UIControlState.Normal);
Użycie dwóch różnych kont testowych iTunes (jeden dla amerykańskiego sklepu i jeden dla japońskiego sklepu) powoduje wykonanie następujących zrzutów ekranu:
Zwróć uwagę, że sklep ma wpływ na język używany na potrzeby informacji o produkcie i walucie cen, podczas gdy ustawienie języka urządzenia wpływa na etykiety i inną zlokalizowaną zawartość.
Pamiętaj, że aby użyć innego konta testowego sklepu, musisz wylogować się w Ustawienia > iTunes i App Store i ponownie uruchomić aplikację, aby zalogować się przy użyciu innego konta. Aby zmienić język urządzenia, przejdź do Ustawienia > Ogólne > języki międzynarodowe>.