在Swift 5.0中将数据持久保存到KeychainAccess中

时间:2019-05-06 08:03:03

标签: swift keychain saving-data

我想将敏感的用户数据持久保存到Keychain中,但是问题是,每次我在模拟器和设备中重新启动应用程序时,我都会丢失所有数据。根据我的理解,除非明确删除密钥链数据,否则它们应继续存在于系统中。我知道如何使用文件管理器将数据保存在文件中,但这不适用于此服务。我试图找到答案,但是没有运气。我特别在寻找“将数据保存到钥匙串中”和“永久保留此数据,以便在删除和重新启动应用程序数据时仍然存在”。仅供参考,我现在正在使用KeychainAccess包装器(https://github.com/kishikawakatsumi/KeychainAccess)。

请帮助我永久保存带有钥匙串的数据。 我正在开发的App存储敏感数据,因此认为应该是钥匙串,但是如果合适的话,您也可以提出其他建议。

下面是我的测试代码,以实现一致的节省,但没有运气。

  1. 这是带有包装的名为KeychainAccess的钥匙串功能
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)

1 个答案:

答案 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对自定义类型进行编码/解码,然后将其保留在钥匙串中,因此我认为这是安全的。请问有人知道它可以帮助建议吗?