iOS開發(fā)基礎(chǔ)149-由UUIDString引發(fā)的思考
問題1:[[UIDevice currentDevice] identifierForVendor].UUIDString什么情況下值會變化?
[[UIDevice currentDevice] identifierForVendor].UUIDString 是一個用于標(biāo)識設(shè)備的唯一標(biāo)識符(UUID),針對同一應(yīng)用程序供應(yīng)商(即同一開發(fā)者的應(yīng)用程序集合),在設(shè)備上不變。然而,有一些情況會導(dǎo)致這個標(biāo)識符發(fā)生變化:
情況導(dǎo)致 identifierForVendor 變化:
-
應(yīng)用卸載和重裝:當(dāng)設(shè)備上來自同一供應(yīng)商的所有應(yīng)用程序都被卸載,再重新安裝任意一個應(yīng)用程序時,會生成新的
identifierForVendor。這意味著,如果用戶完全清除你的應(yīng)用并重新安裝,它會獲得一個新值。 -
設(shè)備恢復(fù)出廠設(shè)置:如果設(shè)備被恢復(fù)出廠設(shè)置,也會生成新的
identifierForVendor。
除此之外,identifierForVendor 不會因?yàn)樵O(shè)備上的通常操作(如重啟設(shè)備、軟件更新等)而改變。
存儲到 Keychain 的優(yōu)勢
Keychain 是一個安全存儲敏感信息的系統(tǒng)級服務(wù),適用于存儲比如密碼、證書和加密密鑰等重要數(shù)據(jù)。把 identifierForVendor 存儲到 Keychain 有一些優(yōu)勢:
- 持久性:即使用戶刪除了應(yīng)用,Keychain 中存儲的數(shù)據(jù)不會被刪除。當(dāng)用戶重新安裝應(yīng)用時,可以從 Keychain 中恢復(fù)數(shù)據(jù)。
- 安全性:Keychain 提供了高安全性的存儲方式,對敏感數(shù)據(jù)的保護(hù)比普通的文件存儲要好得多。
- 跨應(yīng)用共享:在適當(dāng)?shù)呐渲孟拢还?yīng)商的應(yīng)用程序可以共享 Keychain 中的數(shù)據(jù)。
下面是將 identifierForVendor 存儲到 Keychain 的示例代碼:
#import <Security/Security.h>
- (void)storeIdentifierForVendorInKeychain {
NSString *uuid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
NSString *key = @"com.yourcompany.yourapp.identifierForVendor";
// 刪除之前存儲的 UUID
[self deleteUUIDFromKeychain:key];
NSData *uuidData = [uuid dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *query = @{
(id)kSecClass: (id)kSecClassGenericPassword,
(id)kSecAttrAccount: key,
(id)kSecValueData: uuidData,
};
OSStatus status = SecItemAdd((CFDictionaryRef)query, NULL);
if (status == errSecSuccess) {
NSLog(@"UUID stored successfully.");
} else {
NSLog(@"Error storing UUID: %d", (int)status);
}
}
- (NSString *)retrieveUUIDFromKeychain {
NSString *key = @"com.yourcompany.yourapp.identifierForVendor";
NSDictionary *query = @{
(id)kSecClass: (id)kSecClassGenericPassword,
(id)kSecAttrAccount: key,
(id)kSecReturnData: (id)kCFBooleanTrue,
};
CFDataRef dataRef = NULL;
OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&dataRef);
if (status == errSecSuccess) {
NSData *resultData = (__bridge NSData *)dataRef;
NSString *uuid = [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
CFRelease(dataRef);
return uuid;
} else {
NSLog(@"Error retrieving UUID: %d", (int)status);
return nil;
}
}
- (void)deleteUUIDFromKeychain:(NSString *)key {
NSDictionary *query = @{
(id)kSecClass: (id)kSecClassGenericPassword,
(id)kSecAttrAccount: key,
};
OSStatus status = SecItemDelete((CFDictionaryRef)query);
if (status == errSecSuccess) {
NSLog(@"UUID deleted successfully.");
} else {
NSLog(@"Error deleting UUID: %d", (int)status);
}
}
步驟:
- 存儲 UUID:使用
storeIdentifierForVendorInKeychain方法將identifierForVendor存儲到 Keychain 中。 - 檢索 UUID:使用
retrieveUUIDFromKeychain方法從 Keychain 中檢索存儲的 UUID。 - 刪除 UUID:使用
deleteUUIDFromKeychain方法刪除存儲的 UUID。
通過這些步驟和方法,你可以確保即使應(yīng)用被刪除和重新安裝,也可以從 Keychain 中恢復(fù)先前的 identifierForVendor,保持UUID的一致性。
問題2:存儲到 Keychain,什么情況下值會變化 ?
存儲在 Keychain 中的數(shù)據(jù)通常在一些特定情況下會發(fā)生變化。以下是其中一些主要情形:
1. 恢復(fù)出廠設(shè)置
恢復(fù)出廠設(shè)置會清除設(shè)備上的所有數(shù)據(jù),包括應(yīng)用數(shù)據(jù)、用戶文件、系統(tǒng)設(shè)置和 Keychain 數(shù)據(jù)。在這種情況下,Keychain 中存儲的任何值(例如標(biāo)識符、密碼等)都會被刪除并且無法恢復(fù)。
2. 刷機(jī)
刷機(jī)通常指的是重新安裝設(shè)備的固件或操作系統(tǒng)。刷機(jī)過程也會清除設(shè)備上的所有數(shù)據(jù),包括 Keychain 中的數(shù)據(jù)。因此,存儲在 Keychain 中的值會被刪除。
3. 應(yīng)用被卸載
不同于普通的文件存儲,Keychain 中的數(shù)據(jù)在應(yīng)用被卸載時不會被刪除。當(dāng)應(yīng)用重新安裝時,可以繼續(xù)訪問先前存儲的 Keychain 數(shù)據(jù)。然而,如果用戶選擇了“刪除應(yīng)用的數(shù)據(jù)”或使用特定第三方工具清理 Keychain 數(shù)據(jù),相關(guān)的存儲值可能會被刪除。
4. 設(shè)備遷移
在某些情況下,通過 iCloud 備份或設(shè)備遷移將 Keychain 數(shù)據(jù)同步到新設(shè)備上。如果用戶選擇沒有遷移 Keychain 數(shù)據(jù)(例如,設(shè)備遷移時選擇了不備份 Keychain),那么新設(shè)備中的值會發(fā)生變化或丟失。
5. 越獄設(shè)備
越獄會增加 Keychain 數(shù)據(jù)被第三方工具訪問、修改或刪除的風(fēng)險。盡管越獄本身不會直接改變 Keychain 中的值,但越獄后的應(yīng)用和操作可能影響其數(shù)據(jù)完整性,可能導(dǎo)致 Keychain 數(shù)據(jù)被篡改或清除。
6. 應(yīng)用自身操作
如果應(yīng)用在某些條件下(如用戶登出、換新賬戶、重裝等)主動刪除或更新 Keychain 中的數(shù)據(jù),也會導(dǎo)致相關(guān)值發(fā)生變化。例如:
- (void)deleteIdentifierInKeychain {
NSString *key = @"com.yourcompany.yourapp.identifierForVendor";
NSDictionary *query = @{
(id)kSecClass: (id)kSecClassGenericPassword,
(id)kSecAttrAccount: key,
};
OSStatus status = SecItemDelete((CFDictionaryRef)query);
if (status == errSecSuccess) {
NSLog(@"UUID deleted successfully.");
} else {
NSLog(@"Error deleting UUID: %d", (int)status);
}
}
7. 用戶主動清除 Keychain
用戶可以通過某些工具或設(shè)置,主動選擇清除特定的 Keychain 數(shù)據(jù),這樣會導(dǎo)致存儲值的刪除或變化。
常見問題:
-
卸載和重新安裝應(yīng)用:
- 不恢復(fù)出廠設(shè)置:重裝應(yīng)用通常不會影響 Keychain 數(shù)據(jù)。
- 恢復(fù)出廠設(shè)置或重置所有設(shè)置:Keychain 數(shù)據(jù)會被刪除。
-
設(shè)備切換:
- 如果用戶在設(shè)備切換過程中未備份或恢復(fù) Keychain 數(shù)據(jù),新的 Keychain 數(shù)據(jù)將重新生成。
簡而言之,盡管 Keychain 存儲提供了一種相對持久的存儲機(jī)制,在以下情況下存儲值可能會發(fā)生變化或被清除:
- 恢復(fù)出廠設(shè)置或刷機(jī)。
- 設(shè)備遷移而未同步 Keychain 數(shù)據(jù)。
- 越獄引起的數(shù)據(jù)篡改或清除。
- 應(yīng)用自身操作或用戶主動清除 Keychain 數(shù)據(jù)。

浙公網(wǎng)安備 33010602011771號