From 39b0b0ed53dac036dc9fb0a19dba98f20ee5e846 Mon Sep 17 00:00:00 2001 From: E-know Date: Sat, 10 Sep 2022 01:54:04 +0900 Subject: [PATCH 01/21] [Feat] Add function for universal links - Add checkLink func in AppData --- AsyncSwift/AsyncSwiftApp.swift | 6 +++++- AsyncSwift/Observed/AppData.swift | 23 ++++++++++++++++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/AsyncSwift/AsyncSwiftApp.swift b/AsyncSwift/AsyncSwiftApp.swift index 4effa71..b5b6c30 100644 --- a/AsyncSwift/AsyncSwiftApp.swift +++ b/AsyncSwift/AsyncSwiftApp.swift @@ -17,7 +17,11 @@ struct AsyncSwiftApp: App { MainTabView() .environmentObject(appData) .onOpenURL { url in - print(url) + if appData.checkLink(url: url) { + print("Success Link URL: \(url)") + } else { + print("Fail Link URL: \(url)") + } } } } diff --git a/AsyncSwift/Observed/AppData.swift b/AsyncSwift/Observed/AppData.swift index 5f29232..07659e4 100644 --- a/AsyncSwift/Observed/AppData.swift +++ b/AsyncSwift/Observed/AppData.swift @@ -9,15 +9,28 @@ import SwiftUI import UIKit final class AppData: ObservableObject { - @Published var currentTab: Tab = .event // Universal Link로 앱진입시 StampView 전환을 위한 변수 + @Published var currentTab: Tab = .event // Universal Link로 앱진입시 StampView 전환을 위한 변수 var scannedSeminarQR = true // Universal Link로 진입시 QR코드 스캔 여부 + + func checkLink(url: URL) -> Bool { + guard let host = URLComponents(url: url, resolvingAgainstBaseURL: true)?.host else { return false } + + switch host { + case Tab.stamp.rawValue: + scannedSeminarQR = true + currentTab = .stamp + default: + currentTab = .ticketing + } + return true + } } enum Tab: String, CaseIterable { - case event - case ticketing - case stamp + case event + case ticketing + case stamp var title: String { rawValue @@ -39,4 +52,4 @@ enum Tab: String, CaseIterable { case .stamp: StampView() } } - } +} From 5496c0f9068ec86793512cc7385a3e14bc21c023 Mon Sep 17 00:00:00 2001 From: E-know Date: Thu, 15 Sep 2022 01:05:59 +0900 Subject: [PATCH 02/21] [Feat] URL Parsing --- AsyncSwift/Observed/AppData.swift | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/AsyncSwift/Observed/AppData.swift b/AsyncSwift/Observed/AppData.swift index 07659e4..d29a6b6 100644 --- a/AsyncSwift/Observed/AppData.swift +++ b/AsyncSwift/Observed/AppData.swift @@ -13,15 +13,30 @@ final class AppData: ObservableObject { var scannedSeminarQR = true // Universal Link로 진입시 QR코드 스캔 여부 func checkLink(url: URL) -> Bool { + // URL Example = https://www.asyncswift.info?seminar=seminar002&tab=ticketing + // URL Example = https://www.asyncswift.info?seminar=seminar002&tab=event guard let host = URLComponents(url: url, resolvingAgainstBaseURL: true)?.host else { return false } - switch host { + var queries: [String: String] = [:] + for item in URLComponents(url: url, resolvingAgainstBaseURL: true)?.queryItems ?? [] { + queries[item.name] = item.value + } + + //TODO: seminar002도 나중에 JSON으로 관리하면 앱 업데이트 할 필요 없이 간편하게 수정 할 수 있을것 같습니다. + if queries["seminar"] != "seminar002" { + return false + } + + switch queries["tab"] { case Tab.stamp.rawValue: scannedSeminarQR = true currentTab = .stamp + case Tab.event.rawValue: + currentTab = .event default: - currentTab = .ticketing + return false } + return true } } From dbbc9bda5d556f700cfe637b2e73677c0117526d Mon Sep 17 00:00:00 2001 From: E-know Date: Thu, 15 Sep 2022 01:30:33 +0900 Subject: [PATCH 03/21] [Feat] Add KeyChain for StampHistory --- AsyncSwift/Observed/AppData.swift | 3 +- AsyncSwift/Observed/KeyChain.swift | 80 ++++++++++++++++++++++++++++++ AsyncSwift/Views/StampView.swift | 2 +- 3 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 AsyncSwift/Observed/KeyChain.swift diff --git a/AsyncSwift/Observed/AppData.swift b/AsyncSwift/Observed/AppData.swift index d29a6b6..912e069 100644 --- a/AsyncSwift/Observed/AppData.swift +++ b/AsyncSwift/Observed/AppData.swift @@ -10,7 +10,6 @@ import UIKit final class AppData: ObservableObject { @Published var currentTab: Tab = .event // Universal Link로 앱진입시 StampView 전환을 위한 변수 - var scannedSeminarQR = true // Universal Link로 진입시 QR코드 스캔 여부 func checkLink(url: URL) -> Bool { // URL Example = https://www.asyncswift.info?seminar=seminar002&tab=ticketing @@ -29,7 +28,7 @@ final class AppData: ObservableObject { switch queries["tab"] { case Tab.stamp.rawValue: - scannedSeminarQR = true + KeyChain.shared.addItem(key: queries["seminar"], pwd: "true") currentTab = .stamp case Tab.event.rawValue: currentTab = .event diff --git a/AsyncSwift/Observed/KeyChain.swift b/AsyncSwift/Observed/KeyChain.swift new file mode 100644 index 0000000..177de37 --- /dev/null +++ b/AsyncSwift/Observed/KeyChain.swift @@ -0,0 +1,80 @@ +// +// KeyChain.swift +// AsyncSwift +// +// Created by Inho Choi on 2022/09/15. +// + +import Foundation + +class KeyChain { + static let shared = KeyChain() + + private init() { } + + func addItem(key: Any, pwd: Any) -> Bool { + let addQuery: [CFString: Any] = [kSecClass: kSecClassGenericPassword, + kSecAttrAccount: key, + kSecValueData: (pwd as AnyObject).data(using: String.Encoding.utf8.rawValue) as Any] + + let result: Bool = { + let status = SecItemAdd(addQuery as CFDictionary, nil) + if status == errSecSuccess { + return true + } else if status == errSecDuplicateItem { + return updateItem(value: pwd, key: key) + } + + print("addItem Error : \(status.description))") + return false + }() + + return result + } + + func getItem(key: Any) -> Any? { + let getQuery: [CFString: Any] = [kSecClass: kSecClassGenericPassword, + kSecAttrAccount: key, + kSecReturnAttributes: true, + kSecReturnData: true] + var item: CFTypeRef? + let result = SecItemCopyMatching(getQuery as CFDictionary, &item) + + if result == errSecSuccess { + if let existingItem = item as? [String: Any], + let data = existingItem[kSecValueData as String] as? Data, + let password = String(data: data, encoding: .utf8) { + return password + } + } + + print("getItem Error : \(result.description)") + return nil + } + + func updateItem(value: Any, key: Any) -> Bool { + let prevQuery: [CFString: Any] = [kSecClass: kSecClassGenericPassword, + kSecAttrAccount: key] + let updateQuery: [CFString: Any] = [kSecValueData: (value as AnyObject).data(using: String.Encoding.utf8.rawValue) as Any] + + let result: Bool = { + let status = SecItemUpdate(prevQuery as CFDictionary, updateQuery as CFDictionary) + if status == errSecSuccess { return true } + + print("updateItem Error : \(status.description)") + return false + }() + + return result + } + + func deleteItem(key: String) -> Bool { + let deleteQuery: [CFString: Any] = [kSecClass: kSecClassGenericPassword, + kSecAttrAccount: key] + let status = SecItemDelete(deleteQuery as CFDictionary) + if status == errSecSuccess { return true } + + print("deleteItem Error : \(status.description)") + return false + } +} diff --git a/AsyncSwift/Views/StampView.swift b/AsyncSwift/Views/StampView.swift index 52621ba..3452e05 100644 --- a/AsyncSwift/Views/StampView.swift +++ b/AsyncSwift/Views/StampView.swift @@ -14,7 +14,7 @@ struct StampView: View { var body: some View { NavigationView { Group { - if appData.scannedSeminarQR { + if let _ = KeyChain.shared.getItem(key: "seminar002") { ZStack { stampBack stampFront From e7a227f3fd2fc767ae01dc8f3a71c740d247f121 Mon Sep 17 00:00:00 2001 From: E-know Date: Thu, 15 Sep 2022 02:00:39 +0900 Subject: [PATCH 04/21] [Feat] Keychain exception handling --- AsyncSwift.xcodeproj/project.pbxproj | 4 ++++ AsyncSwift/Observed/AppData.swift | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/AsyncSwift.xcodeproj/project.pbxproj b/AsyncSwift.xcodeproj/project.pbxproj index 8e225c9..e19cf92 100644 --- a/AsyncSwift.xcodeproj/project.pbxproj +++ b/AsyncSwift.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + B25E600C28D2400500E96C78 /* KeyChain.swift in Sources */ = {isa = PBXBuildFile; fileRef = B25E600B28D2400500E96C78 /* KeyChain.swift */; }; B289943328CA69FF002B9F67 /* StampView+Observed.swift in Sources */ = {isa = PBXBuildFile; fileRef = B289943228CA69FF002B9F67 /* StampView+Observed.swift */; }; B2E1083128C9CD6900C3DD59 /* AppData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2E1083028C9CD6900C3DD59 /* AppData.swift */; }; C63A865F28CA70ED0064C417 /* EventDetailView+Observed.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63A865E28CA70ED0064C417 /* EventDetailView+Observed.swift */; }; @@ -35,6 +36,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + B25E600B28D2400500E96C78 /* KeyChain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyChain.swift; sourceTree = ""; }; B289943228CA69FF002B9F67 /* StampView+Observed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StampView+Observed.swift"; sourceTree = ""; }; B2E1083028C9CD6900C3DD59 /* AppData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppData.swift; sourceTree = ""; }; C63A865E28CA70ED0064C417 /* EventDetailView+Observed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EventDetailView+Observed.swift"; sourceTree = ""; }; @@ -157,6 +159,7 @@ C6F7798A28C9CBC60036773B /* EventView+Observed.swift */, C63A865E28CA70ED0064C417 /* EventDetailView+Observed.swift */, C66DAD4F28CF478700195DEB /* SessionView+Observed.swift */, + B25E600B28D2400500E96C78 /* KeyChain.swift */, B2E1083028C9CD6900C3DD59 /* AppData.swift */, B289943228CA69FF002B9F67 /* StampView+Observed.swift */, E9171EFF28D15426002FAF52 /* TicketingView+Observed.swift */, @@ -246,6 +249,7 @@ C66DAD5028CF478700195DEB /* SessionView+Observed.swift in Sources */, C6E744A028CA557100B7B2BD /* Color+.swift in Sources */, C68DE95128C77DDA00CA4CC8 /* TicketingView.swift in Sources */, + B25E600C28D2400500E96C78 /* KeyChain.swift in Sources */, C6F7798B28C9CBC60036773B /* EventView+Observed.swift in Sources */, E9171F0028D15426002FAF52 /* TicketingView+Observed.swift in Sources */, C6F7798728C9CB3A0036773B /* StampView.swift in Sources */, diff --git a/AsyncSwift/Observed/AppData.swift b/AsyncSwift/Observed/AppData.swift index a6e63cf..c754dc0 100644 --- a/AsyncSwift/Observed/AppData.swift +++ b/AsyncSwift/Observed/AppData.swift @@ -28,7 +28,7 @@ final class AppData: ObservableObject { switch queries["tab"] { case Tab.stamp.rawValue: - KeyChain.shared.addItem(key: queries["seminar"], pwd: "true") + KeyChain.shared.addItem(key: queries["seminar"], pwd: "true") ? print("Adding Stamp History KeyChain is Success") : print("Adding Stamp History is Fail") currentTab = .stamp case Tab.event.rawValue: currentTab = .event From f0b5762204615efd6ca86be38c0c3594f7fb66ca Mon Sep 17 00:00:00 2001 From: E-know Date: Thu, 15 Sep 2022 02:02:24 +0900 Subject: [PATCH 05/21] [Modify] Change variable to higher order function --- AsyncSwift/Observed/AppData.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncSwift/Observed/AppData.swift b/AsyncSwift/Observed/AppData.swift index c754dc0..e62159b 100644 --- a/AsyncSwift/Observed/AppData.swift +++ b/AsyncSwift/Observed/AppData.swift @@ -16,7 +16,7 @@ final class AppData: ObservableObject { // URL Example = https://www.asyncswift.info?seminar=seminar002&tab=event guard let host = URLComponents(url: url, resolvingAgainstBaseURL: true)?.host else { return false } - var queries: [String: String] = [:] + var queries = [String: String]() for item in URLComponents(url: url, resolvingAgainstBaseURL: true)?.queryItems ?? [] { queries[item.name] = item.value } From 4d93dd56ed9292bc3d45d0b4a7a719de9d1b7e13 Mon Sep 17 00:00:00 2001 From: Inho Choi <55151796+E-know@users.noreply.github.com> Date: Thu, 15 Sep 2022 02:31:45 +0900 Subject: [PATCH 06/21] Update AsyncSwift/Observed/KeyChain.swift Co-authored-by: Eunyeong Kim --- AsyncSwift/Observed/KeyChain.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncSwift/Observed/KeyChain.swift b/AsyncSwift/Observed/KeyChain.swift index 177de37..83e28c9 100644 --- a/AsyncSwift/Observed/KeyChain.swift +++ b/AsyncSwift/Observed/KeyChain.swift @@ -7,7 +7,7 @@ import Foundation -class KeyChain { +final class KeyChain { static let shared = KeyChain() private init() { } From 6fe33bf539337672c6441852b6fb3ac8af927096 Mon Sep 17 00:00:00 2001 From: E-know Date: Thu, 15 Sep 2022 02:46:51 +0900 Subject: [PATCH 07/21] =?UTF-8?q?[Modify]=20KeyChain=20=EA=B0=92=20AppData?= =?UTF-8?q?=EC=97=90=20=EC=A0=80=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsyncSwift/Observed/AppData.swift | 3 +++ AsyncSwift/Views/StampView.swift | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/AsyncSwift/Observed/AppData.swift b/AsyncSwift/Observed/AppData.swift index e62159b..f03840d 100644 --- a/AsyncSwift/Observed/AppData.swift +++ b/AsyncSwift/Observed/AppData.swift @@ -10,6 +10,9 @@ import UIKit final class AppData: ObservableObject { @Published var currentTab: Tab = .event // Universal Link로 앱진입시 StampView 전환을 위한 변수 + lazy var doesStampExist: Bool = { + KeyChain.shared.getItem(key: "seminar002") != nil + }() func checkLink(url: URL) -> Bool { // URL Example = https://www.asyncswift.info?seminar=seminar002&tab=ticketing diff --git a/AsyncSwift/Views/StampView.swift b/AsyncSwift/Views/StampView.swift index 3452e05..a45786e 100644 --- a/AsyncSwift/Views/StampView.swift +++ b/AsyncSwift/Views/StampView.swift @@ -14,7 +14,7 @@ struct StampView: View { var body: some View { NavigationView { Group { - if let _ = KeyChain.shared.getItem(key: "seminar002") { + if appData.doesStampExist { ZStack { stampBack stampFront From 7125ad7eab1aac66d4bcf806f3671562e57140c2 Mon Sep 17 00:00:00 2001 From: E-know Date: Thu, 15 Sep 2022 19:55:53 +0900 Subject: [PATCH 08/21] [Feat] seminar002 -> fetch Json File --- AsyncSwift.xcodeproj/project.pbxproj | 14 +++++--- AsyncSwift/Models/Stamp.swift | 12 +++++++ AsyncSwift/Observed/AppData.swift | 48 +++++++++++++++++++++++----- 3 files changed, 62 insertions(+), 12 deletions(-) create mode 100644 AsyncSwift/Models/Stamp.swift diff --git a/AsyncSwift.xcodeproj/project.pbxproj b/AsyncSwift.xcodeproj/project.pbxproj index e1efdc3..1f149c1 100644 --- a/AsyncSwift.xcodeproj/project.pbxproj +++ b/AsyncSwift.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ B25E600C28D2400500E96C78 /* KeyChain.swift in Sources */ = {isa = PBXBuildFile; fileRef = B25E600B28D2400500E96C78 /* KeyChain.swift */; }; B289943328CA69FF002B9F67 /* StampView+Observed.swift in Sources */ = {isa = PBXBuildFile; fileRef = B289943228CA69FF002B9F67 /* StampView+Observed.swift */; }; B2E1083128C9CD6900C3DD59 /* AppData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2E1083028C9CD6900C3DD59 /* AppData.swift */; }; + B2FC6F6328D309FF00D2ACBF /* Stamp.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2FC6F6228D309FF00D2ACBF /* Stamp.swift */; }; C63A865F28CA70ED0064C417 /* EventDetailView+Observed.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63A865E28CA70ED0064C417 /* EventDetailView+Observed.swift */; }; C63A866328CB3D490064C417 /* View+.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63A866228CB3D490064C417 /* View+.swift */; }; C63A866528CB3F6D0064C417 /* DateFormatter+.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63A866428CB3F6D0064C417 /* DateFormatter+.swift */; }; @@ -40,6 +41,7 @@ B25E600B28D2400500E96C78 /* KeyChain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyChain.swift; sourceTree = ""; }; B289943228CA69FF002B9F67 /* StampView+Observed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StampView+Observed.swift"; sourceTree = ""; }; B2E1083028C9CD6900C3DD59 /* AppData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppData.swift; sourceTree = ""; }; + B2FC6F6228D309FF00D2ACBF /* Stamp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stamp.swift; sourceTree = ""; }; C63A865E28CA70ED0064C417 /* EventDetailView+Observed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EventDetailView+Observed.swift"; sourceTree = ""; }; C63A866228CB3D490064C417 /* View+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+.swift"; sourceTree = ""; }; C63A866428CB3F6D0064C417 /* DateFormatter+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateFormatter+.swift"; sourceTree = ""; }; @@ -152,6 +154,7 @@ C66C68D228D1B00A0091F960 /* EventModel.swift */, C66C68D428D1B0130091F960 /* SessionModel.swift */, E94F92C628D2505100D9E759 /* Ticketing.swift */, + B2FC6F6228D309FF00D2ACBF /* Stamp.swift */, ); path = Models; sourceTree = ""; @@ -269,6 +272,7 @@ C63A866528CB3F6D0064C417 /* DateFormatter+.swift in Sources */, C6F7798F28C9D1BF0036773B /* SessionView.swift in Sources */, C66C68D328D1B00A0091F960 /* EventModel.swift in Sources */, + B2FC6F6328D309FF00D2ACBF /* Stamp.swift in Sources */, B2E1083128C9CD6900C3DD59 /* AppData.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -396,10 +400,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = AsyncSwift/AsyncSwift.entitlements; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"AsyncSwift/Preview Content\""; - DEVELOPMENT_TEAM = 76AJ433CP5; + DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AsyncSwift/Info.plist; @@ -419,6 +423,7 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.kim.AsyncSwift; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; @@ -431,10 +436,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = AsyncSwift/AsyncSwift.entitlements; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"AsyncSwift/Preview Content\""; - DEVELOPMENT_TEAM = 76AJ433CP5; + DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AsyncSwift/Info.plist; @@ -454,6 +459,7 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.kim.AsyncSwift; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; diff --git a/AsyncSwift/Models/Stamp.swift b/AsyncSwift/Models/Stamp.swift new file mode 100644 index 0000000..9bdb2ab --- /dev/null +++ b/AsyncSwift/Models/Stamp.swift @@ -0,0 +1,12 @@ +// +// Stamp.swift +// AsyncSwift +// +// Created by Inho Choi on 2022/09/15. +// + +import Foundation + +struct Stamp: Codable { + let title: String +} diff --git a/AsyncSwift/Observed/AppData.swift b/AsyncSwift/Observed/AppData.swift index f03840d..a22fafd 100644 --- a/AsyncSwift/Observed/AppData.swift +++ b/AsyncSwift/Observed/AppData.swift @@ -10,13 +10,15 @@ import UIKit final class AppData: ObservableObject { @Published var currentTab: Tab = .event // Universal Link로 앱진입시 StampView 전환을 위한 변수 + + private var currentStamp: Stamp? lazy var doesStampExist: Bool = { - KeyChain.shared.getItem(key: "seminar002") != nil + KeyChain.shared.getItem(key: currentStamp?.title) != nil }() func checkLink(url: URL) -> Bool { - // URL Example = https://www.asyncswift.info?seminar=seminar002&tab=ticketing - // URL Example = https://www.asyncswift.info?seminar=seminar002&tab=event + // URL Example = https://www.asyncswift.info?tab=ticketing + // URL Example = https://www.asyncswift.info?tab=event guard let host = URLComponents(url: url, resolvingAgainstBaseURL: true)?.host else { return false } var queries = [String: String]() @@ -24,14 +26,13 @@ final class AppData: ObservableObject { queries[item.name] = item.value } - //TODO: seminar002도 나중에 JSON으로 관리하면 앱 업데이트 할 필요 없이 간편하게 수정 할 수 있을것 같습니다. - if queries["seminar"] != "seminar002" { - return false - } + fetchCurrentStamp() + + guard let currentStampName = currentStamp?.title else { return false } switch queries["tab"] { case Tab.stamp.rawValue: - KeyChain.shared.addItem(key: queries["seminar"], pwd: "true") ? print("Adding Stamp History KeyChain is Success") : print("Adding Stamp History is Fail") + KeyChain.shared.addItem(key: currentStampName, pwd: "true") ? print("Adding Stamp History KeyChain is Success") : print("Adding Stamp History is Fail") currentTab = .stamp case Tab.event.rawValue: currentTab = .event @@ -41,6 +42,37 @@ final class AppData: ObservableObject { return true } + + private func fetchCurrentStamp() { + guard + let url = URL(string: "https://raw.githubusercontent.com/Async-Swift/jsonstorage/main/stamp.json") + else { return } + + + let request = URLRequest(url: url) + let dataTask = URLSession.shared.dataTask(with: request) { data, response, _ in + guard + let response = response as? HTTPURLResponse, + response.statusCode == 200, + let data = data + else { return } + + DispatchQueue.main.async { [weak self] in + do { + let stamp = try JSONDecoder().decode(Stamp.self, from: data) + self?.currentStamp = stamp + if KeyChain.shared.addItem(key: self?.currentStamp?.title, pwd: "true") { + print("Stamp history saved in KeyChian") + } else { + print("Stamp recording failed to save to KeyChian.") + } + } catch { + self?.currentStamp = nil + } + } + } + dataTask.resume() + } } From beb398bb87b6ebd1307701f8c9bf539dae0cb418 Mon Sep 17 00:00:00 2001 From: E-know Date: Fri, 16 Sep 2022 00:01:51 +0900 Subject: [PATCH 09/21] [Fix] Change when Json files are called --- AsyncSwift/Observed/AppData.swift | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/AsyncSwift/Observed/AppData.swift b/AsyncSwift/Observed/AppData.swift index a22fafd..3f9e580 100644 --- a/AsyncSwift/Observed/AppData.swift +++ b/AsyncSwift/Observed/AppData.swift @@ -15,6 +15,10 @@ final class AppData: ObservableObject { lazy var doesStampExist: Bool = { KeyChain.shared.getItem(key: currentStamp?.title) != nil }() + + init(){ + fetchCurrentStamp() + } func checkLink(url: URL) -> Bool { // URL Example = https://www.asyncswift.info?tab=ticketing @@ -26,13 +30,12 @@ final class AppData: ObservableObject { queries[item.name] = item.value } - fetchCurrentStamp() - guard let currentStampName = currentStamp?.title else { return false } switch queries["tab"] { case Tab.stamp.rawValue: KeyChain.shared.addItem(key: currentStampName, pwd: "true") ? print("Adding Stamp History KeyChain is Success") : print("Adding Stamp History is Fail") + self.doesStampExist = true currentTab = .stamp case Tab.event.rawValue: currentTab = .event @@ -61,11 +64,6 @@ final class AppData: ObservableObject { do { let stamp = try JSONDecoder().decode(Stamp.self, from: data) self?.currentStamp = stamp - if KeyChain.shared.addItem(key: self?.currentStamp?.title, pwd: "true") { - print("Stamp history saved in KeyChian") - } else { - print("Stamp recording failed to save to KeyChian.") - } } catch { self?.currentStamp = nil } From e9c08862b49e9415cea1439a2ce1c6ff7d91e394 Mon Sep 17 00:00:00 2001 From: E-know Date: Fri, 16 Sep 2022 00:21:04 +0900 Subject: [PATCH 10/21] [Modify] Project Settings --- AsyncSwift.xcodeproj/project.pbxproj | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/AsyncSwift.xcodeproj/project.pbxproj b/AsyncSwift.xcodeproj/project.pbxproj index 1f149c1..7272948 100644 --- a/AsyncSwift.xcodeproj/project.pbxproj +++ b/AsyncSwift.xcodeproj/project.pbxproj @@ -400,10 +400,11 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = AsyncSwift/AsyncSwift.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"AsyncSwift/Preview Content\""; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = 76AJ433CP5; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AsyncSwift/Info.plist; @@ -423,7 +424,7 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.kim.AsyncSwift; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; + PROVISIONING_PROFILE_SPECIFIER = AsyncSwiftProvisioningProfile; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; @@ -436,10 +437,11 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = AsyncSwift/AsyncSwift.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"AsyncSwift/Preview Content\""; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = 76AJ433CP5; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AsyncSwift/Info.plist; @@ -459,7 +461,7 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.kim.AsyncSwift; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; + PROVISIONING_PROFILE_SPECIFIER = AsyncSwiftProvisioningProfile; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; From 4df1fba1b84ed4f471aa47a1950d0ba111f0a22d Mon Sep 17 00:00:00 2001 From: E-know Date: Fri, 16 Sep 2022 00:21:28 +0900 Subject: [PATCH 11/21] [Modify] Stamp Model --- AsyncSwift/Models/Stamp.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncSwift/Models/Stamp.swift b/AsyncSwift/Models/Stamp.swift index 9bdb2ab..d50375b 100644 --- a/AsyncSwift/Models/Stamp.swift +++ b/AsyncSwift/Models/Stamp.swift @@ -7,6 +7,6 @@ import Foundation -struct Stamp: Codable { +struct Stamp: Decodable { let title: String } From f478e6dc1f78cb71a3027febf9d70f567a5072e3 Mon Sep 17 00:00:00 2001 From: E-know Date: Fri, 16 Sep 2022 00:23:29 +0900 Subject: [PATCH 12/21] [Modify] Variable Description and Rename --- AsyncSwift/Observed/AppData.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/AsyncSwift/Observed/AppData.swift b/AsyncSwift/Observed/AppData.swift index 3f9e580..4170651 100644 --- a/AsyncSwift/Observed/AppData.swift +++ b/AsyncSwift/Observed/AppData.swift @@ -9,10 +9,11 @@ import SwiftUI import UIKit final class AppData: ObservableObject { - @Published var currentTab: Tab = .event // Universal Link로 앱진입시 StampView 전환을 위한 변수 + /// Universal Link로 앱진입시 StampView 전환을 위한 변수 + @Published var currentTab: Tab = .event private var currentStamp: Stamp? - lazy var doesStampExist: Bool = { + lazy var isStampExist: Bool = { KeyChain.shared.getItem(key: currentStamp?.title) != nil }() @@ -35,7 +36,7 @@ final class AppData: ObservableObject { switch queries["tab"] { case Tab.stamp.rawValue: KeyChain.shared.addItem(key: currentStampName, pwd: "true") ? print("Adding Stamp History KeyChain is Success") : print("Adding Stamp History is Fail") - self.doesStampExist = true + self.isStampExist = true currentTab = .stamp case Tab.event.rawValue: currentTab = .event From 170ea255b0948a330c32a30c2344265d96c98b17 Mon Sep 17 00:00:00 2001 From: Inho Choi <55151796+E-know@users.noreply.github.com> Date: Fri, 16 Sep 2022 00:34:32 +0900 Subject: [PATCH 13/21] Update AsyncSwift/Observed/AppData.swift Co-authored-by: Eunyeong Kim --- AsyncSwift/Observed/AppData.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncSwift/Observed/AppData.swift b/AsyncSwift/Observed/AppData.swift index 3f9e580..5f3938f 100644 --- a/AsyncSwift/Observed/AppData.swift +++ b/AsyncSwift/Observed/AppData.swift @@ -23,7 +23,7 @@ final class AppData: ObservableObject { func checkLink(url: URL) -> Bool { // URL Example = https://www.asyncswift.info?tab=ticketing // URL Example = https://www.asyncswift.info?tab=event - guard let host = URLComponents(url: url, resolvingAgainstBaseURL: true)?.host else { return false } + guard URLComponents(url: url, resolvingAgainstBaseURL: true)?.host != nil else { return false } var queries = [String: String]() for item in URLComponents(url: url, resolvingAgainstBaseURL: true)?.queryItems ?? [] { From b3be3935308a006ac139b5583ea5c7d17e94f497 Mon Sep 17 00:00:00 2001 From: E-know Date: Fri, 16 Sep 2022 00:38:00 +0900 Subject: [PATCH 14/21] [Modify] Change If -> switch --- AsyncSwift/Observed/KeyChain.swift | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/AsyncSwift/Observed/KeyChain.swift b/AsyncSwift/Observed/KeyChain.swift index 83e28c9..ccb4fc6 100644 --- a/AsyncSwift/Observed/KeyChain.swift +++ b/AsyncSwift/Observed/KeyChain.swift @@ -19,14 +19,16 @@ final class KeyChain { let result: Bool = { let status = SecItemAdd(addQuery as CFDictionary, nil) - if status == errSecSuccess { + + switch status { + case errSecSuccess: return true - } else if status == errSecDuplicateItem { + case errSecDuplicateItem: return updateItem(value: pwd, key: key) + default: + print("addItem Error : \(status.description))") + return false } - - print("addItem Error : \(status.description))") - return false }() return result From cc3b0b7e92fc4ba2065a827e881cce0263dbecb6 Mon Sep 17 00:00:00 2001 From: E-know Date: Fri, 16 Sep 2022 00:41:03 +0900 Subject: [PATCH 15/21] [Modify] Rename Variable --- AsyncSwift/Views/StampView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncSwift/Views/StampView.swift b/AsyncSwift/Views/StampView.swift index a45786e..8698985 100644 --- a/AsyncSwift/Views/StampView.swift +++ b/AsyncSwift/Views/StampView.swift @@ -14,7 +14,7 @@ struct StampView: View { var body: some View { NavigationView { Group { - if appData.doesStampExist { + if appData.isStampExist { ZStack { stampBack stampFront From ac161f9cb65f4f4a79721bcb653295b696ed94c6 Mon Sep 17 00:00:00 2001 From: E-know Date: Fri, 16 Sep 2022 00:41:19 +0900 Subject: [PATCH 16/21] [Modify] Change Keychain return value --- AsyncSwift/Observed/KeyChain.swift | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/AsyncSwift/Observed/KeyChain.swift b/AsyncSwift/Observed/KeyChain.swift index ccb4fc6..8304442 100644 --- a/AsyncSwift/Observed/KeyChain.swift +++ b/AsyncSwift/Observed/KeyChain.swift @@ -17,21 +17,17 @@ final class KeyChain { kSecAttrAccount: key, kSecValueData: (pwd as AnyObject).data(using: String.Encoding.utf8.rawValue) as Any] - let result: Bool = { - let status = SecItemAdd(addQuery as CFDictionary, nil) - - switch status { - case errSecSuccess: - return true - case errSecDuplicateItem: - return updateItem(value: pwd, key: key) - default: - print("addItem Error : \(status.description))") - return false - } - }() + let status = SecItemAdd(addQuery as CFDictionary, nil) - return result + switch status { + case errSecSuccess: + return true + case errSecDuplicateItem: + return updateItem(value: pwd, key: key) + default: + print("addItem Error : \(status.description))") + return false + } } func getItem(key: Any) -> Any? { From 2a0956fdedbf8a1a9cf20f58ae6410e02b6ff5e6 Mon Sep 17 00:00:00 2001 From: Inho Choi <55151796+E-know@users.noreply.github.com> Date: Fri, 16 Sep 2022 00:43:15 +0900 Subject: [PATCH 17/21] Update AsyncSwift/Observed/KeyChain.swift Co-authored-by: Eunyeong Kim --- AsyncSwift/Observed/KeyChain.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/AsyncSwift/Observed/KeyChain.swift b/AsyncSwift/Observed/KeyChain.swift index 8304442..d9535ce 100644 --- a/AsyncSwift/Observed/KeyChain.swift +++ b/AsyncSwift/Observed/KeyChain.swift @@ -57,10 +57,7 @@ final class KeyChain { let result: Bool = { let status = SecItemUpdate(prevQuery as CFDictionary, updateQuery as CFDictionary) - if status == errSecSuccess { return true } - - print("updateItem Error : \(status.description)") - return false + return status == errSecSuccess }() return result From 573dabf0f3b7dccfab4e85bc98c8e65434557818 Mon Sep 17 00:00:00 2001 From: Inho Choi <55151796+E-know@users.noreply.github.com> Date: Fri, 16 Sep 2022 00:43:36 +0900 Subject: [PATCH 18/21] Update AsyncSwift/Observed/KeyChain.swift Co-authored-by: Eunyeong Kim --- AsyncSwift/Observed/KeyChain.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AsyncSwift/Observed/KeyChain.swift b/AsyncSwift/Observed/KeyChain.swift index d9535ce..3c741a5 100644 --- a/AsyncSwift/Observed/KeyChain.swift +++ b/AsyncSwift/Observed/KeyChain.swift @@ -38,10 +38,10 @@ final class KeyChain { var item: CFTypeRef? let result = SecItemCopyMatching(getQuery as CFDictionary, &item) - if result == errSecSuccess { - if let existingItem = item as? [String: Any], - let data = existingItem[kSecValueData as String] as? Data, - let password = String(data: data, encoding: .utf8) { + if result == errSecSuccess, + let existingItem = item as? [String: Any], + let data = existingItem[kSecValueData as String] as? Data, + let password = String(data: data, encoding: .utf8) { return password } } From ef2c32158f0c4bfe2e7d0c5d294449a8b22f1d7f Mon Sep 17 00:00:00 2001 From: E-know Date: Fri, 16 Sep 2022 00:46:12 +0900 Subject: [PATCH 19/21] [Modify] Weak reference guard handling --- AsyncSwift/Observed/AppData.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/AsyncSwift/Observed/AppData.swift b/AsyncSwift/Observed/AppData.swift index 8d192ba..dc1eb26 100644 --- a/AsyncSwift/Observed/AppData.swift +++ b/AsyncSwift/Observed/AppData.swift @@ -62,11 +62,12 @@ final class AppData: ObservableObject { else { return } DispatchQueue.main.async { [weak self] in + guard let self = self else {return } do { let stamp = try JSONDecoder().decode(Stamp.self, from: data) - self?.currentStamp = stamp + self.currentStamp = stamp } catch { - self?.currentStamp = nil + self.currentStamp = nil } } } From 4f205c0e7727ad9be15d5aac6ff140600daa6bef Mon Sep 17 00:00:00 2001 From: E-know Date: Fri, 16 Sep 2022 00:47:58 +0900 Subject: [PATCH 20/21] [Fix] Fix code error --- AsyncSwift/Observed/KeyChain.swift | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/AsyncSwift/Observed/KeyChain.swift b/AsyncSwift/Observed/KeyChain.swift index 3c741a5..f6d829c 100644 --- a/AsyncSwift/Observed/KeyChain.swift +++ b/AsyncSwift/Observed/KeyChain.swift @@ -6,6 +6,7 @@ // import Foundation +import UIKit final class KeyChain { static let shared = KeyChain() @@ -38,14 +39,12 @@ final class KeyChain { var item: CFTypeRef? let result = SecItemCopyMatching(getQuery as CFDictionary, &item) - if result == errSecSuccess, - let existingItem = item as? [String: Any], - let data = existingItem[kSecValueData as String] as? Data, - let password = String(data: data, encoding: .utf8) { - return password - } + if result == errSecSuccess, + let existingItem = item as? [String: Any], + let data = existingItem[kSecValueData as String] as? Data, + let password = String(data: data, encoding: .utf8) { + return password } - print("getItem Error : \(result.description)") return nil } From 23ecdb9d6f1f806d81c4cb50712d83d2ed4fa843 Mon Sep 17 00:00:00 2001 From: E-know Date: Fri, 16 Sep 2022 00:49:54 +0900 Subject: [PATCH 21/21] [Modify] Change to If statement return --- AsyncSwift/Observed/KeyChain.swift | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/AsyncSwift/Observed/KeyChain.swift b/AsyncSwift/Observed/KeyChain.swift index f6d829c..704dcfc 100644 --- a/AsyncSwift/Observed/KeyChain.swift +++ b/AsyncSwift/Observed/KeyChain.swift @@ -66,9 +66,11 @@ final class KeyChain { let deleteQuery: [CFString: Any] = [kSecClass: kSecClassGenericPassword, kSecAttrAccount: key] let status = SecItemDelete(deleteQuery as CFDictionary) - if status == errSecSuccess { return true } - - print("deleteItem Error : \(status.description)") - return false + if status == errSecSuccess { + return true + } else { + print("deleteItem Error : \(status.description)") + return false + } } }