diff --git a/WebAppUIKitBase.xcodeproj/project.pbxproj b/WebAppUIKitBase.xcodeproj/project.pbxproj index 29fdb8b..39e5df9 100644 --- a/WebAppUIKitBase.xcodeproj/project.pbxproj +++ b/WebAppUIKitBase.xcodeproj/project.pbxproj @@ -6,6 +6,11 @@ objectVersion = 77; objects = { +/* Begin PBXBuildFile section */ + A7D80D4D2CC5DFFF00E93F4D /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = A7D80D4C2CC5DFFF00E93F4D /* SnapKit */; }; + A7D80D502CC5E01D00E93F4D /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = A7D80D4F2CC5E01D00E93F4D /* Alamofire */; }; +/* End PBXBuildFile section */ + /* Begin PBXFileReference section */ A749CDFD2CC5D8CD0038D13D /* WebAppUIKitBase.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WebAppUIKitBase.app; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -36,6 +41,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + A7D80D4D2CC5DFFF00E93F4D /* SnapKit in Frameworks */, + A7D80D502CC5E01D00E93F4D /* Alamofire in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -78,6 +85,8 @@ ); name = WebAppUIKitBase; packageProductDependencies = ( + A7D80D4C2CC5DFFF00E93F4D /* SnapKit */, + A7D80D4F2CC5E01D00E93F4D /* Alamofire */, ); productName = WebAppUIKitBase; productReference = A749CDFD2CC5D8CD0038D13D /* WebAppUIKitBase.app */; @@ -107,6 +116,10 @@ ); mainGroup = A749CDF42CC5D8CD0038D13D; minimizedProjectReferenceProxies = 1; + packageReferences = ( + A7D80D4B2CC5DFFF00E93F4D /* XCRemoteSwiftPackageReference "SnapKit" */, + A7D80D4E2CC5E01D00E93F4D /* XCRemoteSwiftPackageReference "Alamofire" */, + ); preferredProjectObjectVersion = 77; productRefGroup = A749CDFE2CC5D8CD0038D13D /* Products */; projectDirPath = ""; @@ -144,20 +157,20 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2.0.8.1; DEVELOPMENT_TEAM = 45MYH7ZHUQ; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WebAppUIKitBase/Info.plist; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "검색과 길안내를 위해 사용합니다."; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UIMainStoryboardFile = Main; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 2.0.8; PRODUCT_BUNDLE_IDENTIFIER = "kr.kro.sean-k.WebAppUIKitBase"; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -176,20 +189,20 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2.0.8.1; DEVELOPMENT_TEAM = 45MYH7ZHUQ; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WebAppUIKitBase/Info.plist; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "검색과 길안내를 위해 사용합니다."; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UIMainStoryboardFile = Main; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 2.0.8; PRODUCT_BUNDLE_IDENTIFIER = "kr.kro.sean-k.WebAppUIKitBase"; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -343,6 +356,38 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + A7D80D4B2CC5DFFF00E93F4D /* XCRemoteSwiftPackageReference "SnapKit" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/SnapKit/SnapKit.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 5.7.1; + }; + }; + A7D80D4E2CC5E01D00E93F4D /* XCRemoteSwiftPackageReference "Alamofire" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/Alamofire/Alamofire.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 5.10.1; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + A7D80D4C2CC5DFFF00E93F4D /* SnapKit */ = { + isa = XCSwiftPackageProductDependency; + package = A7D80D4B2CC5DFFF00E93F4D /* XCRemoteSwiftPackageReference "SnapKit" */; + productName = SnapKit; + }; + A7D80D4F2CC5E01D00E93F4D /* Alamofire */ = { + isa = XCSwiftPackageProductDependency; + package = A7D80D4E2CC5E01D00E93F4D /* XCRemoteSwiftPackageReference "Alamofire" */; + productName = Alamofire; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = A749CDF52CC5D8CD0038D13D /* Project object */; } diff --git a/WebAppUIKitBase.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/WebAppUIKitBase.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..1d89461 --- /dev/null +++ b/WebAppUIKitBase.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,24 @@ +{ + "originHash" : "4d1117f641c000c6545947e4d48e126cc17473ec53f643df82900a33ad4936b2", + "pins" : [ + { + "identity" : "alamofire", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Alamofire/Alamofire.git", + "state" : { + "revision" : "e16d3481f5ed35f0472cb93350085853d754913f", + "version" : "5.10.1" + } + }, + { + "identity" : "snapkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SnapKit/SnapKit.git", + "state" : { + "revision" : "2842e6e84e82eb9a8dac0100ca90d9444b0307f4", + "version" : "5.7.1" + } + } + ], + "version" : 3 +} diff --git a/WebAppUIKitBase.xcodeproj/project.xcworkspace/xcuserdata/seankim.xcuserdatad/UserInterfaceState.xcuserstate b/WebAppUIKitBase.xcodeproj/project.xcworkspace/xcuserdata/seankim.xcuserdatad/UserInterfaceState.xcuserstate index 6c34935..a0b0982 100644 Binary files a/WebAppUIKitBase.xcodeproj/project.xcworkspace/xcuserdata/seankim.xcuserdatad/UserInterfaceState.xcuserstate and b/WebAppUIKitBase.xcodeproj/project.xcworkspace/xcuserdata/seankim.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/WebAppUIKitBase.xcodeproj/xcuserdata/seankim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/WebAppUIKitBase.xcodeproj/xcuserdata/seankim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..f49fa77 --- /dev/null +++ b/WebAppUIKitBase.xcodeproj/xcuserdata/seankim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/WebAppUIKitBase/AppDelegate.swift b/WebAppUIKitBase/AppDelegate.swift deleted file mode 100644 index 2678098..0000000 --- a/WebAppUIKitBase/AppDelegate.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// AppDelegate.swift -// WebAppUIKitBase -// -// Created by Sean Kim on 10/21/24. -// - -import UIKit - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - - - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - return true - } - - // MARK: UISceneSession Lifecycle - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - // Called when a new scene session is being created. - // Use this method to select a configuration to create the new scene with. - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { - // Called when the user discards a scene session. - // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. - // Use this method to release any resources that were specific to the discarded scenes, as they will not return. - } - - -} - diff --git a/WebAppUIKitBase/Common/AppDelegate.swift b/WebAppUIKitBase/Common/AppDelegate.swift index 4dd12c0..a110ff7 100644 --- a/WebAppUIKitBase/Common/AppDelegate.swift +++ b/WebAppUIKitBase/Common/AppDelegate.swift @@ -7,25 +7,43 @@ import UIKit +import AdSupport +import AppTrackingTransparency + @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. + + + + + return true } - - // MARK: UISceneSession Lifecycle - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - // Called when a new scene session is being created. - // Use this method to select a configuration to create the new scene with. - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + + /// 앱이 Active 로 전환될때 호출 : back -> fore 시 호출 + func applicationDidBecomeActive(_ application: UIApplication) { + + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + ATTrackingManager.requestTrackingAuthorization(completionHandler: { status in + switch status { + case .notDetermined: + printLog(status) + case .restricted: + printLog(status) + case .denied: + printLog(status) + case .authorized: + printLog(status) + } + }) + } } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { - // Called when the user discards a scene session. - // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. - // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + + func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { + let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) } + let token = tokenParts.joined() + printLog("Device Tokens: \(token)") } diff --git a/WebAppUIKitBase/Common/CommonUtils.swift b/WebAppUIKitBase/Common/CommonUtils.swift index f62c8e7..931064e 100644 --- a/WebAppUIKitBase/Common/CommonUtils.swift +++ b/WebAppUIKitBase/Common/CommonUtils.swift @@ -5,4 +5,128 @@ // Created by Sean Kim on 10/21/24. // -import Foundation +import UIKit +import CoreLocation + +import Alamofire + +class CommonUtils: NSObject, CLLocationManagerDelegate { + static let shared: CommonUtils = CommonUtils() + + private override init() {} + + //MARK: - Location + weak var locationDelegate: LocationDelegate? + + let locationManager: CLLocationManager = { + let manager = CLLocationManager() + manager.desiredAccuracy = kCLLocationAccuracyBest + manager.distanceFilter = kCLDistanceFilterNone + return manager + }() + var lastLocation: CLLocation? + + + public func checkLocationPermission() { + printLog("[위치] Check Loc Permission") + locationManager.delegate = self + locationManager.requestWhenInUseAuthorization() + self.toggleUpdatingLocation(true) + } + + public func toggleUpdatingLocation(_ toggle: Bool) { + if toggle { + locationManager.startUpdatingLocation() + } else { + locationManager.stopUpdatingLocation() + } + } + + // 14이상인 경우만 산정해서 한거라서 14.0 미만을 원하면 다른 메서드를 만들어야 함 + func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { + printLog("[위치] locationManagerDidChangeAuthorization") // 처음 불러 올 떄 요거 불려짐 + switch manager.authorizationStatus { + case .authorizedAlways, .authorizedWhenInUse, .authorized: + printLog("[위치] 권한 허용") + self.locationDelegate?.checkPermission(true) + self.toggleUpdatingLocation(true) + default: + printLog("[위치] 권한 미허용 & 기타 오류") + self.locationDelegate?.checkPermission(false) + self.toggleUpdatingLocation(false) + + } + } + + // 14이상인 경우만 산정해서 한거라서 14.0 미만을 원하면 다른 메서드를 만들어야 함 + func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { + printLog("[위치] didUpdateLocations") // 요건 값을 가져올 때 불려짐 + switch manager.authorizationStatus { + case .authorizedAlways, .authorizedWhenInUse: + printLog("[위치] 권한 허용") + self.locationDelegate?.checkPermission(true) + if let location = locations.first{ + printLog("[위치] 정보 수신 성공") + self.locationDelegate?.getLocation(location) + } + default: + printLog("[위치] 권한 미허용 & 기타 오류") + self.locationDelegate?.checkPermission(false) + } + } + + func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { + printLog("[위치] didFailWithError") + self.locationDelegate?.checkPermission(false) + } + + +// MARK: - URL + func afGET(url: String, param: [String:String], headers: HTTPHeaders?) async throws -> Any { + return try await withCheckedThrowingContinuation { continuation in + AF.request(url, + method: .get, + parameters: param, + headers: headers) + .validate(statusCode: 200 ..< 300) + .responseString { response in + printLog("[LOG] response: \(response)") + switch response.result { + case .success(let value): + printLog("[LOG]") + continuation.resume(returning: value) + case .failure(let error): + printLog("[LOG]") + continuation.resume(throwing: error) + } + } + } + } + + public func jsonToDict(_ input: String) -> [String: Any] { + if let jsonData = input.data(using: .utf8){ + do { + if let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] { + return jsonObject + } + } catch let error { // 이 부분 + printLog("JSON ERROR: \(error))") + } + } + return [:] + } + + public func jsonToType(_ input: String, as type: T.Type) -> T? { + if let jsonData = input.data(using: .utf8) { + do { + let decodedObject = try JSONDecoder().decode(T.self, from: jsonData) + return decodedObject + } catch let error { + printLog("JSON 디코딩 오류: \(error)") + } + } + return nil + } + +} + diff --git a/WebAppUIKitBase/Common/Prefix.swift b/WebAppUIKitBase/Common/Prefix.swift index e9c4a3b..ff44f75 100644 --- a/WebAppUIKitBase/Common/Prefix.swift +++ b/WebAppUIKitBase/Common/Prefix.swift @@ -4,7 +4,7 @@ // // Created by Sean Kim on 2/20/24. // -import SwiftUI +import UIKit // MARK: - TYPEALIAS typealias VOID_TO_VOID = () -> () @@ -26,13 +26,6 @@ public func printLog(_ object: T, _ file: String = #file, _ function: String #if DEBUG let dateString = Date().convertString("yyyy/MM/dd HH:mm:ss:SSS") Swift.print( -// """ -// __________ __________ -// |* TIME = [\(dateString)] || FILE = [\(file.lastPathComponent)] -// | NAME = [\(function)] || LINE = [\(line)] -// |>>> PRINT = \(object) -//  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ -// """ """ __________ __________ __________ __________ * LOCATION : [\(file.lastPathComponent) : \(line)] - \(function) @@ -149,9 +142,6 @@ func copyToClipboard(_ text: String){ -// MARK: - CUSTOM COMPONENTS - - // MARK: - EXTENSION extension String { /// 마지막 경로 구성 요소 @@ -379,34 +369,27 @@ extension Date { } } - -extension Font { - enum NPS_Font : String { - case regular - case bold +extension UIViewController { + public func makeUIAlert(title: String, message: String, okTitle: String, okAction:((UIAlertAction) -> Void)? = nil, completion: (() -> ())? = nil) { + let alertController = UIAlertController(title: "\(title)", message: "\(message)", preferredStyle: .alert) + let okAction = UIAlertAction(title: "\(okTitle)", style: .default, handler: okAction) + alertController.addAction(okAction) + self.present(alertController, animated: true, completion: completion) + } + + public func makeUITwoAlert(title: String, message: String, okTitle: String, okAction:((UIAlertAction) -> Void)? = nil, cancelTitle: String, cancelAction:((UIAlertAction) -> Void)? = nil, completion: (() -> ())? = nil) { + let alertController = UIAlertController(title: "\(title)", message: "\(message)", preferredStyle: .alert) + let okAction = UIAlertAction(title: "\(okTitle)", style: .default, handler: okAction) + alertController.addAction(okAction) - var value: String { - switch self { - case .regular: - return "NPS-font-Regular" - case .bold: - return "NPS-font-Bold" - } - } + let cancelAction = UIAlertAction(title: "\(cancelTitle)", style: .cancel, handler: cancelAction) + alertController.addAction(cancelAction) + + self.present(alertController, animated: true, completion: completion) } - - static func nps(font: NPS_Font = .regular, size: CGFloat = 12) -> Font { - return .custom(font.value, size: size) - } - - } -extension View { - func endTextEditing() { - UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) - } -} + // MARK: - ANNOTATION diff --git a/WebAppUIKitBase/Common/Protocol/LoactionProtocol.swift b/WebAppUIKitBase/Common/Protocol/LoactionProtocol.swift index a351262..034daa4 100644 --- a/WebAppUIKitBase/Common/Protocol/LoactionProtocol.swift +++ b/WebAppUIKitBase/Common/Protocol/LoactionProtocol.swift @@ -5,4 +5,15 @@ // Created by Sean Kim on 10/21/24. // -import Foundation +//import Foundation +import CoreLocation + +protocol LocationDelegate: NSObject { + func checkPermission(_ type: Bool) + func getLocation(_ location: CLLocation) +} + +extension LocationDelegate { + func checkPermission(_ type: Bool) {} + func getLocation(_ location: CLLocation) {} +} diff --git a/WebAppUIKitBase/Common/SceneDelegate.swift b/WebAppUIKitBase/Common/SceneDelegate.swift index 8838e81..980d035 100644 --- a/WebAppUIKitBase/Common/SceneDelegate.swift +++ b/WebAppUIKitBase/Common/SceneDelegate.swift @@ -22,34 +22,15 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { window?.makeKeyAndVisible() } - func sceneDidDisconnect(_ scene: UIScene) { - // Called as the scene is being released by the system. - // This occurs shortly after the scene enters the background, or when its session is discarded. - // Release any resources associated with this scene that can be re-created the next time the scene connects. - // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). + func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { + guard let url = URLContexts.first?.url else { + return + } } - - func sceneDidBecomeActive(_ scene: UIScene) { - // Called when the scene has moved from an inactive state to an active state. - // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. - } - - func sceneWillResignActive(_ scene: UIScene) { - // Called when the scene will move from an active state to an inactive state. - // This may occur due to temporary interruptions (ex. an incoming phone call). - } - - func sceneWillEnterForeground(_ scene: UIScene) { - // Called as the scene transitions from the background to the foreground. - // Use this method to undo the changes made on entering the background. - } - - func sceneDidEnterBackground(_ scene: UIScene) { - // Called as the scene transitions from the foreground to the background. - // Use this method to save data, release shared resources, and store enough scene-specific state information - // to restore the scene back to its current state. - } - + + + + } diff --git a/WebAppUIKitBase/Info.plist b/WebAppUIKitBase/Info.plist index dd3c9af..0eb786d 100644 --- a/WebAppUIKitBase/Info.plist +++ b/WebAppUIKitBase/Info.plist @@ -15,8 +15,6 @@ Default Configuration UISceneDelegateClassName $(PRODUCT_MODULE_NAME).SceneDelegate - UISceneStoryboardFile - Main diff --git a/WebAppUIKitBase/IntroVC.swift b/WebAppUIKitBase/IntroVC.swift deleted file mode 100644 index c03da97..0000000 --- a/WebAppUIKitBase/IntroVC.swift +++ /dev/null @@ -1,8 +0,0 @@ -// -// IntroVC.swift -// WebAppUIKitBase -// -// Created by Sean Kim on 10/21/24. -// - -import Foundation diff --git a/WebAppUIKitBase/Scene/AppDelegate.swift b/WebAppUIKitBase/Scene/AppDelegate.swift deleted file mode 100644 index 4dd12c0..0000000 --- a/WebAppUIKitBase/Scene/AppDelegate.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// AppDelegate.swift -// WebAppUIKitBase -// -// Created by Sean Kim on 10/21/24. -// - -import UIKit - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - return true - } - - // MARK: UISceneSession Lifecycle - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - // Called when a new scene session is being created. - // Use this method to select a configuration to create the new scene with. - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { - // Called when the user discards a scene session. - // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. - // Use this method to release any resources that were specific to the discarded scenes, as they will not return. - } - - -} - diff --git a/WebAppUIKitBase/Scene/IntroVC.swift b/WebAppUIKitBase/Scene/IntroVC.swift index 1e67d9e..35836a3 100644 --- a/WebAppUIKitBase/Scene/IntroVC.swift +++ b/WebAppUIKitBase/Scene/IntroVC.swift @@ -6,12 +6,205 @@ // import UIKit +import Alamofire + +import SnapKit +import CoreLocation class IntroVC: UIViewController { override func viewDidLoad() { super.viewDidLoad() + CommonUtils.shared.locationDelegate = self + } + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + if isIllegalDevice() { + self.makeUIAlert(title: "안내", + message: "변경된 OS를 사용하는 기기는 서비스를 이용할 수 없습니다.", + okTitle: "확인") { _ in + exit(1) + } + } else { + if NetworkReachabilityManager.default?.isReachable == false { + self.makeUIAlert(title: "서비스 연결 문제 발생", + message: """ + 네트워크 문제로 서비스에 연결하지 못하였습니다. + 네트워크 상태를 확인후 다시 실행해주세요. + """, + okTitle: "확인") { _ in + exit(1) + } + } else { + self.checkAppVersion() + } + } + } + + + private func checkAppVersion() { + Task { + do { + let result = try await CommonUtils.shared.afGET(url:VER_URL, + param: VER_PARAM, + headers: VER_HEADERS) +// let result = """ +// {"status":{"code":"000","message":"성공"},"data":{"finalVer":"2.0.8","forceVer":"2.0.6","forceUpdtYn":"P","remark":"기능추가","checkVer":"9.9.9"}} +// """ + printLog("Success : \(result)") + let response = CommonUtils.shared.jsonToType("\(result)", as: VersionResponse.self) + + if let code = response?.status.code, code == "000" { + if let currentVer = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String, + let finalVer = response?.data.finalVer, let forceVer = response?.data.forceVer, + let checkVer = response?.data.checkVer, let forceUpdtYn = response?.data.forceUpdtYn + { + switch self.versionCompare(currentVer, finalVer) { + case .equal, .bigger: // 업데이트 처리 필요 없음 + CommonUtils.shared.checkLocationPermission() + case .smaller: + switch self.versionCompare(currentVer, forceVer) { + case .equal, .bigger: + if forceUpdtYn == "P" {// PASS라서 P 한건데 Y 해도 된다. + self.makeUITwoAlert(title: "업데이트 안내", + message: "최신 버전이 새로 나왔어요\n지금 업데이트하시겠어요?", + okTitle: "지금 업데이트", + okAction: { _ in + let appStoreURL = URL(string: "http://www.naver.com")! + UIApplication.shared.open(appStoreURL, options: [:], completionHandler: nil) + exit(1) + }, cancelTitle: "나중에") { _ in + CommonUtils.shared.checkLocationPermission() + } + } else { + CommonUtils.shared.checkLocationPermission() + } + case .smaller: + self.makeUIAlert(title: "업데이트 안내", + message: "앱을 사용하시려면\n최신버전으로 업데이트 해주세요", + okTitle: "지금 업데이트") { _ in + let appStoreURL = URL(string: "http://www.naver.com")! + UIApplication.shared.open(appStoreURL, options: [:], completionHandler: nil) + exit(1) + } + } + } + } + else { + throw NSError(domain: "com.version.API", + code: Int(response?.status.code ?? "") ?? -1, + userInfo: [NSLocalizedDescriptionKey: "Version is Wrong"]) + } + } else { + throw NSError(domain: "com.version.API", + code: Int(response?.status.code ?? "") ?? -1, + userInfo: [NSLocalizedDescriptionKey: "Version is Wrong"]) + } + } catch { + printLog("App Check ERROR: \(error)") + self.makeUIAlert(title: "서비스 연결 문제 발생", + message: """ + 일시적인 장애 또는 네트워크 문제로 + 서비스에 연결하지 못하였습니다. + 문제가 계속될 경우 고객센터로 문의해 주세요 + """, + okTitle: "확인") { _ in + exit(1) + } + } + } + } + /// compareVer에 비교를 할 문자열을 넣어주면 된다. + /// + /// [결과 해석: 현재 버전이 비교 버전보다 (RESULT) 하다.] + private func versionCompare(_ currentVer: String, _ compareVer: String) -> CompareVersion { + let currentArray = currentVer.components(separatedBy: ["."]).map {Int($0) ?? 0} + let compareArray = compareVer.components(separatedBy: ["."]).map {Int($0) ?? 0} + printLog("Ver current: \(currentArray)") + printLog("Ver force: \(compareArray)") + for i in 0 ..< currentArray.count { + if currentArray[i] > compareArray[i] { + // 현재 버전이 비교하려는 버전보다 큰 경우 == 그냥 일반 동작을 시키면 된다. + return .bigger + } else if currentArray[i] < compareArray[i] { + // 현재 버전이 비교하려는 버전보다 작은 경우 == 업데이트 조건 처리 + return .smaller + } + } + + // 현재 버전이 비교 버전과 동일 + return .equal + } + + private func moveToWeb() { + let VC = MainWebVC() + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, + let window = windowScene.windows.first { + window.rootViewController = VC + } } } + +extension IntroVC: LocationDelegate { + + func checkPermission(_ type: Bool) { + if type { +// CommonUtils.CommonUtils.shared.saveUdData("Y", forKey: "locationYn") + } else { +// CommonUtils.CommonUtils.shared.saveUdData("N", forKey: "locationYn") + self.moveToWeb() + } + } + + func getLocation(_ location: CLLocation) { + CommonUtils.shared.locationManager.stopUpdatingLocation() + let lat = location.coordinate.latitude + let lng = location.coordinate.longitude + CommonUtils.shared.lastLocation = location + printLog("Intro \(String(describing: CommonUtils.shared.lastLocation))") + printLog("Intro Delegate = lattitude : \(lat) longitude : \(lng)") + printLog("위치 권한 허용 > 웹뷰 start") + self.moveToWeb() + } +} + + + +enum CompareVersion: Int { + case equal = 0 + case bigger + case smaller +} + +class VersionResponse: Codable { + let status: Status + let data: VersionData +} +/// API 확인 변수 +/// +/// code: API 정상 확인 코드 (e.g. 000: 정상) +/// +/// message: 코드에 대한 설명 +class Status: Codable { + let code, message: String + +} + +/// API 데이터 변수 +/// +/// finaclVer: 현재 가장 최신 버전 +/// +/// forceVer: 이 버전보다 미만의 버전은 강제 업데이트 시행 +/// +/// checkVer: 개발용 및 업데이트 관련 버전 +/// +/// forceUpdYn: P(Y) 등의 값일 시 finalVer보다 미만의 경우 선택 업데이트 동작 시행 +/// +/// remark: 현재 버전 관련한 설명 +class VersionData: Codable { + let finalVer, forceVer, checkVer: String? + let forceUpdtYn: String? + let remark: String? +} diff --git a/WebAppUIKitBase/Scene/MainWebVC.swift b/WebAppUIKitBase/Scene/MainWebVC.swift index e9b227b..5e19d60 100644 --- a/WebAppUIKitBase/Scene/MainWebVC.swift +++ b/WebAppUIKitBase/Scene/MainWebVC.swift @@ -5,4 +5,15 @@ // Created by Sean Kim on 10/21/24. // -import Foundation +import UIKit +import WebKit + +import SnapKit + +class MainWebVC: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + self.view.backgroundColor = .white + } +} diff --git a/WebAppUIKitBase/Scene/SceneDelegate.swift b/WebAppUIKitBase/Scene/SceneDelegate.swift deleted file mode 100644 index 8838e81..0000000 --- a/WebAppUIKitBase/Scene/SceneDelegate.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// SceneDelegate.swift -// WebAppUIKitBase -// -// Created by Sean Kim on 10/21/24. -// - -import UIKit - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - - var window: UIWindow? - - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - guard let windowScene = (scene as? UIWindowScene) else { return } - window = UIWindow(frame: UIScreen.main.bounds) - window?.windowScene = windowScene - // 여기서 메인 화면 띄우는 걸 함 - window?.rootViewController = IntroVC() - - window?.makeKeyAndVisible() - } - - func sceneDidDisconnect(_ scene: UIScene) { - // Called as the scene is being released by the system. - // This occurs shortly after the scene enters the background, or when its session is discarded. - // Release any resources associated with this scene that can be re-created the next time the scene connects. - // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). - } - - func sceneDidBecomeActive(_ scene: UIScene) { - // Called when the scene has moved from an inactive state to an active state. - // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. - } - - func sceneWillResignActive(_ scene: UIScene) { - // Called when the scene will move from an active state to an inactive state. - // This may occur due to temporary interruptions (ex. an incoming phone call). - } - - func sceneWillEnterForeground(_ scene: UIScene) { - // Called as the scene transitions from the background to the foreground. - // Use this method to undo the changes made on entering the background. - } - - func sceneDidEnterBackground(_ scene: UIScene) { - // Called as the scene transitions from the foreground to the background. - // Use this method to save data, release shared resources, and store enough scene-specific state information - // to restore the scene back to its current state. - } - - -} - diff --git a/WebAppUIKitBase/SecretCode.swift b/WebAppUIKitBase/SecretCode.swift deleted file mode 100644 index 612a4ad..0000000 --- a/WebAppUIKitBase/SecretCode.swift +++ /dev/null @@ -1,8 +0,0 @@ -// -// SecretCode.swift -// WebAppUIKitBase -// -// Created by Sean Kim on 10/21/24. -// - -import Foundation