Swift 9주차 - 웹 뷰로 간단한 웹 브라우저 만들기

2024. 5. 4. 02:32swift

Swift 9주차 - 웹 뷰로 간단한 웹 브라우저 만들기

 

 

이번 주차에서는 웹 뷰를 사용해 다양한 기능을 구현하는 웹 페이지를 만들어 볼 예정이다.

 

목차

     

    웹 뷰(Web View)

     

    웹 뷰(Web View)는 웹 콘텐츠를 뷰 형태로 보여주는 앱이다. 크롬 브라우저와 같이 HTML로 작성된 홈페이지를 표시할 수 있다.

     

    직접 인터넷에 연결된 주소를 입력하여 홈페이지에 접속할 수 있을 뿐만 아니라 미리 저장된 HTML 파일을 읽어들여 표시할 수도 있다.

     

     

     

    웹 뷰 앱 화면 꾸미기

     

    먼저 홈페이지 URL을 입력할 텍스트 필드를 추가해보자.

     

    우측 상단 라이브러리 버튼을 클릭해 택스트 필드(Text Field)를 찾고 스토리보드 위쪽에 끌어오자.

     

     

     

    그리고 홈페이지 이동을 위한 버튼을 추가하자.

     

     

     

    인스펙터 창을 열어 버튼 스타일을 Default로 변경하자.

     

     

    버튼의 텍스트는 Go로 변경하자.

     

     

     

    같은 방법으로 버튼을 6개 더 추가해보자.

    마찬가지로 버튼 6개 모두 스타일을 Default로 변경하자.

     

     

    위 화면처럼 버튼 텍스트를 각각 Site1, Site2, Site3, Site4, HTML, File로 변경하자.

     

     

    그리고 웹킷 뷰(WebKit View)를 찾아 화면 가운데에 추가하자.

     

     

     

     

    이제 홈페이지를 제어할 수 있는 툴바(Toolbar)를 추가해보자.

     

     

    그리고 이 툴바에 바 버튼 아이템(Bar Button Item)을 3개 더 추가해서 총 4개로 구성해보자.

     

     

     

    버튼들이 정렬이 되지 않아 보기 불편한 상태다.

     

    버튼들이 툴바에 균등하게 배치될 수 있도록 플렉서블 스페이스 바 버튼 아이템(Flexible Space Bar Button Item)을 추가해보자.

     

    플렉서블 스페이스 바 버튼 아이템을 아래처럼 바 버튼 아이템 사이사이에 추가하자.

     

    Flexible | Item | Flexible | Item | Flexible | Item | Flexible | Item | Flexible

     

     

     

    플렉서블 아이템을 추가하면 위 사진처럼 자동으로 버튼들이 정렬될 것이다.

     

    이제 바 버튼 아이템들을 아이콘으로 변경해보자.

     

     

    아이템을 선택하고 시스템 아이템을 정지(Stop)로 변경하자.

     

    같은 방법으로 남은 아이템들도 각각 새로고침(Refresh), 되감기(Rewind), 앞으로 감기(Fast Forward)로 변경하자.

     

     

     

    마지막으로 로딩을 표시하기 위한 액티비티 인디케이터 뷰를 화면 가운데에 추가하자.

     

    액티비티 인디케이터 뷰란 아이폰을 사용할 때 로딩을 기다릴 때 화면 가운데에서 돌아가는 원 모양의 점선을 말한다.

     

     

    그리고 Hides When Stopped를 활성화하여 동작이 멈추면 보이지 않게 하자.

     

     

    아웃렛 변수와 액션 함수 추가하기

     

    텍스트 필드에 대한 아웃렛 변수를 추가해보자.

     

     

    이름은 txtUrl로 지정하고 연결하자.

     

     

    그다음 웹 뷰에 대한 아웃렛 변수를 추가하자.

     

     

    이름은 myWebView로 설정하자.

     

    웹 뷰 아웃렛 변수를 추가하면 아래처럼 에러가 발생할 것이다.

     

    에러가 발생한 이유는 타입이 WKWebView로 설정되어 있는데 WKWebView가 정의되어 있는 WebKet이 import 되지 않았기 때문이다.

     

    아래처럼 WebKit을 import 해주자.

     

     

    마지막으로 액티비티 인디케이터 뷰에 대한 아웃렛 변수를 추가하자.

     

     

    이름은 myActivityIndicator로 설정하자.

     

     

    이제 Go 버튼에 대한 액션 함수를 추가하자.

     

     

    이름은 btnGotoUrl로 변경하고 타입은 UIButton으로 변경하자.

     

     

    다음으로 Site1 버튼에 대한 액션 함수를 추가하자.

     

     

    이름은 btnGoSite1으로 변경하고 타입은 UIButton으로 변경하자.

     

     

    같은 방식으로 Site2, Site3, Site4 버튼의 액션 함수 btnGoSite2, btnGoSite3, btnGoSite4를 추가하자.

     

     

     

    HTML 버튼의 액션 함수를 추가하자.

     

     

    이름은 btnLoadHtmlString으로 변경하고 타입은 UIBtton으로 변경하자.

     

     

    마지막으로 File 버튼의 액션 함수를 추가하자.

     

     

    이름은 btnLoadHtmlFile로 변경하고 타입은 UIButton으로 변경하자.

     

     

    이제 툴바의 아이템들의 액션 함수를 추가하자.

     

    먼저 Stop 아이템에 대한 액션 함수를 추가하자.

     

     

    이름은 btnStop로 변경하고 타입은 UIBarButtonItem으로 변경하자.

     

    같은 방법으로 툴바 버튼 Refresh, Rewind, Fast Forward의 액션 함수를 추가하자.

     

    이름은 각각 btnReload, btnGoBack, btnGoForward로 변경하고 타입도 UIBarButtonItem으로 변경해주자.

     

     

     

    이렇게 모든 액션 함수가 추가되었다.

     

     

    앱 시작시 지정된 페이지 보여주기

     

    먼저 앱을 처음 시작할 때 기본적으로 특정 웹 페이지를 보여 주기 의해 웹 페이지를 로드하는 함수를 만들어야 한다.

     

    viewDidLoad 함수 위에 아래 코드를 추가해주자.

     

    func loadWebPage(_ url: String) {
        let myUrl = URL(string: url) // 1
        let myRequest = URLRequest(url: myUrl!) // 2
        self.myWebView.load(myRequest) // 3
    }

     

    1. 상수 myUrl은 url값을 받아 URL타입으로 선언한다.
    2. 상수 myRequest는 상수 myUrl을 받아 URLRequest타입으로 선언한다.
    3. UIWebView형의 myWebView 클래스의 load 메서드를 호출한다.

     

    앱을 시작할 때 지정한 웹 페이지가 나타나도록 viewDidLoad 함수 안에 loadWebPage 함수를 추가해보자.

     

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        loadWebPage("https://nicodora.tistory.com")
    }

     

    주소는 임의로 필자의 블로그 주소를 입력하였다.

     

     

    그리고 에뮬레이터를 실행해보면 아마 지정된 웹 페이지가 나타나지 않을 것이다.

     

    이 문제를 해결하기 위해선 Info.plist 파일을 수정하여 웹 페이지에 접속할 수 있도록 권한을 줘야 한다.

     

     

    Info.plist파일을 선택하고 Information Property List의 오른쪽에 있는 +를 눌러 항목을 추가하자.

     

    App Transport Security Settings를 선택하자.

     

     

     

    App Transport Security Settings 왼쪽 화살표가 아래로 향하도록 한 다음 다시 한번 + 를 눌러 항목을 추가하고 Allow Arbitrary Loads를 선택하자.

     

     

     

    Allow Arbitrary Loads의 Value값을 YES로 변경하자.

     

     

     

    이제 에뮬레이터를 실행해보면 아래처럼 지정한 웹 페이지가 나타나게 된다.

     

     

    액티비티 인디케이터 구현하기

     

    아래 사진처럼 뷰 컨트롤러의 선언문과 viewDidLoad() 함수에 코드를 추가하자.

     

     

     

    viewDidLoad() 함수 아래에 로딩중인지 확인하기 위한 매개변수에 didCommit이 있는 webView 함수를 추가하자.

     

     

    func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
        myActivityIndicator.startAnimating()
        myActivityIndicator.isHidden = false
    }

     

    myWebView가 로딩중일때 인디케이터를 실행하고 화면에 나타나게 한다.

     

     

    같은 방법으로 아래처럼 두개의 webView 함수를 추가해보자.

     

     

     

    didFinish를 매개변수로 가지는 webView함수는 로딩이 완료되었을 때 동작하므로 인디케이터를 중지하고 숨긴다.

     

    didFail을 매개변수로 가지는 webView함수는 로딩 실패시 동작하므로 마찬가지로 인디케이터를 중지하고 숨긴다.

     

     

     

    Site1, Site2, Site3, Site4 버튼 구현하기

     

    이제 버튼을 클릭하면 지정한 웹 사이트로 이동하도록 코드를 추가해보자.

     

    각각의 Site 버튼을 클릭해서 이동할 웹 사이트의 주소를 btnGoSite1, btnGoSite2, btnGoSite3, btnGoSite4 함수에 추가하자.

     

    @IBAction func btnGoSite1(_ sender: UIButton) {
        loadWebPage("https://www.navercorp.com/")
    }
    
    @IBAction func btnGoSite2(_ sender: UIButton) {
        loadWebPage("https://about.google/")
    }
    
    @IBAction func btnGoSite3(_ sender: UIButton) {
        loadWebPage("https://toss.im/")
    }
    
    @IBAction func btnGoSite4(_ sender: UIButton) {
        loadWebPage("https://www.apple.com/kr/")
    }

     

     

    에뮬레이터를 실행하여 Site 버튼을 클릭하면 지정한 웹 사이트로 이동하는 것을 확인할 수 있다.

     

     

     

    정지, 재로딩, 이전 페이지, 다음 페이지 버튼 구현하기

     

    웹 브라우저의 기본 기능인 정지, 재로딩, 이전 페이지로 이동, 다음 페이지로 이동을 웹 뷰에서 동작하도록 구현해보자.

     

    해당 액션들을 제어할 수 있는 코드를 각각 btnStop, btnReload, btnGoBack, btnGoFoward 함수에 추가하자.

     

    @IBAction func btnStop(_ sender: UIBarButtonItem) {
        myWebView.stopLoading()
    }
    
    @IBAction func btnReload(_ sender: UIBarButtonItem) {
        myWebView.reload()
    }
    
    @IBAction func btnGoBack(_ sender: UIBarButtonItem) {
        myWebView.goBack()
    }
    
    @IBAction func btnGoForward(_ sender: UIBarButtonItem) {
        myWebView.goForward()
    }

     

     

    에뮬레이터를 실행시켜 해당 버튼들을 눌러보면 제대로 동작하는 모습을 확인할 수 있다.

     

     

     

     

     

    HTML 버튼 구현하기

     

    HTML 코드를 변수에 저장하고 HTML 버튼을 클릭하면 변수의 내용이 HTML 형식에 맞추어 웹 뷰로 나타나게 구현해 보자.

     

    아래 코드를 btnLoadHtmlString 함수 안에 입력하자.

     

    @IBAction func btnLoadHtmlString(_ sender: UIButton) {
        let htmlString = "<h1> HTML String </h1><p> String 변수를 이용한 웹 페이지 </p> <p><a href=\"https://www.induk.ac.kr/index.do\">인덕대학교 홈페이지</a>로 이동</p>"
        myWebView.loadHTMLString(htmlString, baseURL: nil)
    }

     

    HTML문을 변수에 저장하고 loadHTMLString 함수를 이용하여 변수에 저장된 HTML문을 웹 뷰에 나타낸다.

     

    에뮬레이터를 실행시킨 후 HTML 버튼을 눌러보면 변수에 저장했던 HTML문이 적용되는 것을 확인할 수 있다.

     

     

    File 버튼 구현하기

     

    이번에는 File 버튼을 클릭하면 HTML 파일을 읽어들여 웹 뷰로 나타내는 코드를 추가해 보려고 한다.

     

    메뉴의 File -> New -> File... 을 클릭하자.

     

     

     

    그런다음 Other의 Empty를 선택한 후 Next 버튼을 클릭한다.

     

     

     

    Save As에 htmlView.html 을 입력해 파일명을 정하고 Create 버튼을 클릭하여 HTML 파일을 생성하자.

     

     

     

    추가된 HTML 파일을 Web 폴더 안으로 이동시킨다.

     

     

    그런 다음 html 파일을 열어 아래 코드를 추가하자.

     

    <html>
        <head>
            <meta charset="utf-8">
        </head>
        <body>
            <h1> HTML FILE </h1>
            html File을 이용한 웹페이지<br>
            <p><a href="https://www.induk.ac.kr/index.do\">인덕대학교 홈페이지</a>로 이동</p>
        </body>
    </html>

     

     

    그리고 다음 소스코드를 btnLoadHtmlFile 함수에 입력한다.

     

    @IBAction func btnLoadHtmlFile(_ sender: UIButton) {
        let filePath = Bundle.main.path(forResource: "htmlView", ofType: "html") // 1
        let myUrl = URL(fileURLWithPath: filePath!) // 2
        let myRequest = URLRequest(url: myUrl) // 3
        myWebView.load(myRequest) // 4
    }

     

    1. htmlView.html 파일에 대한 패스 변수를 생성한다.
    2. 패스 변수를 이용하여 URL 변수를 생성한다.
    3. URL 변수를 이용하요 Request 변수를 생성한다.
    4. Request 변수를 이용하요 HTML 파일을 로딩한다.

     

    에뮬레이터를 실행하여 File 버튼을 클릭하면 미리 만들어 놓은 HTML 파일의 내용이 적용된 것을 확인할 수 있다.

     

     

     

    http:// 문자열 자동 삽입 기능 구현하기

     

    우리가 보통 웹 브라우저에서 주소를 입력할 때 프로토콜(http://)을 직접 입력하지 않고 사용한다.

     

    하지만 이는 웹 브라우저에서 기본적으로 설정을 해놨기 때문이고 실제로는 내부적으로 프로토콜을 적어줘야 한다.

     

    따라서 이번에는 입력받은 문자열에 프로토콜이 있는지 검사하고 없을 경우 'http://' 문자열을 자동으로 추가하는 함수를 만들어 보려고 한다.

     

     

    btnGoUrl 함수 위에 checkUrl 함수를 추가하자.

     

    그리고 아래 소스 코드를 checkURL 함수에 추가하자.

     

    func checkUrl(_ url: String) -> String {
        var strUrl = url
        let flag = strUrl.hasPrefix("http://")
        if !flag {
            strUrl = "http://" + strUrl
        }
        return strUrl
    }

     

    입력받은 url이 'http://'를 가지고 있지 않다면 strUrl에 'http://'를 추가하고 리턴한다.

     

     

    Go 버튼을 클릭하면 텍스트 필드에 적힌 주소로 웹 뷰가 로딩되도록 btnGotoUrl 함수를 수정하자.

     

    @IBAction func btnGotoUrl(_ sender: UIButton) {
        let myUrl = checkUrl(txtUrl.text!)
        txtUrl.text = ""
        self.loadWebPage(myUrl)
    }

     

     

     

    에뮬레이터를 실행시킨 후 텍스트 필드에 입력한 페이지 주소로 이동하는 것을 확인할 수 있다.

     

    'http://' 를 입력하지 않아도 해당 주소로 정상적으로 이동하는 것을 확인할 수 있다.

     

     

     

    웹 뷰 앱 전체 소스 코드

     

    import UIKit
    import WebKit
    
    class ViewController: UIViewController, WKNavigationDelegate {
        
        @IBOutlet var txtUrl: UITextField!
        @IBOutlet var myWebView: WKWebView!
        @IBOutlet var myActivityIndicator: UIActivityIndicatorView!
        
        func loadWebPage(_ url: String) {
            let myUrl = URL(string: url)
            let myRequest = URLRequest(url: myUrl!)
            self.myWebView.load(myRequest)
        }
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            myWebView.navigationDelegate = self
            loadWebPage("https://nicodora.tistory.com")
        }
        
        func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
            myActivityIndicator.startAnimating()
            myActivityIndicator.isHidden = false
        }
        
        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            myActivityIndicator.stopAnimating()
            myActivityIndicator.isHidden = true
        }
        
        func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: any Error) {
            myActivityIndicator.stopAnimating()
            myActivityIndicator.isHidden = true
        }
        
        func checkUrl(_ url: String) -> String {
            var strUrl = url
            let flag = strUrl.hasPrefix("http://")
            if !flag {
                strUrl = "http://" + strUrl
            }
            return strUrl
        }
    
        @IBAction func btnGotoUrl(_ sender: UIButton) {
            let myUrl = checkUrl(txtUrl.text!)
            txtUrl.text = ""
            self.loadWebPage(myUrl)
        }
        
        @IBAction func btnGoSite1(_ sender: UIButton) {
            loadWebPage("https://www.navercorp.com/")
        }
        
        @IBAction func btnGoSite2(_ sender: UIButton) {
            loadWebPage("https://about.google/")
        }
        
        @IBAction func btnGoSite3(_ sender: UIButton) {
            loadWebPage("https://toss.im/")
        }
        
        @IBAction func btnGoSite4(_ sender: UIButton) {
            loadWebPage("https://www.apple.com/kr/")
        }
        
        @IBAction func btnLoadHtmlString(_ sender: UIButton) {
            let htmlString = "<h1> HTML String </h1><p> String 변수를 이용한 웹 페이지 </p> <p><a href=\"https://www.induk.ac.kr/index.do\">인덕대학교 홈페이지</a>로 이동</p>"
            myWebView.loadHTMLString(htmlString, baseURL: nil)
        }
        
        @IBAction func btnLoadHtmlFile(_ sender: UIButton) {
            let filePath = Bundle.main.path(forResource: "htmlView", ofType: "html")
            let myUrl = URL(fileURLWithPath: filePath!)
            let myRequest = URLRequest(url: myUrl)
            myWebView.load(myRequest)
        }
        
        @IBAction func btnStop(_ sender: UIBarButtonItem) {
            myWebView.stopLoading()
        }
        
        @IBAction func btnReload(_ sender: UIBarButtonItem) {
            myWebView.reload()
        }
        
        @IBAction func btnGoBack(_ sender: UIBarButtonItem) {
            myWebView.goBack()
        }
        
        @IBAction func btnGoForward(_ sender: UIBarButtonItem) {
            myWebView.goForward()
        }
        
    }