iOS 8(OS X Yosemite)引入了一种新的API/常量,用于检测用户设备是否设置了密码。
可以使用
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
来检测设备上是否设置了密码。
流程如下:
1. 尝试使用该属性在钥匙串中保存新项目
2. 如果成功,表示当前启用了密码
3. 如果密码未被保存,则表示没有密码
4. 清理项目,因为如果它已经在钥匙串中,则会使“添加”操作失败,看起来好像密码未设置
我在我的iPhone 5S上测试过这个方法,首先返回
true
,然后我在设置中禁用了密码,它返回
false
。最后,我重新启用了密码,它返回
true
。之前的操作系统版本将返回
false
。该代码在模拟器中也可以工作,在安装有OS X密码的机器上返回
true
(我没有测试其他OS X场景)。
此外,请参见此处的示例项目:
https://github.com/project-imas/passcode-check/pull/5
最后,据我所知,iOS 8没有禁用数据保护的设置,因此我认为这就是您需要的所有内容,以确保加密。
BOOL isAPIAvailable = (&kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly != NULL);
if(isAPIAvailable) {
NSData* secret = [@"Device has passcode set?" dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *attributes = @{
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: @"LocalDeviceServices",
(__bridge id)kSecAttrAccount: @"NoAccount",
(__bridge id)kSecValueData: secret,
(__bridge id)kSecAttrAccessible: (__bridge id)kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
};
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL);
if (status == errSecSuccess) {
NSDictionary *query = @{
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: @"LocalDeviceServices",
(__bridge id)kSecAttrAccount: @"NoAccount"
};
status = SecItemDelete((__bridge CFDictionaryRef)query);
return true;
}
if (status == errSecDecode) {
return false;
}
}
return false;
P.S.正如苹果在介绍WWDC视频(711钥匙链和使用Touch ID进行身份验证)中指出的那样,他们故意选择不直接通过API公开密码状态,以防止应用程序陷入不该有的情况(例如:“这个设备有密码吗?好的,我将以明文形式存储这些私人信息”)。更好的做法是创建一个加密密钥,将其存储在kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
下,并加密该文件。如果用户决定禁用他们的密码,则无法恢复该文件。