본문 바로가기
개발 블로그/아이폰개발

[iOS SWIFT] WKWebview에서 WKUserContentContoller 를 JavaScript 연동 (Native <-> JavaScript) 통신

by snapshot 2020. 6. 30.

PG사 결제 및 PASS를 통한 본인 인증 할 때 Native iOS 앱과 JavaScript 연동이 필요하다.

이유는 결제 및 본인 인증의 성공 여부 또는 실패했을 때 앱 자체에서 대응을 해야 하기 때문이다.

 

import WebKit // 필수

 

일단 우리에게 필요한건 WKWebView의 세팅이 필요하다.

참고로 IBOutlet 으로 되지 않으니..코드로 세팅하시길..

일단 webview의 세팅은 이렇다..

 

모든 코드는 밑에 있으니 그대로 쓰시면되고 일단 설명을 하겠다 .

WKUserContentController를 생성하고 웹에서 사용할 name을 미리 세팅 해준다. 우리가 사용할 name은 성공할 때 success 실패는 error 두개만 사용할 것이다.

 

그리고 우리는 WKWebViewConfiguration을 통해서 contentController 와 웹뷰를 세팅해 줄 것이다.

그냥 외우자. 이건 이해가 아닌 세팅 부분이다.

그리고 IBOutlet이 아닌 코드로 웹뷰 세팅을 해줘야 한다.

 

웹뷰 세팅

lazy var webView : WKWebView = {
            // JavaScript 와 통신을 하기 위해서 필요한 Controller
            let contentController = WKUserContentController()
            contentController.add(self, name: "success")  //성공 name 세팅
            contentController.add(self, name: "error")  //실패 name 세팅

            //이것을 통해서 웹뷰 세팅을 해줘야 하기 때문에 IBOulet으로 할 수 없음
            let configuration = WKWebViewConfiguration()
            configuration.userContentController = contentController

            let theWebview = WKWebView(frame: self.view.bounds, configuration: configuration)
            theWebview.uiDelegate = self    //굳이 할 필요는 없음
            theWebview.navigationDelegate = self //굳이 할 필요는 없음

            return theWebview
        }()

웹뷰 세팅을 마쳤으면 WKScriptMessageHandler 프로토콜을 통해서 우리는 웹에서 자바스크립트로 이벤트를 줬을 때 위에서 세팅한 success, error인 message.name을 통해서 분기로 처리할 수 있다.

웹에서 보낸 파라미터는 meesage.body로 받을 수 있다.

 

WKScriptMessageHandler

extension CetivficationViewController : WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {

        if(message.name == "success") {
            print(message.body)
        } else if (message.name == "error") {
            print(message.body)
        }
    }
}

 

 

서버에서는 window.webkit.messageHandlers.success.postMessage('성공'); 이런식으로 이벤트를 보내주면 된다.

window.webkit.messageHandlers.(name).postMessage('body');

<!DOCTYPE html>
<html lang="ko">  
  <head>     
   <title>MessageHandler Test</title>    
    <style type="text/css">      
      #container {         
       margin-top: 30pt;       
     }     
   button {    
        background-color: gray;   
         border: none;    
        padding: 10pt;     
       font-size: 20pt;      
      width: 100%;     
   }     
   </style>    
    <script type="text/javascript">  
      function sendMessage() {   
         window.webkit.messageHandlers.success.postMessage('성공');      
  }    
    </script>   
 </head>   
 <body>    
    <div id='container' align='center'>    
        <button onclick='sendMessage();'>send message()</button></br>  
      </div>  
  </body>
</html>

 

 

** JS에서 네티이브에 보내는 파라미터가 2개인 경우는

webkit.messageHandlers.error.postMessage({code: 'code 입니다.', message: '뭔가 잘못했습니다.'});

코드에서는

let values:[String:String] = message.body as! Dictionary 
            print("\\(values["subject"]) / \\(values["url"]")

이런식으로 가능하다.

 

 

***** 모든 코드 ****

import UIKit
import WebKit //Import 핪디ㅏ

class CetivficationViewController: UIViewController {

    lazy var webView : WKWebView = {
        // JavaScript 와 통신을 하기 위해서 필요한 Controller
        let contentController = WKUserContentController()

        //자바 스크립트에서 호출해줄 name
        contentController.add(self, name: "success")
        contentController.add(self, name: "error")

        //이것을 통해서 웹뷰 세팅을 해줘야 하기 때문에 IBOulet으로 할 수 없음
        let configuration = WKWebViewConfiguration()
        configuration.userContentController = contentController

        let theWebview = WKWebView(frame: self.view.bounds, configuration: configuration)
        theWebview.uiDelegate = self    //굳이 할 필요는 없음
        theWebview.navigationDelegate = self //굳이 할 필요는 없음

        return theWebview
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(webView) //웹뷰를 뷰에 올려주고...
        self.request() // url 통신 시작!!

        //self.testForHTMLRequest()    일단 서버가 잘못했는지 내가 잘못 했는지 볼려면 이런식으로 테스트 실행
    }

    class func show(with topViewController : UIViewController) {
        let homeView = UIStoryboard.init(name: CERTIVICATION_STORYBOARD, bundle: nil).instantiateViewController(withIdentifier: "CertificationCheckForPASSViewController")
        topViewController.present(homeView, animated: true, completion: nil)
    }
}

// MARK: - function
private extension CetivficationViewController {

    func getWebViewRequestURL() -> URL{
        let urlString = "https://api.test.comeod.eoe.eowoeiroweiro"
        // 우리는 테스트 서버 마다 url 다르게 사용하기 때문에 분기 처리를 해줬음
        return URL(string: urlString)!
    }

    // url을 통한 실행
    func request() {
        let request = URLRequest(url: self.getWebViewRequestURL())
        // Header 값 세팅이 필요했기 때문에 사용..필요 없으면 삭제
        //            let userId = "asdfasdfsadf"
        //            request.setValue(userId, forHTTPHeaderField: "userId")
        self.webView.load(request)
    }

    //버튼으로 실제로 구현이 되는지 테스트를 해보고 싶다면 이 함수 실행
    func testForHTMLRequest() {
        self.webView.loadHTMLString(self.getHTML(), baseURL: nil)
    }

    func getHTML() -> String {
        return "<!DOCTYPE html><html lang=\"ko\"><head><title>MessageHandler Test</title><style type=\"text/css\">#container {margin-top: 30pt;}button {background-color: gray;border: none;padding: 10pt;font-size: 20pt;width: 100%;}</style><script type=\"text/javascript\">function sendMessage() {window.webkit.messageHandlers.error.postMessage('실패실패');}</script></head><body><div id='container' align='center'><button onclick='sendMessage();'>send message()</button></br></div></body></html>"
    }
}

//***************************
// 이 부분이 중요함
extension CetivficationViewController : WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {

        if(message.name == "success") {
            print(message.body)
        } else if (message.name == "error") {
            print(message.body)
        }
    }
}

// 이건 델리게이트 함수들...지금은 필요 없음
extension CetivficationViewController : WKNavigationDelegate, WKUIDelegate {
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {

    }

    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {

    }
}

댓글