나의 발자취

iOS WebKit: Web <> App 통신하기 본문

앱 개발/iOS

iOS WebKit: Web <> App 통신하기

달모드 2024. 9. 5. 14:19

 

 

웹페이지를 로드하는 일은 기본적으로 아래와 같은데, 표시한 내용을 iOS에서 구현해주는 것이다.

  • 인터넷 브라우저가 URL을 파싱해서 스킴/도메인/path로 구분한 후 해당 IP 주소와 포트 주소로 웹 서버를 연결하고,
  • 그다음 HTTP request(헤더, 쿠키, user agent 정보가 들어감)를 보낸다.
  • 그러면 상대편 서버가 리퀘스트 처리를 하여 요청한 데이터와 함께, status code가 포함된 HTTP response를 다시 보낸다.
  • 브라우저가 이 응답(HTML/CSS/JS) 및 다른 리소스를 받아서 페이지를 렌더링하기 시작한다.
  • 브라우저는 HTML으로부터 DOM을 생성하고, CSS/JS를 반영해서 웹페이지를 디스플레이한다.
  • 최종 페이지가 스크린에 나타나서 user interaction을 대기하는 상태로 놓여진다. (다이나믹 컨텐츠는 페이지 전체를 새로고침할 필요 없이 리얼타임으로 업데이트된다.)
  • 사용자가 페이지와 interact를 하게 되면, 추가적인 HTTP request/response가 전송되게 된다.
  • HTTPS 사이트의 경우, 데이터 암호화를 위해 SSL/TLS 연결이 이루어져야한다.
  • 상태 유지 및 사용자 선호 환경을 저장하기 위해 쿠키와 세션이 사용된다.

 

자, 그렇기 때문에 1) URL 변수 만들어서 가져오고, 2) HTTP request 보내고, 3) HTTP response를 전달받는 것이다.

 

따라서 기본적인 구현은 아래와 같다.

import UIKit
import WebKit

class ViewController: UIViewController {

    @IBOutlet weak var webView: WKWebView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 1) URL 변수 만들어서 가져오고, 
        let url = URL(string: "https://naver.com")
        guard let url else {
            return
        }
        
        // 2) HTTP request 보내고, 
        let request = URLRequest(url: url)
        
        // 3) HTTP response를 전달받는 것이다.
        webView.load(request)
    }


}

 

 

1. url 객체를 받아온다. 

url 변수의 타입은 옵셔널이기 때문에, guard let을 통해 옵셔널 언래핑을 해준다.

(guard let url = url 이지만 편의상 두 개의 변수명이 사실상 같으므로 guard let url 까지만 사용)

 

 

 

2. 

info.plist에서, http 주소도 리다이렉션을 하기 위해 추가를 해준다.

아래와 같이 같은 레벨에서 App Transport Security Settings를 추가해준다. 

 

그 다음 하위에 Allow Arbitrary Loads를 추가하고 값을 YES로 변경한다. (NO-YES인 이유는 Obj-C에서 넘어온것임)

 

 

Swift(Native) <> Web 통신 하는 방법을 구현해보자

1. Simple Web Server에 내가 js로 만들어놓은 파일 업로드 후 서버 올리기 -> 웹서버 완성

2. XCode로 가서 아래와 같이 코드 작성

 

import UIKit
import WebKit

class ViewController: UIViewController {


    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let webViewConfig = WKWebViewConfiguration()
        var userContent = WKUserContentController()

        userContent.add(self, name: "SendMessage")
        userContent.add(self, name: "SayHello")
        userContent.add(self, name: "SetUser")
        
        
    }


}

 

 여기서 self는 Delegate의 역할을 하는데, .add인 이유-Delegate긴 한데 메시지에 따라 처리해주는 delegate를 따로 만들 수 있다는 뜻이다.

지금과 같이 하면 Delegate를 구현하지 않아서 에러가 나니까, extension으로 구현을 해준다.

 

3. Extension으로 Delegate 위임

extension ViewController: WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        switch message.name {
        case "SendMessage": print("SendMessage")
        case "SayHello": print("SayHello")
        case "SetUser": print("SetUser")
            
        default:
            print("정의되지 않은 메시지")
        }
    }
}

 

 

4. 위쪽 VC에 아래의 WebView Config를 넣어주고, 뷰를 만들어준다.

webViewConfig.userContentController = userContent

 

그리고 이 Configuration을 받을 수 있는 initializer은 아래의 configuration 매개변수를 받는 생성자밖에 없으므로 이를 선택해줌!

 

var webView = WKWebView(frame: view.frame, configuration: webViewConfig)

 

 

5. 뷰에 subview를 추가해줘서 나타나게끔 한다.

view.addSubview(webView)

 

 

6. request 만들기

// request 생성
        guard let url = URL(string: "http://127.0.0.1:8080") else { return }
        let request = URLRequest(url: url)
        webView.load(request)

 

 

7. 결과 확인

라이언이 있는곳처럼 웹에서 보내는 신호를 앱(native)에서 받아서 처리하고 있는걸 볼 수 있다!!

 

 

8. 최종 코드

//
//  ViewController.swift
//  WebNativeCom


import UIKit
import WebKit

class ViewController: UIViewController {


    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let webViewConfig = WKWebViewConfiguration()
        let userContent = WKUserContentController()

        userContent.add(self, name: "SendMessage")
        userContent.add(self, name: "SayHello")
        userContent.add(self, name: "SetUser")
        
        webViewConfig.userContentController = userContent
        
        var webView = WKWebView(frame: view.frame, configuration: webViewConfig)
        
        view.addSubview(webView)
        
        // request 생성
        guard let url = URL(string: "http://127.0.0.1:8080") else { return }
        let request = URLRequest(url: url)
        webView.load(request)
        
    }


}
extension ViewController: WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        switch message.name {
        case "SendMessage": print("SendMessage")
        case "SayHello": print("SayHello")
        case "SetUser": print("SetUser")
            
        default:
            print("정의되지 않은 메시지")
        }
    }
}
728x90
반응형
Comments