Visão geral do StoreKit e recuperando informações do produto no Xamarin.iOS
A interface do usuário para uma compra no aplicativo é mostrada nas capturas de tela abaixo. Antes de qualquer transação ocorrer, o aplicativo deve recuperar o preço e a descrição do produto para exibição. Em seguida, quando o usuário pressiona Comprar, o aplicativo faz uma solicitação ao StoreKit, que gerencia a caixa de diálogo de confirmação e o login do ID Apple. Supondo que a transação seja bem-sucedida, o StoreKit notifica o código do aplicativo, que deve armazenar o resultado da transação e fornecer ao usuário acesso à compra.
Classes
A implementação de compras no aplicativo requer as seguintes classes da estrutura do StoreKit:
SKProductsRequest – Uma solicitação ao StoreKit para produtos aprovados para vender (App Store). Pode ser configurado com vários IDs de produto.
- SKProductsRequestDelegate – Declara métodos para lidar com solicitações e respostas de produtos.
- SKProductsResponse – Enviado de volta ao delegado do StoreKit (App Store). Contém os SKProducts que correspondem aos Ids do produto enviados com a solicitação.
- SKProduct – Um produto recuperado do StoreKit (que você configurou no iTunes Connect). Contém informações sobre o produto, como ID do produto, Título, Descrição e Preço.
- SKPayment – Criado com uma ID do Produto e adicionado à fila de pagamento para realizar uma compra.
- SKPaymentQueue – Solicitações de pagamento em fila a serem enviadas à Apple. As notificações são acionadas como resultado de cada pagamento que está sendo processado.
- SKPaymentTransaction – Representa uma transação concluída (uma solicitação de compra que foi processada pela App Store e enviada de volta ao seu aplicativo via StoreKit). A transação pode ser comprada, restaurada ou com falha.
- SKPaymentTransactionObserver – Subclasse personalizada que responde a eventos gerados pela fila de pagamento StoreKit.
- As operações do StoreKit são assíncronas – depois que um SKProductRequest é iniciado ou um SKPayment é adicionado à fila, o controle é retornado ao seu código. O StoreKit chamará métodos em sua subclasse SKProductsRequestDelegate ou SKPaymentTransactionObserver quando receber dados dos servidores da Apple.
O diagrama a seguir mostra as relações entre as várias classes StoreKit (classes abstratas devem ser implementadas em seu aplicativo):
Essas classes são explicadas com mais detalhes mais adiante neste documento.
Testando
A maioria das operações do StoreKit requer um dispositivo real para teste. A recuperação de informações do produto (ou seja, preço e descrição) funcionará no simulador, mas as operações de compra e restauração retornarão um erro (como FailedTransaction Code=5002: Ocorreu um erro desconhecido).
Nota: StoreKit não funciona no iOS Simulator. Ao executar seu aplicativo no Simulador do iOS, o StoreKit registra um aviso se o aplicativo tentar recuperar a fila de pagamento. O teste da loja deve ser feito em dispositivos reais.
Importante: Não entre com sua conta de teste no aplicativo Configurações. Você pode usar o aplicativo Configurações para sair de qualquer conta existente do ID Apple e, em seguida, aguardar ser solicitado dentro da sequência de compra no aplicativo para fazer login usando um ID Apple de teste.
Se você tentar entrar na loja real com uma conta de teste, ela será automaticamente convertida em um ID Apple real. Essa conta não será mais utilizável para testes.
Para testar o código do StoreKit, você deve sair da sua conta de teste normal do iTunes e fazer login com uma conta de teste especial (criada no iTunes Connect) vinculada à loja de teste. Para sair da conta atual, visite Configurações > iTunes e App Store , conforme mostrado aqui:
em seguida, inicie sessão com uma conta de teste quando solicitado pelo StoreKit na sua aplicação:
Para criar usuários de teste no iTunes Connect, clique em Usuários e Funções na página principal.
Selecionar Testadores de Área Restrita
A lista de usuários existentes é exibida. Você pode adicionar um novo usuário ou excluir um registro existente. O portal não permite (atualmente) que você exiba ou edite usuários de teste existentes, portanto, é recomendável que você mantenha um bom registro de cada usuário de teste criado (especialmente a senha atribuída). Depois de excluir um usuário de teste, o endereço de email não poderá ser reutilizado para outra conta de teste.
Os novos usuários de teste têm atributos semelhantes a um ID Apple real (como nome, senha, pergunta e resposta secretas). Mantenha um registro de todos os detalhes inseridos aqui. O campo Selecionar iTunes Store determinará qual moeda e idioma as compras no aplicativo usarão quando estiverem conectados como esse usuário.
Recuperando informações do produto
O primeiro passo para vender um produto de compra no aplicativo é exibi-lo: recuperar o preço e a descrição atuais da App Store para exibição.
Independentemente do tipo de produtos que um aplicativo vende (Consumível, Não Consumível ou um tipo de Assinatura), o processo de recuperação de informações do produto para exibição é o mesmo. O código InAppPurchaseSample que acompanha este artigo contém um projeto chamado consumíveis que demonstra como recuperar informações de produção para exibição. Ele mostra como:
- Crie uma implementação e
SKProductsRequestDelegate
implemente oReceivedResponse
método abstrato. O código de exemplo chama isso deInAppPurchaseManager
classe. - Verifique com o StoreKit se os pagamentos são permitidos (usando
SKPaymentQueue.CanMakePayments
). - Instancie um
SKProductsRequest
com os IDs do produto que foram definidos no iTunes Connect. Isso é feito no método doInAppPurchaseManager.RequestProductData
exemplo. - Chame
SKProductsRequest
o método Start no . Isso dispara uma chamada assíncrona para os servidores da App Store. O Delegado (InAppPurchaseManager
) será chamado de volta com os resultados. - O método do Delegado (
InAppPurchaseManager
)ReceivedResponse
atualiza a interface do usuário com os dados retornados da App Store (preços de produtos e descrições ou mensagens sobre produtos inválidos).
A interação geral é semelhante a esta (o StoreKit está integrado ao iOS e a App Store representa os servidores da Apple):
Exibindo exemplo de informações do produto
O código de exemplo Consumables demonstra como as informações do produto podem ser recuperadas. A tela principal do exemplo exibe informações de dois produtos recuperados da App Store:
O código de exemplo para recuperar e exibir informações do produto é explicado com mais detalhes abaixo.
Métodos ViewController
A ConsumableViewController
classe gerenciará a exibição de preços para dois produtos cujas IDs de produto são codificadas na 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();
}
No nível da classe, também deve haver um NSObject declarado que será usado para configurar um NSNotificationCenter
observador:
NSObject priceObserver;
No método ViewWillAppear, o observador é criado e atribuído usando a central de notificações padrão:
priceObserver = NSNotificationCenter.DefaultCenter.AddObserver (
InAppPurchaseManager.InAppPurchaseManagerProductsFetchedNotification,
(notification) => {
// display code goes here, to handle the response from the App Store
}
No final do ViewWillAppear
método, chame o RequestProductData
método para iniciar a solicitação StoreKit. Depois que essa solicitação for feita, o StoreKit entrará em contato de forma assíncrona com os servidores da Apple para obter as informações e enviá-las de volta ao seu aplicativo. Isso é alcançado pela SKProductsRequestDelegate
subclasse ( InAppPurchaseManager
) que é explicada na próxima seção.
iap.RequestProductData(products);
O código para exibir o preço e a descrição simplesmente recupera as informações do SKProduct e as atribui aos controles UIKit (observe que exibimos o LocalizedTitle
e LocalizedDescription
– StoreKit resolve automaticamente o texto e os preços corretos com base nas configurações da conta do usuário). O código a seguir pertence à notificação que criamos acima:
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
}
}
Finalmente, o método deve garantir que ViewWillDisappear
o observador seja removido:
NSNotificationCenter.DefaultCenter.RemoveObserver (priceObserver);
Métodos SKProductRequestDelegate (InAppPurchaseManager)
O RequestProductData
método é chamado quando o aplicativo deseja recuperar preços de produtos e outras informações. Ele analisa a coleção de IDs de produto no tipo de dados correto e, em seguida, cria um SKProductsRequest
com essas informações. Chamar o método Start faz com que uma solicitação de rede seja feita aos servidores da Apple. A solicitação será executada de forma assíncrona e chamará o ReceivedResponse
método do Delegate quando for concluída com êxito.
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();
}
O iOS encaminhará automaticamente a solicitação para a versão 'sandbox' ou 'produção' da App Store, dependendo do perfil de provisionamento com o qual o aplicativo está sendo executado – portanto, quando você estiver desenvolvendo ou testando seu aplicativo, a solicitação terá acesso a todos os produtos configurados no iTunes Connect (mesmo aqueles que ainda não foram enviados ou aprovados pela Apple). Quando seu aplicativo estiver em produção, as solicitações do StoreKit retornarão apenas informações para produtos aprovados .
O ReceivedResponse
método substituído é chamado depois que os servidores da Apple responderam com dados. Como isso é chamado em segundo plano, o código deve analisar os dados válidos e usar uma notificação para enviar as informações do produto a qualquer ViewControllers que esteja 'ouvindo' essa notificação. O código para coletar informações válidas do produto e enviar uma notificação é mostrado abaixo:
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);
}
Embora não seja mostrado no diagrama, o RequestFailed
método também deve ser substituído para que você possa fornecer alguns comentários ao usuário caso os servidores da App Store não estejam acessíveis (ou algum outro erro ocorra). O código de exemplo apenas grava no console, mas um aplicativo real pode optar por consultar a error.Code
propriedade e implementar um comportamento personalizado (como um alerta para o usuário).
public override void RequestFailed (SKRequest request, NSError error)
{
Console.WriteLine (" ** InAppPurchaseManager RequestFailed() " + error.LocalizedDescription);
}
Esta captura de tela mostra o aplicativo de amostra imediatamente após o carregamento (quando nenhuma informação do produto está disponível):
Produtos inválidos
Um SKProductsRequest
também pode retornar uma lista de IDs de produto inválidos. Produtos inválidos geralmente são devolvidos devido a um dos seguintes:
A ID do Produto foi digitada incorretamente – Somente IDs de Produto válidos são aceitos.
Produto não foi aprovado – Durante os testes, todos os produtos que são liberados para venda devem ser devolvidos por um SKProductsRequest
, no entanto, na produção apenas produtos aprovados são devolvidos.
A ID do aplicativo não é explícita – as IDs de aplicativo curinga (com um asterisco) não permitem compras no aplicativo.
Perfil de provisionamento incorreto – Se você fizer alterações na configuração do aplicativo no portal de provisionamento (como habilitar compras no aplicativo), lembre-se de gerar novamente e usar o perfil de provisionamento correto ao criar o aplicativo.
O contrato de Aplicativos Pagos do iOS não está em vigor – os recursos do StoreKit não funcionarão a menos que haja um contrato válido para sua Conta de Desenvolvedor Apple.
O binário está no estado Rejeitado – Se houver um binário enviado anteriormente no estado Rejeitado (pela equipe da App Store ou pelo desenvolvedor), os recursos do StoreKit não funcionarão.
O ReceivedResponse
método no código de exemplo gera os produtos inválidos para o 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 );
}
}
Exibindo preços localizados
Os níveis de preço especificam um preço específico para cada produto em todas as App Stores internacionais. Para garantir que os preços sejam exibidos corretamente para cada moeda, use o seguinte método de extensão (definido em SKProductExtension.cs
) em vez da propriedade Price de cada 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;
}
}
O código que define o Título do botão usa o método de extensão da seguinte maneira:
string Buy = "Buy {0}"; // or a localizable string
buy5Button.SetTitle(String.Format(Buy, product.LocalizedPrice()), UIControlState.Normal);
O uso de duas contas de teste diferentes do iTunes (uma para a loja americana e outra para a loja japonesa) resulta nas seguintes capturas de tela:
Observe que a loja afeta o idioma usado para informações sobre o produto e a moeda do preço, enquanto a configuração de idioma do dispositivo afeta rótulos e outros conteúdos localizados.
Lembre-se de que, para usar uma conta de teste de loja diferente, você deve sair nas Configurações > do iTunes e da App Store e reiniciar o aplicativo para entrar com uma conta diferente. Para alterar o idioma do dispositivo, vá para Configurações > gerais > de idioma internacional>.