[ios] WebKit(WKWebView) 사용하기(이제 UIActivityViewController를 곁들인)

Cobugi·2022년 1월 29일
1
post-thumbnail

WebView

  • 앱에서 웹을 보여주고싶을 때 사용한다
  • 웹뷰를 사용하는 방법에는 3가지가 있는데
    • UIWebView : (iOS 2.0 ~) 현재는 사용되지 않는다, WKWebView에 비해 성능이 좋지 않음
    • SFSafariView : (iOS 9.0 ~) 필요에 따라 사용, 사파리 앱과 동일한 기능을 가짐, 사파리와 동일한 쿠키, 웹사이트 데이터 등을 공유
    • WKWebView : (iOS 8.0 ~) 가장 일반적으로 사용됨, 메모리가 앱과 별도의 스레드로 관리됨, 웹페이지에 메모리가 많이 할당되더라도 앱은 죽지 않음, UIWebView보다 성능이 좋음

만들어볼것

1. import WebKit

2. func loadWebView(_ url: String) 정의하기

  • url(String)을 받아서 URL 타입으로 변환하고 URLRequest로 또 변환후 webView의 load 메소드로 urlRequest를 넘겨주면 됨
func loadWebView(_ url: String) {
    guard let url = URL(string: url) else { return }
    let urlRequest = URLRequest(url: url)
    webView.load(urlRequest)
}
  • loadWebView("http://naver.com") 라고 하면 Naver 웹 페이지가 열림

3. indicator 만들기

  • 웹 페이지를 불러오는데 약간의 시간이 걸린다
  • 그 시간동안 indicator를 실행시켜 지금 실행중임을 사용자에게 알린다
  • webView의 WKNavigationDelegate의 메소드들로 구현할 수 있다
  • webView(_:didCommit:) : 웹 페이지 정보를 수신하기 시작할때 호출되는 메소드
  • webView(_:didFinish:) : 웹 페이지가 보여지는 것이 다 끝나면 호출되는 메소드
  • webView(_:didFail:withError:) : 웹 페이지를 불러오다가 실패했을 때 호출되는 메소드
extension WebViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
        indicator.isHidden = false
        indicator.startAnimating()
    }
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        indicator.stopAnimating()
        indicator.isHidden = true
        guard let title = webView.title else { return }
        navigationItem.title = title
    }
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        indicator.stopAnimating()
        indicator.isHidden = true
    }
}

4. ToolBar 만들기

  • 화면 하단에 정지, 새로고침, 다음, 이전을 나타내는 버튼들이 있다
  • 먼저 UIToolbar()를 하나 만들고
  • 툴바에 들어갈 UIBarButtonItem()를 만들어주면 된다
  • 또한 버튼들끼리 간격을 주고싶을 때는 UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)를 빈공간에 넣어주면 된다
  • 툴바에 들어갈 버튼들이 다 준비되었으면 툴바.items = [...바 버튼 아이템들...]
    private let toolBar = UIToolbar()
    private let stopBarButton = UIBarButtonItem(
        barButtonSystemItem: .stop,
        target: self,
        action: #selector(didTapStopBarButton)
    )
    private let refreshBarButton = UIBarButtonItem(
        barButtonSystemItem: .refresh,
        target: self,
        action: #selector(didTapRefreshBarButton)
    )
    private let goBackBarButton = UIBarButtonItem(
        barButtonSystemItem: .rewind,
        target: self,
        action: #selector(didTapGoBackBarButton)
    )
    private let goForwardBarButton = UIBarButtonItem(
        barButtonSystemItem: .fastForward,
        target: self,
        action: #selector(didTapGoForwardBarButton)
    )

    func setupToolBar() {
        let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
        toolBar.items = [
            flexibleSpace,
            stopBarButton,
            flexibleSpace,
            refreshBarButton,
            flexibleSpace,
            goBackBarButton,
            flexibleSpace,
            goForwardBarButton,
            flexibleSpace
        ]
    }

5. ToolBarButton에 이벤트 만들기

  • WebView의 메소드들로 모두 바로 구현할 수 있다
    @objc func didTapStopBarButton() {
        webView.stopLoading()
    }
    @objc func didTapRefreshBarButton() {
        webView.reload()
    }
    @objc func didTapGoBackBarButton() {
        webView.goBack()
    }
    @objc func didTapGoForwardBarButton() {
        webView.goForward()
    }

6. url에 http://(https://)가 있는지 확인

  • hasPrefix(_ prefix: String) : 접두사에 매개변수가 있는지 확인하여 Bool값을 반환한다
  • hasPrefix을 사용해서 http:// 또는 https://가 있는지 확인하는 flag를 만든다
  • 둘다 없다면 추가해주고 반환하면 된다
    func checkURL(_ urlString: String) -> String {
        var url = urlString
        let httpFlag = url.hasPrefix("http://")
        let httpsFlag = url.hasPrefix("https://")
        
        if !httpFlag && !httpsFlag {
            url = "https://\(url)"
        }
        return url
    }

7. html 파일을 직접 여는 방법

  • htmlView.html
<DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Cobugi</title>
  <style>
    body, h1, p {
      margin: 0;
    }
    .container {
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      background-color: #ffcc00;
      width: 100vw;
      height: 100vh;
    }
    a {
      font-size: 25px;
    }
  </style>
