[] IntroVC 완성, 버전 체크, 위치정보 수신 등 기초적인 기능들 추가

This commit is contained in:
김선규 2024-10-21 14:52:12 +09:00
parent a7d36694bb
commit d9911cc30b
17 changed files with 484 additions and 230 deletions

View File

@ -6,6 +6,11 @@
objectVersion = 77; objectVersion = 77;
objects = { 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 */ /* Begin PBXFileReference section */
A749CDFD2CC5D8CD0038D13D /* WebAppUIKitBase.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WebAppUIKitBase.app; sourceTree = BUILT_PRODUCTS_DIR; }; A749CDFD2CC5D8CD0038D13D /* WebAppUIKitBase.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WebAppUIKitBase.app; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@ -36,6 +41,8 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
A7D80D4D2CC5DFFF00E93F4D /* SnapKit in Frameworks */,
A7D80D502CC5E01D00E93F4D /* Alamofire in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -78,6 +85,8 @@
); );
name = WebAppUIKitBase; name = WebAppUIKitBase;
packageProductDependencies = ( packageProductDependencies = (
A7D80D4C2CC5DFFF00E93F4D /* SnapKit */,
A7D80D4F2CC5E01D00E93F4D /* Alamofire */,
); );
productName = WebAppUIKitBase; productName = WebAppUIKitBase;
productReference = A749CDFD2CC5D8CD0038D13D /* WebAppUIKitBase.app */; productReference = A749CDFD2CC5D8CD0038D13D /* WebAppUIKitBase.app */;
@ -107,6 +116,10 @@
); );
mainGroup = A749CDF42CC5D8CD0038D13D; mainGroup = A749CDF42CC5D8CD0038D13D;
minimizedProjectReferenceProxies = 1; minimizedProjectReferenceProxies = 1;
packageReferences = (
A7D80D4B2CC5DFFF00E93F4D /* XCRemoteSwiftPackageReference "SnapKit" */,
A7D80D4E2CC5E01D00E93F4D /* XCRemoteSwiftPackageReference "Alamofire" */,
);
preferredProjectObjectVersion = 77; preferredProjectObjectVersion = 77;
productRefGroup = A749CDFE2CC5D8CD0038D13D /* Products */; productRefGroup = A749CDFE2CC5D8CD0038D13D /* Products */;
projectDirPath = ""; projectDirPath = "";
@ -144,20 +157,20 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 2.0.8.1;
DEVELOPMENT_TEAM = 45MYH7ZHUQ; DEVELOPMENT_TEAM = 45MYH7ZHUQ;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = WebAppUIKitBase/Info.plist; INFOPLIST_FILE = WebAppUIKitBase/Info.plist;
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "검색과 길안내를 위해 사용합니다.";
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0; MARKETING_VERSION = 2.0.8;
PRODUCT_BUNDLE_IDENTIFIER = "kr.kro.sean-k.WebAppUIKitBase"; PRODUCT_BUNDLE_IDENTIFIER = "kr.kro.sean-k.WebAppUIKitBase";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
@ -176,20 +189,20 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 2.0.8.1;
DEVELOPMENT_TEAM = 45MYH7ZHUQ; DEVELOPMENT_TEAM = 45MYH7ZHUQ;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = WebAppUIKitBase/Info.plist; INFOPLIST_FILE = WebAppUIKitBase/Info.plist;
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "검색과 길안내를 위해 사용합니다.";
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0; MARKETING_VERSION = 2.0.8;
PRODUCT_BUNDLE_IDENTIFIER = "kr.kro.sean-k.WebAppUIKitBase"; PRODUCT_BUNDLE_IDENTIFIER = "kr.kro.sean-k.WebAppUIKitBase";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
@ -343,6 +356,38 @@
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
/* End XCConfigurationList section */ /* 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 */; rootObject = A749CDF52CC5D8CD0038D13D /* Project object */;
} }

View File

@ -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
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid = "B820CAC2-8B2D-4CF9-9D9F-B449DF8BFD0D"
type = "1"
version = "2.0">
</Bucket>

View File

@ -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<UISceneSession>) {
// 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.
}
}

View File

