Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- UICollectionView
- RxCocoa
- 클린 코드
- 리펙터링
- Observable
- 리펙토링
- map
- collectionview
- Xcode
- MVVM
- 스위프트
- combine
- SWIFT
- HIG
- ios
- Human interface guide
- Clean Code
- 리팩토링
- 애니메이션
- swiftUI
- Protocol
- uiscrollview
- swift documentation
- uitableview
- tableView
- rxswift
- ribs
- UITextView
- Refactoring
- clean architecture
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] KeychainAccess프레임워크로 키체인(keychain)관리하기 본문
* 키체인을 사용해서 데이터를 저장해도, 디바이스에서 보안 툴을 가지고 키체인에 저장된 문자열들을 모두 알 수 있기 때문에 암호화 하여 저장하고, 복호화하여 읽도록 필요: ios-development.tistory.com/manage/posts/
Kehchain pod 종속성
pod 'KeychainAccess', '4.1.0'
Clean Architecture에 의해서, 앱을 Domain과 App영역으로 나눈다면, Keychain의 protocol(Domain영역)과 구현(App영역)을 분리
App영역에서 사용할 때는 Domain영역의 값을, 화면전환 할 때 주입해주는 구조로 구성하여, 추후에 테스트하기 쉽게 구현하는 것이 중요
ex) MVVM구조를 사용한다면, ViewModel에 Dependencies라는 struct에 정의
struct Dependencies {
let keychain: KeyValueStore // KeyValueStore는 Domain의 protocol
}
위 내용을 해당 화면으로 이동할 때, KeyValueStore의 구현체를 주입해주는 형태
구조의 이점
- 유지보수에 용이(결합도와 응집도): 키체인 로직에 대해서 수정하고 싶을 때, 구현체만 바꾸어주면 사용하는 입장에서 하나도 수정할 것이 없고 그대로 사용해도 되는 이점)
- 테스트에 용이: 구현체를 따로 만들어서 여러가지 경우를 주입시켜가며 테스트에 이점
앱 구조 설정
앱 구조 및 cocoa pod 여러 프로젝트 의존성 관리 방법은 여기 참고
- 메인 앱: MainProj.xcodeproj
- 도메인: Domain.xcodeproj
- podfile: KeychainAccess 의존성을 MyApp프로젝트에 주입 (아래 파일 입력 후 pod install)
platform :ios, '11.0'
use_frameworks!
inhibit_all_warnings!
workspace 'MyApp'
project 'MyApp/MyApp.project'
project 'Domain/Domain.project'
def data_pods
pod 'KeychainAccess'
end
target 'MyApp' do
project 'MyApp/MyApp.project'
data_pods
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0'
config.build_settings['SWIFT_VERSION'] = '5.1'
end
end
end
KeyChain에 사용될 키 정의
Domain/Constants.swift
//
// Constants.swift
// Domain
//
// Created by 김종권 on 2020/11/15.
//
import Foundation
struct Constants {
struct KeyChainKey {
static let name = "name"
static let email = "eamil"
}
}
- Domain에 keychain관련 기능 프로토콜 추가 "KeyValueStore"
(바뀌지 않을 공통 로직은 extension으로 구현)
//
// KeyValueStore.swift
// Domain
//
// Created by 김종권 on 2020/12/16.
//
import Foundation
public protocol KeyValueStore {
func save(key: String, value: String)
func get(key: String) -> String?
func delete(key: String)
func removeAll()
}
public extension KeyValueStore {
func getName() -> String {
return get(key: Constants.KeyChainKey.name) ?? ""
}
func getEmail() -> String {
return get(key: Constants.KeyChainKey.email) ?? ""
}
func saveName(_ name: String) {
return save(key: Constants.KeyChainKey.name, value: name)
}
func saveEmail(_ email: String) {
return save(key: Constants.KeyChainKey.email, value: email)
}
func deleteUserInfo() {
delete(key: Constants.KeyChainKey.name)
delete(key: Constants.KeyChainKey.email)
}
}
- MyApp에 Keychain관련 싱글턴으로 구현체 추가 "KeychainService"
//
// KeychainService.swift
// MyApp
//
// Created by 김종권 on 2020/11/15.
//
import Foundation
import Domain
import KeychainAccess
public class KeychainService: KeyValueStore {
public static let shared = KeychainService()
private init() {}
let lockCredentials = Keychain()
public func save(key: String, value: String) {
do {
try lockCredentials.set(value, key: key)
} catch {
print(error.localizedDescription)
}
}
public func get(key: String) -> String? {
do {
guard let key = try lockCredentials.get(key) else {
return nil
}
return key
} catch {
print(error.localizedDescription)
return nil
}
}
public func delete(key: String) {
do {
try lockCredentials.remove(key)
} catch {
print(error.localizedDescription)
}
}
public func removeAll() {
do {
try lockCredentials.removeAll()
} catch {
print(error.localizedDescription)
}
}
}
- 주입하는 형태로 사용: KeychainService를 갈아 엎더라도, 결국에 Domain에 정의한 KeyValueStore을 쓰고 있으므로 유지보수에 용이
사용하는 쪽은 (변하지 않는)KeyValueStore 타입을 가지고 있고, 주입시키는 쪽은 (변하는)KeychainService를 사용
//
// ViewController.swift
// MyApp
//
// Created by 김종권 on 2020/11/15.
//
import UIKit
import Domain
class ViewController: UIViewController {
let vm = ViewModel
override func viewDidLoad() {
super.viewDidLoad()
vm = ViewModel(keychain: KeychainService.share)
}
}
class ViewModel {
let keychain: KeyValueStore
init(keychain: Keychain) {
self.keychain = keychain
}
func saveName() {
keychain.saveName("Jake")
}
}
키체인 프레임워크 : KeychainAccess프레임워크
* 전체 소스코드: github.com/JK0369/keychainSample
* 기타) OCP개념을 이용하여 keychain을 사용하는 코드가 있는 글 참고
keychain을 KeychainRepository, KeychainService로 나누고 실제 접근은 KeychainService에서 이루어지도록 하는 코드
'iOS 응용 (swift)' 카테고리의 다른 글
[iOS - swift] 버튼을 누를 경우, 클립보드에 자동 저장 기능, 복사하기, copy (UIPasteboard.general.string) (0) | 2020.11.20 |
---|---|
[iOS - swift] NotificationCenter, RxSwift, Foreground진입 시 동작 (0) | 2020.11.16 |
[iOS - swift] table view에서 특정 separator 삭제 방법 (header의 하단, 마지막 셀의 하단) (0) | 2020.11.12 |
[iOS - swift] iOS14+ 위치 권한 설정 (precise) (0) | 2020.11.08 |
[APNs] Apple push notification service (0) | 2020.11.08 |
Comments