开发过程中,我们都会使用Keychain或者UserDefaults来存储一些App登录用户相关的数据,或者服务器的token等,可以很方便的实现App启动自登录的功能;但是这个对于测试来说就比较头疼,尤其是存储到Keychain里的不能删除的数据,而要模仿一个全新的从没有安装过我们应用的App的时候,必须要清除掉保存的Keychain。
1. Keychain清除
Keychain是iOS设备中的一个安全的存储容器,可以用来为应用保存敏感信息比如用户名,密码,网络密码,认证令牌。在删掉应用后,Keychain中的数据也会保留,用户再次安装的App还能从Keychain中读取到数据。所以Keychain中保存的数据一般都是比较重要,并且不希望卸载应用后就被删除的数据,比如用户的登录信息,wifi密码等。我们常用的OpenUDID库就是使用Keychain的这个特性来获取唯一性的设备ID,具体做法是,生成一个UUID,或者是获取广告标识符,然后存入Keychain,这样删除应用后再次安装应用也还能读取到上一次生成的设备标识符。
清空Keychain的思路很简单,就是遍历keychain中存储的数据,然后挨个删除。代码如下:
- (void)clearKeyChain {
NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:
(__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnAttributes,
(__bridge id)kSecMatchLimitAll, (__bridge id)kSecMatchLimit,
nil];
NSArray *secItemClasses = [NSArray arrayWithObjects:
(__bridge id)kSecClassGenericPassword,
(__bridge id)kSecClassInternetPassword,
(__bridge id)kSecClassCertificate,
(__bridge id)kSecClassKey,
(__bridge id)kSecClassIdentity,
nil];
for (id secItemClass in secItemClasses) {
[query setObject:secItemClass forKey:(__bridge id)kSecClass];
CFTypeRef result = NULL;
SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
if (result != NULL) CFRelease(result);
NSDictionary *spec = @{(__bridge id)kSecClass: secItemClass};
SecItemDelete((__bridge CFDictionaryRef)spec);
}
}
2. NSUserDefault的清除
UserDefaults是iOS设备上一个Key-Value的存储容器,最终数据会以plist文件的形式存在文件夹Library/Preferences下面。默认的UserDefaults的文件名是bundle identitier加上.plist的后缀名。UserDefaulst会随App的删除而被清除(也可以同步到iCloud上),所以UserDefaults存储着一些可以再生的的数据。
- (void)clearUserDefaults {
// 清空默认存储
NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
[[NSUserDefaults standardUserDefaults] synchronize];
// 清空自定义存储
NSString *path = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES).lastObject;
path = [path stringByAppendingPathComponent:@"Preferences"];
NSArray *fileList = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
for (NSString * filename in fileList) {
NSString *filepath = [path stringByAppendingPathComponent:filename];
BOOL isDir = NO;
[[NSFileManager defaultManager] fileExistsAtPath:filepath isDirectory:(&isDir)];
if (!isDir && [filename hasSuffix:@".plist"] && (![filename isEqualToString:appDomain])) {
NSString *suitename = [filename stringByDeletingPathExtension];
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:suitename];
[userDefaults removePersistentDomainForName:suiteName];
[[NSFileManager defaultManager] removeItemAtPath:filepath error:nil];
}
}
}
网友评论