@ -7,25 +7,43 @@
import UIKit import UIKit
import AdSupport
import AppTrackingTransparency
@main @main
class AppDelegate: UIResponder, UIApplicationDelegate { class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true return true
} }
// MARK: UISceneSession Lifecycle /// Active : back -> fore
func applicationDidBecomeActive(_ application: UIApplication) {
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created. DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
// Use this method to select a configuration to create the new scene with. ATTrackingManager.requestTrackingAuthorization(completionHandler: { status in
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 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<UISceneSession>) { func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// Called when the user discards a scene session. let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. let token = tokenParts.joined()
// Use this method to release any resources that were specific to the discarded scenes, as they will not return. printLog("Device Tokens: \(token)")
} }

View File

@ -5,4 +5,128 @@
// Created by Sean Kim on 10/21/24. // 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<T: Decodable>(_ 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
}
}

View File

@ -4,7 +4,7 @@
// //
// Created by Sean Kim on 2/20/24. // Created by Sean Kim on 2/20/24.
// //
import SwiftUI import UIKit
// MARK: - TYPEALIAS // MARK: - TYPEALIAS
typealias VOID_TO_VOID = () -> () typealias VOID_TO_VOID = () -> ()
@ -26,13 +26,6 @@ public func printLog<T>(_ object: T, _ file: String = #file, _ function: String
#if DEBUG #if DEBUG
let dateString = Date().convertString("yyyy/MM/dd HH:mm:ss:SSS") let dateString = Date().convertString("yyyy/MM/dd HH:mm:ss:SSS")
Swift.print( Swift.print(
// """
// __________ __________
// |* TIME = [\(dateString)] || FILE = [\(file.lastPathComponent)]
// | NAME = [\(function)] || LINE = [\(line)]
// |>>> PRINT = \(object)
//
// """
""" """
__________ __________ __________ __________ __________ __________ __________ __________
* LOCATION : [\(file.lastPathComponent) : \(line)] - \(function) * LOCATION : [\(file.lastPathComponent) : \(line)] - \(function)
@ -149,9 +142,6 @@ func copyToClipboard(_ text: String){
// MARK: - CUSTOM COMPONENTS
// MARK: - EXTENSION // MARK: - EXTENSION
extension String { extension String {
/// ///
@ -379,34 +369,27 @@ extension Date {
} }
} }
extension UIViewController {
extension Font { public func makeUIAlert(title: String, message: String, okTitle: String, okAction:((UIAlertAction) -> Void)? = nil, completion: (() -> ())? = nil) {
enum NPS_Font : String { let alertController = UIAlertController(title: "\(title)", message: "\(message)", preferredStyle: .alert)
case regular let okAction = UIAlertAction(title: "\(okTitle)", style: .default, handler: okAction)
case bold 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 { let cancelAction = UIAlertAction(title: "\(cancelTitle)", style: .cancel, handler: cancelAction)
switch self { alertController.addAction(cancelAction)
case .regular:
return "NPS-font-Regular" self.present(alertController, animated: true, completion: completion)
case .bold:
return "NPS-font-Bold"
}
}
} }
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 // MARK: - ANNOTATION

View File

@ -5,4 +5,15 @@
// Created by Sean Kim on 10/21/24. // 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) {}
}

View File

@ -22,34 +22,15 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
window?.makeKeyAndVisible() window?.makeKeyAndVisible()
} }
func sceneDidDisconnect(_ scene: UIScene) { func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
// Called as the scene is being released by the system. guard let url = URLContexts.first?.url else {
// This occurs shortly after the scene enters the background, or when its session is discarded. return
// 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.
}
} }

View File

@ -15,8 +15,6 @@
<string>Default Configuration</string> <string>Default Configuration</string>
<key>UISceneDelegateClassName</key> <key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string> <string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict> </dict>
</array> </array>
</dict> </dict>

View File

@ -1,8 +0,0 @@
//
// IntroVC.swift
// WebAppUIKitBase
//
// Created by Sean Kim on 10/21/24.
//
import Foundation

View File

@ -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<UISceneSession>) {
// 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.
}
}

View File

@ -6,12 +6,205 @@
// //
import UIKit import UIKit
import Alamofire
import SnapKit
import CoreLocation
class IntroVC: UIViewController { class IntroVC: UIViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.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?
}

View File

@ -5,4 +5,15 @@
// Created by Sean Kim on 10/21/24. // 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
}
}

View File

@ -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.
}
}

View File

@ -1,8 +0,0 @@
//
// SecretCode.swift
// WebAppUIKitBase
//
// Created by Sean Kim on 10/21/24.
//
import Foundation