[웹개발자의 IOS 탐방기] 1. Swift UI로 웹앱 만들기

서론

아이폰의 운영체제(IPhone OS : 이하 IOS) 에서 동작하는 Application (이하 App)은 수만가지가 있다. 사람들이 가장 많이 사용하는 방식으로 SwiftUI를 활용하여 List View & Scroll View 등의 View단위로 구성된 Native App. Unitiy 및 SpriteKit, Unreal Engine 등의 게임 프레임워크 킷들을 사용하여 만드는 Game App 등이 여기에 해당된다. 그중에서 나는 모바일 웹을 앱에서 표현하는 통칭 웹앱에 네이티브 기능을 추가한 하이브리드 앱(Hybrid APP)을 만드려고 한다.

SwiftUI를 사용한 웹앱 Project 만들기

웹앱을 만드는데 SwiftUI를 사용한다니 뭔가 어불성실이다. SwiftUI는 대부분 네이티브 앱에서 사용되기 때문에, 보통 UIKit & WebKit 으로 구성되는 웹앱 (StoryBoard와 UIViewController를 연동하여 만드는 웹앱)이 대부분인 현 시점에서 이게 맞나? 싶은 생각을 들게할 것이다. 하지만 내가 SwiftUI를 이용하여 웹앱을 만드는 시작점은, 추후 네이티브 기능을 합쳐서 설정이나 멤버쉽, 구독 및 알림 설정 등의 네이티브 기능을 하단 툴바에 덫붙여서 만들어 볼 생각이기 때문이다.

위 사진처럼 new project를 간단하게 하나 구성한다. interface는 SwiftUI로, storage는 Core Data로 지정한다.

WebView 생성

 

프로젝트를 다 생성하였으면, 새로운 파일의 User Interface를 SwiftUI View로 하여 파일명을 WebView로 지정한다. 초기 웹뷰 코드는 아래와 같이 간단하게만 생성해준다.

Coordinator는 UIViewRepresentable과 UIViewControllerRepresentable 프로토콜을 구현할 때 SwiftUI와 UIKit 간의 상호 작용과 조정을 위해 사용되는 클래스로, UIViewRepresentable 또는 UIViewControllerRepresentable 프로토콜을 사용하여 UIKit 기반의 뷰나 뷰 컨트롤러를 SwiftUI에서 사용하려면, UIKit의 델리게이트 패턴, 액션 타겟 패턴, 데이터 소스 등의 상호 작용을 적절히 처리해야 하는 경우가 많기 때문에 이러한 상호 작용을 쉽게 처리하기 위해 Coordinator 클래스를 사용한다.

결론적으로, Coordinator는 SwiftUI와 UIKit 간의 다리 역할을 하는 중요한 클래스로, 두 프레임워크 간의 상호 작용을 원활하게 만드는 데 큰 역할을 한다. 추후 웹뷰와 네이티브간의 데이터 일원화 및 모니터링 시 (로그인 연동 등), 혹은 웹 페이지에서 웹뷰로 특정 통신이 필요할 때 아래 코드가 요긴하게 쓰일 예정이다.

//
//  WebView.swift
//  webApp
//
//  Created by mingyukim on 10/30/23.
//

import SwiftUI
import WebKit

// 1. SwiftUI를 위한 WKWebView 래퍼
struct WebView: UIViewRepresentable {
    let urlString: String

    func makeUIView(context: Context) -> WKWebView {
        let webView = WKWebView()
        webView.navigationDelegate = context.coordinator
        return webView
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {
        if let url = URL(string: urlString) {
            let request = URLRequest(url: url)
            uiView.load(request)
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, WKNavigationDelegate {
        var parent: WebView

        init(_ parent: WebView) {
            self.parent = parent
        }

        // 필요한 WKNavigationDelegate 메서드를 여기에 추가한다.
    }
}

ContentView 수정

SwiftUI 기반의 프로젝트를 생성하면 자동으로 생성되는 ContentView 파일이 존재한다. 파일을 열어 아래와 같이 수정해보자.

//
//  ContentView.swift
//  webApp
//
//  Created by mingyukim on 10/30/23.
//

import SwiftUI
import CoreData

struct ContentView: View {
    var body: some View {
        NavigationView {
            WebView(urlString: "https://www.google.com")
                .navigationBarTitle("웹뷰 예제", displayMode: .inline)
        }
    }
}
#Preview {
    ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}

SwiftUI의 큰 장점중 하나로 나는 Preview 기능을 꼽겠다. UIKit 에서 StoryBoard에 작업하였을 때에는 항상 빌드하여 시뮬레이터로 뷰 화면을 넘기는 과정을 거쳐야했기 때문에 시간이 낭비되었었는데, SwiftUI를 사용하면 아래 스크린샷 처럼 코드가 바뀔 때 마다 프리뷰가 변하는 것을 감지할 수 있다.