We do exactly that in our of our apps and it works great.It’s a free app that you can upgrade to a full version and we store the upgrade indicator in the keychain. The upgrade indicator is an arbitrary string that you choose, but for the purposes of the keychain it is treated as a password, i.e. the value for kSecValueData is encrypted in the keychain. A nice bonus about this approach is that if the user deletes the app and then later re-installs it, everything is re-enabled like magic because the keychain items are stored separately from the app. And it’s so little additional work over storing something in the user defaults that we decided it was worth it.
Here’s how to create the security item:
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);
Here’s how to find the security item to check its value:
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
}
}
If upgradeItemData is nil, then the key doesn’t exist so you can assume the upgrade is not there or, what we do, is put in a value that means not upgraded.
Update
Added kSecReturnData (Thanks @Luis for pointing it out)
Code on GitHub (ARC variant)
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…