</head>
<body>
  <div class="container">
  <h1>안녕하세요</h1>
  <img src="https://media.vlpt.us/images/yc1303/profile/f834a078-c672-4425-8b20-510628d551c4/%E1%84%80%E1%85%A5%E1%84%87%E1%85%AE%E1%86%A8%E1%84%8B%E1%85%B5%20%E1%84%8B%E1%85%A5%E1%86%AF%E1%84%80%E1%85%AE%E1%86%AF%20500.png?w=240" alt="cobugi's img">
  <a href="https://velog.io/@yc1303">벨로그로 이동</a>
  </div>
</body>
</html>
  • 이런 html 파일을 직접 웹뷰에 띄우고 싶으면
guard let path = Bundle.main.path(forResource: "htmlView", ofType: "html") else { return }
let url = URL(fileURLWithPath: path)
let urlRequest = URLRequest(url: url)
webView.load(urlRequest)

8. UIActivityViewController 맛보기

  • 다음 코드를 작성해보자
let activityItems: [Any] = [webView.title ?? "", webView.url ?? ""]
let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)

present(activityViewController, animated: true)

전체코드

  • UI는 SnapKit으로 구현함
  • 위에서는 searchBar에 대해 작성하지 않음
import UIKit
import SnapKit
import WebKit

class WebViewController: UIViewController {
    
    private let webView = WKWebView()
    private let toolBar = UIToolbar()
    private let stopBarButton = UIBarButtonItem(
        barButtonSystemItem: .stop,
        target: self,
        action: #selector(didTapStopBarButton)
    )
    private let refreshBarButton = UIBarButtonItem(
        barButtonSystemItem: .refresh,
        target: self,
        action: #selector(didTapRefreshBarButton)
    )
    private let goBackBarButton = UIBarButtonItem(
        barButtonSystemItem: .rewind,
        target: self,
        action: #selector(didTapGoBackBarButton)
    )
    private let goForwardBarButton = UIBarButtonItem(
        barButtonSystemItem: .fastForward,
        target: self,
        action: #selector(didTapGoForwardBarButton)
    )
    
    private let indicator: UIActivityIndicatorView = {
        let indicator = UIActivityIndicatorView()
        
        indicator.color = .systemGreen
        indicator.isHidden = true
        
        return indicator
    }()
    
    private lazy var searchController: UISearchController = {
        let searchController = UISearchController()
        
        searchController.obscuresBackgroundDuringPresentation = false
        searchController.searchBar.delegate = self
        searchController.hidesNavigationBarDuringPresentation = false
        
        return searchController
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        webView.navigationDelegate = self
        navigationItem.rightBarButtonItem = UIBarButtonItem(
            image: UIImage(systemName: "square.and.arrow.up"),
            style: .plain,
            target: self,
            action: #selector(didTapShareButton)
        )
        setupLayout()

        guard let path = Bundle.main.path(forResource: "htmlView", ofType: "html") else { return }
        let url = URL(fileURLWithPath: path)
        let urlRequest = URLRequest(url: url)
        webView.load(urlRequest)
        
        navigationItem.searchController = searchController
    }
}
extension WebViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
        indicator.isHidden = false
        indicator.startAnimating()
    }
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        indicator.stopAnimating()
        indicator.isHidden = true
        guard let title = webView.title else { return }
        navigationItem.title = title
    }
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        indicator.stopAnimating()
        indicator.isHidden = true
    }
}

extension WebViewController: UISearchBarDelegate {
    func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
        searchBar.showsCancelButton = false
    }
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
        let url = checkURL(searchBar.text ?? "")
        loadWebView(url)
        navigationItem.searchController?.isActive = false
    }
    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
        navigationItem.searchController?.isActive = false
    }
}

extension WebViewController {
    @objc func didTapStopBarButton() {
        webView.stopLoading()
    }
    @objc func didTapRefreshBarButton() {
        webView.reload()
    }
    @objc func didTapGoBackBarButton() {
        webView.goBack()
    }
    @objc func didTapGoForwardBarButton() {
        webView.goForward()
    }
    @objc func didTapShareButton() {
        let activityItems: [Any] = [webView.title ?? "", webView.url ?? ""]
        let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
        
        present(activityViewController, animated: true)
    }
}

private extension WebViewController {
    func loadWebView(_ url: String) {
        guard let url = URL(string: url) else { return }
        let urlRequest = URLRequest(url: url)
        webView.load(urlRequest)
    }
    func setupLayout() {
        [
            webView,
            toolBar,
            indicator
        ].forEach { view.addSubview($0) }
        toolBar.snp.makeConstraints {
            $0.leading.trailing.bottom.equalToSuperview()
        }
        setupToolBar()
        webView.snp.makeConstraints {
            $0.leading.top.trailing.equalTo(view.safeAreaLayoutGuide)
            $0.bottom.equalTo(toolBar.snp.top)
        }
        indicator.snp.makeConstraints {
            $0.center.equalTo(webView.snp.center)
        }
    }
    func setupToolBar() {
        let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
        toolBar.items = [
            flexibleSpace,
            stopBarButton,
            flexibleSpace,
            refreshBarButton,
            flexibleSpace,
            goBackBarButton,
            flexibleSpace,
            goForwardBarButton,
            flexibleSpace
        ]
    }
    func checkURL(_ urlString: String) -> String {
        var url = urlString
        let httpFlag = url.hasPrefix("http://")
        let httpsFlag = url.hasPrefix("https://")
        
        if !httpFlag && !httpsFlag {
            url = "https://\(url)"
        }
        return url
    }
}
profile
iOS Developer 🐢

0개의 댓글