我想将敏感的用户数据持久保存到Keychain中,但是问题是,每次我在模拟器和设备中重新启动应用程序时,我都会丢失所有数据。根据我的理解,除非明确删除密钥链数据,否则它们应继续存在于系统中。我知道如何使用文件管理器将数据保存在文件中,但这不适用于此服务。我试图找到答案,但是没有运气。我特别在寻找“将数据保存到钥匙串中”和“永久保留此数据,以便在删除和重新启动应用程序数据时仍然存在”。仅供参考,我现在正在使用KeychainAccess包装器(https://github.com/kishikawakatsumi/KeychainAccess)。
请帮助我永久保存带有钥匙串的数据。 我正在开发的App存储敏感数据,因此认为应该是钥匙串,但是如果合适的话,您也可以提出其他建议。
下面是我的测试代码,以实现一致的节省,但没有运气。
import Foundation
import KeychainAccess
class Retriever {
static let keychain = Keychain(service: "com.cochipcho.KeeperApp")
// store
static func saveToKeychain(data: Data) {
keychain[data: "encoded"] = NSData(data: data) as Data
}
//retrieve
static func loadFromKeychain() -> [String] {
let retrievedData = keychain[data: "encoded"]
let string = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(retrievedData!) as? [String]
return string!
}
}
这是一个声明要从钥匙串类中保存/检索数据的视图控制器。
import UIKit
import KeychainAccess
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
var array = [String]()
//saving into keychain
@IBOutlet weak var textField: UITextField!
@IBAction func buttonTapped(_ sender: Any) {
array.append(textField.text!)
let data = NSKeyedArchiver.archivedData(withRootObject: array)
Retriever.saveToKeychain(data: data)
}
//retrieving from keychain
@IBOutlet weak var label: UILabel!
@IBAction func retrieveButton(_ sender: Any) {
label.text = "\(Retriever.loadFromKeychain())"
print(Retriever.loadFromKeychain())
print(Retriever.keychain[data: "encoded"])
}
}
在保存输入数据的控制台中-但一旦在模拟器上重新安装并重新启动应用程序,所有这些都将消失。
["1"]
Optional(227 bytes)
["1", "2"]
Optional(235 bytes)
["1", "2"]
Optional(235 bytes)
["1", "2", "3"]
Optional(243 bytes)
["1", "2", "3", "4"]
Optional(251 bytes)
["1", "2", "3", "4", "5"]
Optional(259 bytes)
答案 0 :(得分:1)
首先,我必须在“功能”中设置KeyChain共享并下载权利。设置好之后,一切顺利。这里有一个对我有帮助的链接。
Unable to store data in Keychain Xcode 8 GM (Swift 3)
此外,这是我在实际项目中遇到的另一个问题。尽管上面的代码使用的是用NSKeyedArchiver编码/解码的数组,但我的项目采用的是自定义类类型,但不适用于NSKeyedArchiver。相反,我尝试使用PropertyList对其进行编码/解码,并且最终可以正常工作。我成功地编码/解码/钥匙串。请参见下面的工作代码。
import Foundation
import KeychainAccess
class UserInformation: Codable {
var isExpanded: Bool
var isPinned: Bool
var sectionName: String
var userInformation: [String?]
var indexPathSection: Int?
init(isExpanded: Bool, isPinned: Bool, sectionName: String, userInformation: [String?], indexPathSection: Int?) {
self.isExpanded = isExpanded
self.isPinned = isPinned
self.sectionName = sectionName
self.userInformation = userInformation
self.indexPathSection = indexPathSection
}
}
extension UserInformation {
static let propertyListEncoder = PropertyListEncoder()
static let propertyListDecoder = PropertyListDecoder()
static let keychain = Keychain(service: "com.cochipcho.KeeperApp-UserInfo")
static func saveToKeychain(userInfo: [UserInformation]) {
let data = try? propertyListEncoder.encode(userInfo)
if let savingData = data {
keychain[data: "encodedUserInfo"] = NSData(data: savingData) as Data
}
}
static func loadFromKeychain() -> [UserInformation]? {
guard let retrievedData = keychain[data: "encodedUserInfo"] else { return nil }
let data = try? propertyListDecoder.decode(Array<UserInformation>.self, from: retrievedData)
return data
}
}
剩下的一个问题-PropertyListEncoder / PropertyList在这里是不错的选择吗?我认为我不存储任何数据,而只是使用PropertyListEncoder对自定义类型进行编码/解码,然后将其保留在钥匙串中,因此我认为这是安全的。请问有人知道它可以帮助建议吗?