티스토리 뷰

반응형

Webview는 앱 기능 중 필수라고 할 수 있습니다. 하이브리드 앱에서 특히 많이 사용하고 있는 Webview를 공유하겠습니다.

Swift 에서는 Webview 사용 시 UIWebView을 사용하였습니다. 그러다 ios 11 버전부터는 Webkit 이라는 위젯이 등장합니다. UIWebview에서 WebKit으로 변경되었지만 소스 변경은 많이 되지 않았기에 소스 업데이트에 대한 걱정은 없었습니다.


버전에 따른 WebView


공유드릴 내용은 버전에 따른 WebView 호출입니다. Xcode로 웹뷰 구현 하다보면 WebKit은 ios11버전 이상에서만 사용 가능하다고 제한을 걸었습니다. Apple Developer에서는  "Webkit 최소 버전은 ios 8 이상부터 지원한다"고 명시하고 있습니다. 차후에 UIWebView 지원없어지면서 XCode에서의 WebKit 제한이 해지 될 것으로 예상됩니다.


1. plist에 권한 설정하기


HTTPS로 구성된 URL 호출 및 WebView 또는 WebKit 로 웹페이지 호출하려면 plist에 등록해야하는 정보가 있습니다.

pist 등록

<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>

만약 도메인이 열리지 않을 경우 홈페이지 주소에 따른 권한을 따로 설정해야합니다.

<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>http://faith-developer.tistory.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>


2. UIWebView


UIWebView에서 URL호출 시 사용하는 함수는 loadRequest(URL) 입니다.

let address = "http://faith-developer.tistory.com"

let url = URL(string: address)

let request = URLRequest(url: url!)

_webview.loadRequest(request)


UIWebView Delegate의 구성은 다음과 같이 4가지로 구성합니다.

func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
    return true
} 

func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
    print(error)
}   

func webViewDidStartLoad(_ webView: UIWebView)

{
    print("start")
    //Todo..
}

 

func webViewDidFinishLoad(_ webView: UIWebView)
{
    print("end")
    //Todo..
}


* webView(_, shouldStartLoadWith, ...) -> Bool
: 웹뷰에서 프레임이 호출 되기 전이 호출 됩니다.

* webView(_, didFailLoadWithError, ...) -> Bool
: 에러 발생 시 호출 됩니다.

* webViewDidStartLoad(_)
: 로딩 시작 시 호출 됩니다.

* webViewDidFinishLoad(_)
:
 로딩 끝났을 시 호출 됩니다.


3. WebKit


WebKit에서 URL호출 시 사용하는 함수는 loadRequest(URL) 입니다.

let address = "http://faith-developer.tistory.com/"

let url = URL(string: address)

let request = URLRequest(url: url!)

webView.load(request)


WebKit Delegate의 구성은 다음과 같이 5가지로 구성합니다.

@available(iOS 8.0, *)

public func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {

    showAlertDialog(message: message, completionHandler: completionHandler)

}

 

@available(iOS 8.0, *)

public func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {

    let alert = UIAlertController(title: "", message: message, preferredStyle: .alert)

    let cancelAction = UIAlertAction(title: "CANCEL", style: .cancel) { action in completionHandler(false) }

    let okAction = UIAlertAction(title: "OK", style: .default) { action in completionHandler(true) }

    alert.addAction(cancelAction)

    alert.addAction(okAction)

    self.present(alert, animated: true, completion: nil)

}

 

@available(iOS 8.0, *)

public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {

    //Todo..

}

 

@available(iOS 8.0, *)

public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {

    //Todo..

}

@available(iOS 8.0, *)

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {

    if navigationAction.request.url?.scheme == "itms-appss" {

          //스키마 검색하여 Todo..  ex)itms-apps

        decisionHandler(.cancel)

    }else{

        decisionHandler(.allow)

    }

}


webView(_, runJavaScriptAlertPanelWithMessage, ...)
: JavaScript에 Alert Panel 호출 시 호출됩니다.

* webView(_, runJavaScriptConfirmPanelWithMessage, ...)
: JavaScript의 Confirm Panel 호출 시 호출 됩니다.

* webView(_, didStartProvisionalNavigation)
: 웹페이지 로드 시 호출 됩니다.

* webView(_, didFinish)
: 웹페이지 로드 완료 시 호출 됩니다.

* webView(_, decidePolicyFor, ...)
: 웹페이지 호출 시작 후 동작하며, 웹 사이트에서 진행할 동작의 사용 유무를 설정할 수 있습니다.


URL로 AppStore 호출


기존 UIWebView에서 앱스토어에 등록된 앱으로 이동 시 " 소개 URL"만 입력하면 접근이 가능했습니다. 

[UIWebView 에서 호출 소스]

let address = "https://itunes.apple.com/kr/app/apple-store/id1288075134"

let url = URL(string: address)

let request = URLRequest(url: url!)

_webview.loadRequest(request)


WebKit은 다음과 같은 방식으로 처리합니다.

[WebKit 에서 호출 방법]

1) webView(_, decidePolicyFor, ..)  에서 호출한 URL의 scheme 체크

2) URL의 scheme 가 "itms-apps" 인지 체크한 후 "itms-apps" 경우 다음 단계를 진행합니다.

3) UIApplication.shared.open(url, options: [:], completionHandler: nil) 에 호출하고자 하는 URL을 입력하여 AppStore를 호출합니다.


ScrollView 활용

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {

   if navigationAction.request.url?.scheme == "itms-appss" {

            // Todo

        // ex) Utils.openURLToAppStore(urlPath: navigationAction.request.url!.absoluteString)

        decisionHandler(.cancel)

    }else{

        decisionHandler(.allow)

    }
}


ScrollView을 활용한 WebView와 다른 ViewController을 스와이프로 화면 전환하는 기능을 구현하였습니다. 


ScrollView 소스 설명


WebView의 Delegate을 MainViewController에 구현하였습니다. 이유는 ScrollView에는 addSubView() 함수를 사용하여 View만 넣을 수 있습니다. 따라서 ViewController에서 처리하는 Delegate는 RootView인 MainViewController에서 동작합니다. 만약 SubView()에 넣은 WebView을 구현한 ViewController에 Delegate을 동작 시도 시 Error()가 발생하는 것을 확인할 수 있습니다.

자세한 소스는 여기에서 확인 할 수 있습니다.


정리


UIWebView와 WebKit의 URL 호출 방법은 비슷하였으나, AppStore 호출 하는 등의 방법은 달라진 것을 확인하였습니다. ios 버전에 따라서 UIWebView를 써야할 경우도 생깁니다. 저 같은 경우는 ios 11 미만 버전에서 WebKit으로 웹화면을 호출하였는데요. 호출한 화면에서 스크롤이 안되어 UIWebView을 사용하였습니다. 이처럼 ios 11 이상 버전과 ios 11 미만 버전을 체크하여 분기를 통한 호출을 한다면 이슈 발생이 적을 것으로 예상됩니다.


참고


https://developer.apple.com/documentation/webkit


반응형
댓글