Armazenando recibos de compra no aplicativo no chaveiro do aplicativo
-
12-11-2019 - |
Pergunta
Eu nunca implementei o In App Purchase antes, então usei o wrapper MKStoreKit e tenho uma implementação funcional.O MKStoreKit mantém todos os recibos no .plist UserDefaults como um BOOL, portanto, é muito simples para os piratas distribuirem as compras no aplicativo em um estado "crackeado".Assim que a primeira compra for feita, o pacote pode ser distribuído e o .plist pode ser recriado para permitir desbloqueios IAP.
Gostaria de estender o MKStoreKit para criar os dados de validação de compra no aplicativo nas chaves do iOS.Existe alguma desvantagem ou possível motivo para que isso falhe para usuários pagantes, não seja confiável ou qualquer outro motivo pelo qual seria uma má ideia fazer isso?Entendo que a pirataria é inevitável e definitivamente não quero alienar usuários pagantes, mas sinto que o .plist UserDefaults é uma maneira muito fácil de contornar.
No meu cenário, um barbante simples seria colocado no chaveiro no momento da compra.Dessa forma, se o binário for distribuído, os desbloqueáveis ainda não estarão habilitados.Claro, seria possível encontrar uma solução alternativa, mas seria necessário um pouco mais de esforço e saber como encontrar o sinalizador TRUE/FALSE e fazer com que ele sempre retornasse o valor correto.Através da ofuscação, eu poderia até tornar um pouco mais difícil rastrear isso.
Obrigado por todos os seus insights e agradeço as respostas que evitam as respostas obrigatórias de pirataria inevitável e de lidar com isso.Estou mais interessado nas viabilidades técnicas desta solução.
Solução
Fazemos exatamente isso em nossos aplicativos e funciona muito bem. É um aplicativo gratuito que você pode atualizar para uma versão completa e armazenamos o indicador de atualização no chaveiro.O indicador de atualização é uma string arbitrária que você escolhe, mas para fins de chaveiro ele é tratado como uma senha, ou seja,o valor de kSecValueData é criptografado nas chaves.Um bom bônus sobre essa abordagem é que se o usuário excluir o aplicativo e depois reinstalá-lo, tudo será reativado como mágica porque os itens das chaves são armazenados separadamente do aplicativo.E é tão pouco trabalho adicional armazenar algo nos padrões do usuário que decidimos que valeu a pena.
Veja como criar o item de segurança:
NSMutableDictionary* dict = [NSMutableDictionary dictionary];
[dict setObject: (id) kSecClassGenericPassword forKey: (id) kSecClass];
[dict setObject: kYourUpgradeStateKey forKey: (id) kSecAttrService];
[dict setObject: kYourUpgradeStateValue forKey: (id) kSecValueData];
SecItemAdd ((CFDictionaryRef) dict, NULL);
Veja como encontrar o item de segurança para verificar seu valor:
NSMutableDictionary* query = [NSMutableDictionary dictionary];
[query setObject: (id) kSecClassGenericPassword forKey: (id) kSecClass];
[query setObject: kYourUpgradeStateKey forKey: (id) kSecAttrService];
[query setObject: (id) kCFBooleanTrue forKey: (id) kSecReturnData];
NSData* upgradeItemData = nil;
SecItemCopyMatching ( (CFDictionaryRef) query, (CFTypeRef*) &upgradeItemData );
if ( !upgradeItemData )
{
// Disable feature
}
else
{
NSString* s = [[[NSString alloc]
initWithData: upgradeItemData
encoding: NSUTF8StringEncoding] autorelease];
if ( [s isEqualToString: kYourUpgradeStateValue] )
{
// Enable feature
}
}
Se upgradeItemData for nulo, então a chave não existe, então você pode assumir que a atualização não existe ou, o que fazemos, é colocada em um valor que significa que não foi atualizada.
Atualizar
Adicionado kSecReturnData (Obrigado @Luis por apontar isso)