Panoramica e recupero di informazioni sul prodotto StoreKit in Xamarin.iOS
L'interfaccia utente per un acquisto in-app è illustrata negli screenshot seguenti. Prima che si verifichi una transazione, l'applicazione deve recuperare il prezzo e la descrizione del prodotto per la visualizzazione. Quindi, quando l'utente preme Acquista, l'applicazione effettua una richiesta a StoreKit che gestisce la finestra di dialogo di conferma e l'account di accesso id Apple. Supponendo che la transazione abbia esito positivo, StoreKit invia una notifica al codice dell'applicazione, che deve archiviare il risultato della transazione e fornire all'utente l'accesso al proprio acquisto.
Classi
L'implementazione degli acquisti in-app richiede le classi seguenti del framework StoreKit:
SKProductsRequest : richiesta a StoreKit per i prodotti approvati da vendere (App Store). Può essere configurato con un numero di ID prodotto.
- SKProductsRequestDelegate : dichiara i metodi per gestire le richieste e le risposte dei prodotti.
- SKProductsResponse : inviato di nuovo al delegato da StoreKit (App Store). Contiene gli SKUProduct che corrispondono agli ID prodotto inviati con la richiesta.
- SKProduct: prodotto recuperato da StoreKit (configurato in iTunes Connessione). Contiene informazioni sul prodotto, ad esempio ID prodotto, Titolo, Descrizione e Prezzo.
- SKPayment : creato con un ID prodotto e aggiunto alla coda di pagamento per eseguire un acquisto.
- SKPaymentQueue : richieste di pagamento in coda da inviare ad Apple. Le notifiche vengono attivate in seguito all'elaborazione di ogni pagamento.
- SKPaymentTransaction : rappresenta una transazione completata (una richiesta di acquisto che è stata elaborata dall'App Store e inviata all'applicazione tramite StoreKit). La transazione può essere acquistata, ripristinata o non riuscita.
- SKPaymentTransactionObserver : sottoclasse personalizzata che risponde agli eventi generati dalla coda di pagamento StoreKit.
- Le operazioni StoreKit sono asincrone : dopo l'avvio di un SKProductRequest o l'aggiunta di un SKPayment alla coda, il controllo viene restituito al codice. StoreKit chiamerà i metodi nella sottoclasse SKProductsRequestDelegate o SKPaymentTransactionObserver quando riceve i dati dai server Apple.
Il diagramma seguente illustra le relazioni tra le varie classi StoreKit (le classi astratte devono essere implementate nell'applicazione):
Queste classi sono illustrate in modo più dettagliato più avanti in questo documento.
Test in corso
La maggior parte delle operazioni StoreKit richiede un dispositivo reale per i test. Il recupero delle informazioni sul prodotto (ad esempio prezzo e descrizione) funzionerà nel simulatore, ma le operazioni di acquisto e ripristino restituiranno un errore (ad esempio FailedTransaction Code=5002 Si è verificato un errore sconosciuto).
Nota: StoreKit non funziona nel simulatore iOS. Quando si esegue l'applicazione nel simulatore iOS, StoreKit registra un avviso se l'applicazione tenta di recuperare la coda di pagamento. Il test dell'archivio deve essere eseguito sui dispositivi effettivi.
Importante: non accedere con l'account di test nell'applicazione Impostazioni. È possibile usare l'applicazione Impostazioni per disconnettersi da qualsiasi account ID Apple esistente, quindi è necessario attendere che venga richiesto all'interno della sequenza di acquisto in-app di accedere usando un ID Apple di test.
Se si tenta di accedere al negozio reale con un account di test, verrà convertito automaticamente in un ID Apple reale. L'account non sarà più utilizzabile per i test.
Per testare il codice StoreKit è necessario disconnettersi dal normale account di test di iTunes e accedere con un account di test speciale (creato in iTunes Connessione) collegato all'archivio di test. Per disconnettersi dall'account corrente, visitare Impostazioni > iTunes e App Store, come illustrato di seguito:
quindi accedere con un account di test quando richiesto da StoreKit all'interno dell'app:
Per creare utenti di test in iTunes Connessione fare clic su Utenti e ruoli nella pagina principale.
Selezionare Tester sandbox
Viene visualizzato l'elenco degli utenti esistenti. È possibile aggiungere un nuovo utente o eliminare un record esistente. Il portale non consente (attualmente) di visualizzare o modificare gli utenti di test esistenti, pertanto è consigliabile mantenere un buon record di ogni utente di test creato (in particolare la password assegnata). Dopo aver eliminato un utente di test, l'indirizzo di posta elettronica non può essere riutilizzato per un altro account di test.
I nuovi utenti di test hanno attributi simili a un ID Apple reale,ad esempio nome, password, domanda segreta e risposta. Mantenere un record di tutti i dettagli immessi qui. Il campo Seleziona iTunes Store determinerà quale valuta e lingua useranno gli acquisti in-app al momento dell'accesso come tale utente.
Recupero delle informazioni sul prodotto
Il primo passaggio nella vendita di un prodotto di acquisto in-app è visualizzarlo: recuperando il prezzo corrente e la descrizione dall'App Store per la visualizzazione.
Indipendentemente dal tipo di prodotti venduti da un'app (Consumabile, Non consumabile o tipo di sottoscrizione), il processo di recupero delle informazioni sul prodotto per la visualizzazione è lo stesso. Il codice InAppPurchaseSample che accompagna questo articolo contiene un progetto denominato Consumables che illustra come recuperare le informazioni di produzione per la visualizzazione. Illustra come:
- Creare un'implementazione di
SKProductsRequestDelegate
e implementare ilReceivedResponse
metodo astratto. Il codice di esempio chiama questaInAppPurchaseManager
classe. - Controllare con StoreKit per verificare se i pagamenti sono consentiti (usando
SKPaymentQueue.CanMakePayments
). - Creare un'istanza
SKProductsRequest
di con gli ID prodotto definiti in iTunes Connessione. Questa operazione viene eseguita nel metodo dell'esempioInAppPurchaseManager.RequestProductData
. - Chiamare il metodo Start in
SKProductsRequest
. In questo modo viene attivata una chiamata asincrona ai server dell'App Store. Il delegato (InAppPurchaseManager
) verrà richiamato con i risultati. - Il metodo Delegate (
InAppPurchaseManager
)ReceivedResponse
aggiorna l'interfaccia utente con i dati restituiti dall'App Store (prezzi e descrizioni dei prodotti o messaggi relativi a prodotti non validi).
L'interazione complessiva è simile alla seguente ( StoreKit è integrato in iOS e l'App Store rappresenta i server Apple):
Esempio di visualizzazione delle informazioni sul prodotto
Il codice di esempio Di consumo illustra come recuperare le informazioni sul prodotto. La schermata principale dell'esempio visualizza le informazioni per due prodotti recuperati dall'App Store:
Il codice di esempio per recuperare e visualizzare le informazioni sul prodotto è illustrato più dettagliatamente di seguito.
Metodi ViewController
La ConsumableViewController
classe gestirà la visualizzazione dei prezzi per due prodotti i cui ID prodotto sono hardcoded nella classe .
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();
}
A livello di classe deve essere presente anche un NSObject dichiarato che verrà usato per configurare un NSNotificationCenter
osservatore:
NSObject priceObserver;
Nel metodo ViewWillAppear l'osservatore viene creato e assegnato usando il centro notifiche predefinito:
priceObserver = NSNotificationCenter.DefaultCenter.AddObserver (
InAppPurchaseManager.InAppPurchaseManagerProductsFetchedNotification,
(notification) => {
// display code goes here, to handle the response from the App Store
}
Alla fine del ViewWillAppear
metodo chiamare il RequestProductData
metodo per avviare la richiesta StoreKit. Dopo aver effettuato questa richiesta, StoreKit contatterà in modo asincrono i server apple per ottenere le informazioni e inviare le informazioni all'app. Questa operazione viene ottenuta dalla SKProductsRequestDelegate
sottoclasse ( InAppPurchaseManager
) illustrata nella sezione successiva.
iap.RequestProductData(products);
Il codice per visualizzare il prezzo e la descrizione recupera semplicemente le informazioni dal prodotto SKProduct e lo assegna ai controlli UIKit ( si noti che viene visualizzato LocalizedTitle
e LocalizedDescription
- StoreKit risolve automaticamente il testo e i prezzi corretti in base alle impostazioni dell'account dell'utente). Il codice seguente appartiene alla notifica creata in precedenza:
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
}
}
Infine, il ViewWillDisappear
metodo deve assicurarsi che l'osservatore venga rimosso:
NSNotificationCenter.DefaultCenter.RemoveObserver (priceObserver);
Metodi SKProductRequestDelegate (InAppPurchaseManager)
Il RequestProductData
metodo viene chiamato quando l'applicazione desidera recuperare i prezzi dei prodotti e altre informazioni. Analizza la raccolta di ID prodotto nel tipo di dati corretto e quindi crea un oggetto SKProductsRequest
con tali informazioni. La chiamata al metodo Start determina l'esecuzione di una richiesta di rete ai server Apple. La richiesta verrà eseguita in modo asincrono e chiamerà il ReceivedResponse
metodo del delegato al termine dell'operazione.
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();
}
iOS instrada automaticamente la richiesta alla versione "sandbox" o "produzione" dell'App Store a seconda del profilo di provisioning con cui è in esecuzione l'applicazione. Quando si sviluppa o si testa l'app, la richiesta avrà accesso a ogni prodotto configurato in iTunes Connessione (anche quelli che non sono ancora stati inviati o approvati da Apple). Quando l'applicazione è in produzione, le richieste StoreKit restituiranno solo le informazioni per i prodotti approvati .
Il ReceivedResponse
metodo sottoposto a override viene chiamato dopo che i server Apple hanno risposto con i dati. Poiché questa operazione viene chiamata in background, il codice deve analizzare i dati validi e usare una notifica per inviare le informazioni sul prodotto a tutti i ViewController che sono in ascolto per tale notifica. Il codice per raccogliere informazioni valide sul prodotto e inviare una notifica è illustrato di seguito:
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);
}
Anche se non visualizzato nel diagramma, il RequestFailed
metodo deve anche essere sottoposto a override in modo da poter fornire un feedback all'utente nel caso in cui i server dell'App Store non siano raggiungibili (o si verifica un altro errore). Il codice di esempio scrive semplicemente nella console, ma un'applicazione reale potrebbe scegliere di eseguire una query sulla error.Code
proprietà e implementare un comportamento personalizzato, ad esempio un avviso per l'utente.
public override void RequestFailed (SKRequest request, NSError error)
{
Console.WriteLine (" ** InAppPurchaseManager RequestFailed() " + error.LocalizedDescription);
}
Questo screenshot mostra l'applicazione di esempio immediatamente dopo il caricamento (quando non sono disponibili informazioni sul prodotto):
Prodotti non validi
Un SKProductsRequest
può anche restituire un elenco di ID prodotto non validi. I prodotti non validi vengono in genere restituiti a causa di uno dei seguenti:
ID prodotto non tipizzato : vengono accettati solo gli ID prodotto validi.
Prodotto non approvato : durante i test, tutti i prodotti cancellati per la vendita devono essere restituiti da un SKProductsRequest
oggetto ; tuttavia, in produzione vengono restituiti solo i prodotti approvati.
ID app non esplicito : gli ID app con caratteri jolly (con un asterisco) non consentono l'acquisto in-app.
Profilo di provisioning errato: se si apportano modifiche alla configurazione dell'applicazione nel portale di provisioning (ad esempio l'abilitazione degli acquisti in-app), ricordarsi di generare di nuovo e usare il profilo di provisioning corretto durante la compilazione dell'app.
Il contratto delle applicazioni a pagamento iOS non è disponibile . Le funzionalità storeKit non funzioneranno affatto a meno che non sia presente un contratto valido per l'account Apple Developer.
Il file binario si trova nello stato Rifiutato: se è presente un file binario inviato in precedenza nello stato Rifiutato (dal team di App Store o dallo sviluppatore), le funzionalità di StoreKit non funzioneranno.
Il ReceivedResponse
metodo nel codice di esempio restituisce i prodotti non validi nella console:
public override void ReceivedResponse (SKProductsRequest request, SKProductsResponse response)
{
// code removed for clarity
foreach (string invalidProductId in response.InvalidProducts) {
Console.WriteLine("Invalid product id: " + invalidProductId );
}
}
Visualizzazione dei prezzi localizzati
I livelli di prezzo specificano un prezzo specifico per ogni prodotto in tutti gli App Store internazionali. Per assicurarsi che i prezzi vengano visualizzati correttamente per ogni valuta, usare il metodo di estensione seguente (definito in SKProductExtension.cs
) anziché la proprietà Price di ogni SKProduct
:
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;
}
}
Il codice che imposta il titolo del pulsante usa il metodo di estensione simile al seguente:
string Buy = "Buy {0}"; // or a localizable string
buy5Button.SetTitle(String.Format(Buy, product.LocalizedPrice()), UIControlState.Normal);
L'uso di due account di test di iTunes diversi (uno per lo store americano e uno per il negozio giapponese) restituisce gli screenshot seguenti:
Si noti che l'archivio influisce sulla lingua usata per informazioni sul prodotto e valuta del prezzo, mentre l'impostazione della lingua del dispositivo influisce sulle etichette e su altri contenuti localizzati.
Tenere presente che per usare un account di test dello store diverso è necessario disconnettersi nel Impostazioni > iTunes e App Store e riavviare l'applicazione per accedere con un account diverso. Per modificare la lingua del dispositivo, passare a Impostazioni > lingua internazionale > generale>.