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
}
}
- 화면 하단에
정지
, 새로고침
, 다음
, 이전
을 나타내는 버튼들이 있다
- 먼저
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
]
}
- 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 파일을 직접 여는 방법
<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 맛보기
%20-%202022-01-29%20at%2017.29.57.png)
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
}
}