KeychainAccess 是一个简单的 Swift 封装器,用于在 iOS 和 macOS 上操作 Keychain。它使 Keychain API 的使用变得极其简单,在 Swift 中更加易用。
<img src="https://github.com/kishikawakatsumi/KeychainAccess/assets/40610/4de4aae1-6fc1-4477-af6d-afbe6d164da0" width="320px" /> <img src="https://github.com/kishikawakatsumi/KeychainAccess/assets/40610/2980ea84-862b-4067-b9b7-90de629171b9" width="320px" /> <img src="https://github.com/kishikawakatsumi/KeychainAccess/assets/40610/3299347d-eb1b-446c-921c-778fa493f818" width="320px" />
let keychain = Keychain(service: "com.example.github-token") keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
let keychain = Keychain(server: "https://github.com", protocolType: .https) keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
let keychain = Keychain(service: "com.example.github-token")
let keychain = Keychain(service: "com.example.github-token", accessGroup: "12ABCD3E4F.shared")
let keychain = Keychain(server: "https://github.com", protocolType: .https)
let keychain = Keychain(server: "https://github.com", protocolType: .https, authenticationType: .htmlForm)
keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
keychain[string: "kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
keychain[data: "secret"] = NSData(contentsOfFile: "secret.bin")
keychain.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")
do { try keychain.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") } catch let error { print(error) }
let token = keychain["kishikawakatsumi"]
let token = keychain[string: "kishikawakatsumi"]
let secretData = keychain[data: "secret"]
let token = try? keychain.get("kishikawakatsumi")
let token = try? keychain.getString("kishikawakatsumi")
let data = try? keychain.getData("kishikawakatsumi")
keychain["kishikawakatsumi"] = nil
do { try keychain.remove("kishikawakatsumi") } catch let error { print("error: \(error)") }
let keychain = Keychain(server: "https://github.com", protocolType: .https) do { try keychain .label("github.com (kishikawakatsumi)") .comment("github access token") .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") } catch let error { print("error: \(error)") }
let keychain = Keychain() let persistentRef = keychain[attributes: "kishikawakatsumi"]?.persistentRef ...
let keychain = Keychain() let creationDate = keychain[attributes: "kishikawakatsumi"]?.creationDate ...
let keychain = Keychain() do { let attributes = try keychain.get("kishikawakatsumi") { $0 } print(attributes?.comment) print(attributes?.label) print(attributes?.creator) ... } catch let error { print("error: \(error)") }
let keychain = Keychain() if let attributes = keychain[attributes: "kishikawakatsumi"] { print(attributes.comment) print(attributes.label) print(attributes.creator) }
提供流畅的接口
let keychain = Keychain(service: "com.example.github-token") .label("github.com (kishikawakatsumi)") .synchronizable(true) .accessibility(.afterFirstUnlock)
let keychain = Keychain(service: "com.example.github-token")
let keychain = Keychain(service: "com.example.github-token") .accessibility(.afterFirstUnlock) keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
let keychain = Keychain(service: "com.example.github-token") do { try keychain .accessibility(.afterFirstUnlock) .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") } catch let error { print("error: \(error)") }
let keychain = Keychain(service: "com.example.github-token") .accessibility(.whenUnlocked) keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
let keychain = Keychain(service: "com.example.github-token") do { try keychain .accessibility(.whenUnlocked) .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") } catch let error { print("error: \(error)") }
let keychain = Keychain(service: "com.example.github-token", accessGroup: "12ABCD3E4F.shared")
let keychain = Keychain(service: "com.example.github-token") .synchronizable(true) keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
let keychain = Keychain(service: "com.example.github-token") do { try keychain .synchronizable(true) .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") } catch let error { print("错误: \(error)") }
任何需要认证的操作都必须在后台线程中运行。 如果在主线程中运行,UI线程将被锁定,以便系统尝试显示认证对话框。
要使用Face ID,请在Info.plist
中添加NSFaceIDUsageDescription
键
如果你想存储受Touch ID保护的钥匙串项目,请指定accessibility
和authenticationPolicy
属性。
let keychain = Keychain(service: "com.example.github-token") DispatchQueue.global().async { do { // 密码移除时是否应该使密钥失效?如果不需要,则使用`.WhenUnlocked` try keychain .accessibility(.whenPasscodeSetThisDeviceOnly, authenticationPolicy: [.biometryAny]) .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") } catch let error { // 如需要,进行错误处理... } }
更新方式与添加时相同。
如果你尝试添加的项目可能已存在且受保护,请不要在主线程中运行。 因为更新受保护的项目需要认证。
此外,如果你想在更新时显示自定义认证提示信息,请指定authenticationPrompt
属性。
如果项目未受保护,authenticationPrompt
参数将被忽略。
let keychain = Keychain(service: "com.example.github-token") DispatchQueue.global().async { do { // 密码移除时是否应该使密钥失效?如果不需要,则使用`.WhenUnlocked` try keychain .accessibility(.whenPasscodeSetThisDeviceOnly, authenticationPolicy: [.biometryAny]) .authenticationPrompt("认证以更新你的访问令牌") .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") } catch let error { // 如需要,进行错误处理... } }
获取方式与获取普通项目相同。如果你尝试获取的项目受保护,系统将自动显示Touch ID或密码认证。
如果你想显示自定义认证提示信息,请指定authenticationPrompt
属性。
如果项目未受保护,authenticationPrompt
参数将被忽略。
let keychain = Keychain(service: "com.example.github-token") DispatchQueue.global().async { do { let password = try keychain .authenticationPrompt("认证以登录服务器") .get("kishikawakatsumi") print("密码: \(password)") } catch let error { // 如需要,进行错误处理... } }
移除方式与移除普通项目相同。 移除钥匙串项目时无法显示Touch ID或密码认证。
let keychain = Keychain(service: "com.example.github-token") do { try keychain.remove("kishikawakatsumi") } catch let error { // 如需要,进行错误处理... }
共享Web凭证是一个编程接口,它使原生iOS应用能够与其网站对应部分共享凭证。例如,用户可能在Safari中登录网站,输入用户名和密码,并使用iCloud钥匙串保存这些凭证。之后,用户可能运行同一开发者的原生应用,应用不需要用户重新输入用户名和密码,共享Web凭证可以访问之前在Safari中输入的凭证。用户还可以在应用内创建新账户、更新密码或删除账户。这些更改随后会被保存并被Safari使用。 https://developer.apple.com/library/ios/documentation/Security/Reference/SharedWebCredentialsRef/
let keychain = Keychain(server: "https://www.kishikawakatsumi.com", protocolType: .HTTPS) let username = "kishikawakatsumi@mac.com" // 首先,检查应用的钥匙串中的凭证 if let password = try? keychain.get(username) { // 如果在钥匙串中找到密码, // 则登录服务器 } else { // 如果在钥匙串中未找到密码, // 尝试从共享Web凭证读取 keychain.getSharedPassword(username) { (password, error) -> () in if password != nil { // 如果在共享Web凭证中找到密码, // 则登录服务器 // 并将密码保存到钥匙串 keychain[username] = password } else { // 如果在钥匙串和共享Web凭证中都未找到密码, // 提示输入用户名和密码 // 登录服务器 // 如果登录成功, // 将凭证同时保存到钥匙串和共享Web凭证。 keychain[username] = inputPassword keychain.setSharedPassword(inputPassword, account: username) } } }
Keychain.requestSharedWebCredential { (credentials, error) -> () in }
生成与Safari自动填充使用的格式相同的强随机密码(xxx-xxx-xxx-xxx)。
let password = Keychain.generatePassword() // => Nhu-GKm-s3n-pMx
在你的应用中添加com.apple.developer.associated-domains授权。此授权必须包含你想要共享凭证的所有域。
在你的网站中添加apple-app-site-association文件。此文件必须包含网站想要共享凭证的所有应用的应用标识符,并且必须正确签名。
当应用安装时,系统会下载并验证每个关联域的站点关联文件。如果验证成功,应用就与该域关联。
更多详情: https://developer.apple.com/library/ios/documentation/Security/Reference/SharedWebCredentialsRef/
let keychain = Keychain(server: "https://github.com", protocolType: .https) print("\(keychain)")
=>
[
[authenticationType: default, key: kishikawakatsumi, server: github.com, class: internetPassword, protocol: https]
[authenticationType: default, key: hirohamada, server: github.com, class: internetPassword, protocol: https]
[authenticationType: default, key: honeylemon, server: github.com, class: internetPassword, protocol: https]
]
let keychain = Keychain(server: "https://github.com", protocolType: .https) let keys = keychain.allKeys() for key in keys { print("键: \(key)") }
=>
键: kishikawakatsumi
键: hirohamada
键: honeylemon
let keychain = Keychain(server: "https://github.com", protocolType: .https) let items = keychain.allItems() for item in items { print("项目: \(item)") }
=>
项目: [authenticationType: Default, key: kishikawakatsumi, server: github.com, class: InternetPassword, protocol: https]
项目: [authenticationType: Default, key: hirohamada, server: github.com, class: InternetPassword, protocol: https]
项目: [authenticationType: Default, key: honeylemon, server: github.com, class: InternetPassword, protocol: https]
如果遇到以下错误,你需要添加一个Keychain.entitlements
文件。
OSStatus error:[-34018] 内部错误,当所需的授权不存在时,客户端既没有application-identifier也没有keychain-access-groups授权。
<img alt="Screen Shot 2019-10-27 at 8 08 50" src="https://yellow-cdn.veclightyear.com/ab5030c0/f53c515c-7d81-4d14-8acb-34f8b9868e0c.png" width="500">
<img src="https://yellow-cdn.veclightyear.com/ab5030c0/e9cb96dc-5685-468e-8b44-3a9affa85db3.png" width="500" />
操作系统 | Swift | |
---|---|---|
v1.1.x | iOS 7+, macOS 10.9+ | 1.1 |
v1.2.x | iOS 7+, macOS 10.9+ | 1.2 |
v2.0.x | iOS 7+, macOS 10.9+, watchOS 2+ | 2.0 |
v2.1.x | iOS 7+, macOS 10.9+, watchOS 2+ | 2.0 |
v2.2.x | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 2.0, 2.1 |
v2.3.x | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 2.0, 2.1, 2.2 |
v2.4.x | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 2.2, 2.3 |
v3.0.x | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 3.x |
v3.1.x | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 4.0, 4.1, 4.2 |
v3.2.x | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 4.0, 4.1, 4.2, 5.0 |
v4.0.x | iOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+ | 4.0, 4.1, 4.2, 5.1 |
v4.1.x | iOS 8+, macOS 10.9+, watchOS 3+, tvOS 9+, Mac Catalyst 13+ | 4.0, 4.1, 4.2, 5.1 |
KeychainAccess 可通过 CocoaPods 获得。要安装它,只需在你的 Podfile 中添加以下几行:
use_frameworks! pod 'KeychainAccess'
KeychainAccess 可通过 Carthage 获得。要安装它,只需在你的 Cartfile 中添加以下一行:
github "kishikawakatsumi/KeychainAccess"
KeychainAccess 也可通过 Swift Package Manager 获得。
选择 File > Add Packages... > Add Package Dependency...
,
首先,创建一个 Package.swift
文件,其包声明包括:
// swift-tools-version:5.0 import PackageDescription let package = Package( name: "MyLibrary", products: [ .library(name: "MyLibrary", targets: ["MyLibrary"]), ], dependencies: [ .package(url: "https://github.com/kishikawakatsumi/KeychainAccess.git", from: "3.0.0"), ], targets: [ .target(name: "MyLibrary", dependencies: ["KeychainAccess"]), ] )
然后,输入
$ swift build
Lib/KeychainAccess.xcodeproj
添加到你的项目中KeychainAccess.framework
与你的目标链接Copy Files Build Phase
以将框架包含在你的应用程序包中参考 iOS 示例项目。
<img src="https://github.com/kishikawakatsumi/KeychainAccess/assets/40610/b7a46cfb-714d-47d5-84ea-6a80f640e03d" width="800px" />kishikawa katsumi, kishikawakatsumi@mac.com
KeychainAccess 在 MIT 许可下可用。有关更多信息,请参阅 LICENSE 文件。
AI辅助编程,代码自动修复
Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。
AI小说写作助手,一站式润色、改写、扩写
蛙蛙写作—国内先进的AI写作平台,涵盖小说、学术、社交媒体等多场景。提供续写、改写、润色等功能,助力创作者高效优化写作流程。界面简洁,功能全面,适合各类写作者提升内容品质和工作效率。
全能AI智能助手,随时解答生活与工作的多样问题
问小白,由元石科技研发的AI智能助手,快速准确地解答各种生活和工作问题,包括但不限于搜索、规划和社交互动,帮助用户在日常生活中提高效率,轻松 管理个人事务。
实时语音翻译/同声传译工具
Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需 求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。
一键生成PPT和Word,让学习生活更轻松
讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。
深度推理能力全新升级,全面对标OpenAI o1
科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能 ,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。
一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型
Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。
AI助力,做PPT更简单!
咔片是一款轻量化在线演示设计工具,借助 AI 技术,实现从内容生成到智能设计的一站式 PPT 制作服务。支持多种文档格式导入生成 PPT,提供海 量模板、智能美化、素材替换等功能,适用于销售、教师、学生等各类人群,能高效制作出高品质 PPT,满足不同场景演示需求。
选题、配图、成文,一站式创作,让内容运营更高效
讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。
专业的AI公文写作平台,公文写作神器
AI 材料星,专业的 AI 公文写作辅助平台,为体制内工作人员提供高效的公文写作解决方案。拥有海量公文文库、9 大核心 AI 功能,支持 30 + 文稿类型生成,助力快速完成领导讲话、工作总结、述职报告等材料,提升办公效率,是体制打工人的得力写作神器。
最新AI工具、AI资讯
独家AI资源、AI项目落地
微信扫一扫关注公众号