앙큼한 개발기록

swiftUI 에서 view Controller로 Webview 띄우기 본문

개발/swift

swiftUI 에서 view Controller로 Webview 띄우기

angkeum 2022. 5. 29. 22:30

최근 하이브리드 앱을 만들어 달라는 부탁을 받고 

매번 story board로 하던 작업을 swift ui로 해보싶어서 swiftui로 프로젝트를 빌드해 보았다. 

 

근데 만들고 보니 swiftui 에서는 storyboard 처럼 viewController가 없어 webview에 권한이나 위치정보, 카메라 정보나 

javascript함수 호출과 같은 부분을 어떤식으로 구현하면 좋을지가 막막하다가 

해당 내용을 구현한 소스를 정리해 보고자 글을 작성해 본다. 

 

그리고 찾는데 오래걸려서 직접 정리하는 것도 있다....

 

1. ViewController.swift 를 하나 만든다. 

- 이름은 상관 없다.

import SwiftUI

struct ViewController: UIViewControllerRepresentable {
    
    // storyboard와 동일한 controller
    let webviewController = WebviewController()
    
    // ContentView에서 최초에 호출되는 override 함수
    func makeUIViewController(context: Context) -> some UIViewController {
        return webviewController
    }
    
    // ContentView 에서 makeUIViewController를 호출하고 나서 업데이트 할때 호출 하는 함수
    // 나는 화면이 다 만들어 지고 나서 위치정보를 호출해 보고 
    // 권한이 있으면 위치정보를 보내주고, 없으면 권한 설정을 표시 한다. 
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        let status = webviewController.locationService.getLocationStatus()
        print("update ui view controller")
        if status != .authorizedAlways && status != .authorizedWhenInUse {
            webviewController.requestAndSendLocation()
        }
    }
}

 

2. 위에 ViewController에서 사용한 WebviewController.swift 를 만든다.

- 이거 먼저 만들고 위에 1번 만들어도 된다.

- 마찬가지로 이름은 상관 없다.

import UIKit
import WebKit

class WebviewController: UIViewController {

    // 팝업을 위해, 결제를 위해 웹뷰를 배열로 만들어서 컨트롤 한다.
    var webviews = [WKWebView]()

    // 우리가 아는 컨트롤러 호출시 초기에 가장 먼저 실행되는 함수
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 호출할 웹뷰 주소
        let host = URL(string: Constants.MAIN_URL)

        // 웹뷰와 앱이 통신하기 위해 하는 설정
        let webConfiguration = WKWebViewConfiguration()
        let contentController = WKUserContentController()
        
        contentController.add(self, name: "location")

        webConfiguration.userContentController = contentController
        webConfiguration.defaultWebpagePreferences.allowsContentJavaScript = true
        webConfiguration.preferences.javaScriptCanOpenWindowsAutomatically = true

        // 웹뷰 생성
        self.createWebView(frame: self.view.frame, config: webConfiguration)
            .load(URLRequest(url: host!))        
    }
    
    // 웹뷰를 만들어 준다. 
    // uiDelegate, navigationDelegate는 알럿, 컨펌, 혹은 내장함수와 팝업, 그리고 생성 되는 라이프사이클을 간섭할수 있다.
    func createWebView(frame: CGRect, config: WKWebViewConfiguration) -> WKWebView {
        let webview = WKWebView(frame: frame, configuration: config)
        webview.uiDelegate = self
        webview.navigationDelegate = self
        webview.allowsBackForwardNavigationGestures = true
        webview.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        webview.translatesAutoresizingMaskIntoConstraints = false
        
        self.view.addSubview(webview)
        self.webviews.append(webview)

        return webview
    }

    // 자바스크립트로 데이터 전달할때 swift객체를 string으로 전환해서 전달하면 javascript에서 object로 받을 수 있다.
    func objectToString(object obj: Any) -> String {
        let jsonData = try! JSONSerialization.data(withJSONObject: obj, options: [])
        return String(data: jsonData, encoding: .utf8)!
    }

    // 위치 정보를 동의 하였을 경우 해당 정보를 javascript로 전달
    func requestAndSendLocation() {
        locationService.requestLocation { coordinate in
            let lat         = coordinate.latitude.description
            let lng         = coordinate.longitude.description
            let position    = ["lat": lat, "lng": lng]
            let stringData  = self.objectToString(object: position)
            
            print("location", stringData)
            
            self.webviews[0].evaluateJavaScript("currentLocation(\(stringData))")
        }
    }
}

 

 

1. ContentView에 ViewController라고 설정하면 웹뷰가 짠 하고 나타난다.

struct ContentView: View {
    var body: some View {
        ViewController()
    }
}
Comments