Хранение в приложении квитанций о покупке в приложении Keychain - PullRequest
42 голосов
/ 12 февраля 2011

Я никогда раньше не реализовывал In App Purchase, поэтому я использовал оболочку MKStoreKit и получил работающую реализацию. MKStoreKit хранит все чеки в списке UserDefaults .plist в виде BOOL, поэтому пиратам очень просто распределять покупки в приложении в «взломанном» состоянии. Как только первая покупка сделана, пакет может быть распределен, и .plist может быть воссоздан для разблокировки IAP.

Я бы хотел расширить MKStoreKit для создания данных проверки покупки в приложении в цепочке для ключей iOS. Есть ли какой-либо недостаток или возможная причина, по которой это может не сработать для платящих пользователей, ненадежность или какая-либо другая причина, почему это было бы в целом плохой идеей? Я понимаю, что пиратство неизбежно, и я определенно не хочу отталкивать платящих пользователей, но я чувствую, что UserDefaults .plist - слишком простой способ обхода.

В моем сценарии простая цепочка будет помещена в цепочку для ключей при совершении покупки. Таким образом, если двоичный файл распространяется, разблокируемые блоки еще не включены. Конечно, было бы возможно найти обходной путь, но потребовалось бы немного больше усилий и узнать, как найти флаг ИСТИНА / ЛОЖЬ и заставить его всегда возвращать правильное значение. Из-за запутывания я даже немного усложнил отследить это.

Спасибо за все ваши идеи, и я ценю ответы, избегая обязательных ответов: пиратство, сделка с ним. Меня больше интересуют технические возможности этого решения.

1 Ответ

54 голосов
/ 19 февраля 2011

Мы делаем именно это в наших приложениях, и это прекрасно работает. Это бесплатное приложение, которое вы можете обновить до полной версии, и мы храним индикатор обновления в связке ключей. Индикатор обновления - это произвольная строка, которую вы выбираете, но для целей цепочки для ключей он обрабатывается как пароль, то есть значение для kSecValueData шифруется в цепочке для ключей. Приятным плюсом этого подхода является то, что если пользователь удаляет приложение, а затем переустанавливает его, все снова включается, как по волшебству, поскольку элементы цепочки для ключей хранятся отдельно от приложения. И так мало дополнительной работы по сохранению чего-либо в пользовательских настройках по умолчанию, что мы решили, что оно того стоит.

Вот как создать элемент безопасности:

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);

Вот как найти элемент безопасности, чтобы проверить его значение:

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
    }
}

Если upgradeItemData равно nil, то ключ не существует, поэтому вы можете предположить, что обновления нет, или, что мы делаем, присвоить значение, которое означает, что не обновлено.

Обновление

Добавлены kSecReturnData (спасибо @Luis за указание на это)

Код на GitHub (вариант ARC)

...