728x90
728x90
SMALL
간단하지만 꼭 사용하게 되는 웹뷰 기능 iOS는 2~3가지 구현 방법이 있다고 하는데 그 중 2가지를 살펴보고자 한다.
첫번째는 가장 일반적인 WKWebView 라이브러리를 사용하는 방법이다.
두번째는 Safari와 같은 환경으로 보여주는 SafariService 프레임워크를 사용하는 방법이다.
두개 다 크게 어려운건 없었기에 아래 간단히 결과화면과 코드 설명만 작성해본다.
결과화면
좌측은 Safari 환경이 적용된 SFSafariViewController로 구현한 모습이고,
우측은 WKWebView를 이용해 구현한 웹뷰이다.
Github
구현
- Enums.swift
enum Page:String {
case Naver = "https://www.naver.com"
case Google = "https://www.google.com"
case Tistory = "https://s-o-h-a.tistory.com"
}
오픈할 페이지 URL주소를 Enum 형식으로 관리
- SafariView.swift
import SafariServices
class CustomSafariViewController : UIViewController {
private var currentViewController:SFSafariViewController?
func openUrl(_ url:URL) {
let newViewController = SFSafariViewController(url: url)
if let currentViewController = currentViewController {
currentViewController.view.removeFromSuperview()
currentViewController.removeFromParent()
self.currentViewController = nil
}
addChild(newViewController)
newViewController.view.frame = view.frame
view.addSubview(newViewController.view)
currentViewController = newViewController
}
}
struct SafariView: UIViewControllerRepresentable {
var url: URL
func makeUIViewController(context: UIViewControllerRepresentableContext<SafariView>) -> CustomSafariViewController {
return CustomSafariViewController()
}
func updateUIViewController(_ uiViewController: CustomSafariViewController, context: UIViewControllerRepresentableContext<SafariView>) {
uiViewController.openUrl(url)
}
}
struct SafariView_Previews: PreviewProvider {
static var previews: some View {
SafariView(url: URL(string: "http://www.naver.com")!)
}
}
- Safari 형식으로 열리는 웹뷰
- UIViewController에 SFSafariViewController가 자식으로 들어있는 형태
- SafariView를 생성할 때 인스턴스를 재사용하기에 직접 삭제 후 URL 주소를 초기화 해주어야함
- UIViewController이므로 UIViewControllerRepresentable을 사용하여 SwiftUI에서 사용할 수 있도록 한다
- WebView.swift
import WebKit
class CustomWebViewContorller : UIViewController {
var url:URL?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// 웹뷰 추가
let newView = WKWebView()
newView.frame = view.frame
view.addSubview(newView)
// URL 로드
guard let url = url else { return }
newView.load(URLRequest(url: url))
}
}
struct WebView : UIViewControllerRepresentable {
var url: URL
func makeUIViewController(context: UIViewControllerRepresentableContext<WebView>) -> CustomWebViewContorller {
return CustomWebViewContorller()
}
func updateUIViewController(_ uiViewController: CustomWebViewContorller, context: UIViewControllerRepresentableContext<WebView>) {
uiViewController.url = url
}
}
struct WebView_Previews: PreviewProvider {
static var previews: some View {
WebView(url: URL(string: "http://www.naver.com")!)
}
}
- 일반 WebView 형식
- UIViewController를 열고 WKWebView화면을 추가하여 보여준다
- "This method should not be called on the main thread as it may lead to UI unresponsiveness"라는 오류가 계속 관찰되는데, Xcode 14이상 & iOS 16이상 에서 관찰되는 문제로 DispatchQueue.main을 사용해도 소용없는 버그로 보여진다. 추후 Apple에서 수정하거나 방법을 찾아봐야할 것으로 보여짐
- ContentView.swift
struct ContentView: View {
// Safari 열림 체크
@State private var isSafariShow = false
// WebView 열림 체크
@State private var isWebShow = false
// 열릴 URL
@State private var targetUrl:URL?
var body: some View {
NavigationStack {
// Safari
VStack {
Text("Safari로 열기")
.padding()
.background(.black)
.foregroundColor(.white)
.font(.headline)
.cornerRadius(10)
Button {
setSafariUrl(.Naver)
} label: {
Text("네이버 열기")
}
.navigationDestination(isPresented: $isSafariShow) {
if let targetUrl = targetUrl {
SafariView(url: targetUrl)
}
}
.padding()
Button {
setSafariUrl(.Google)
} label: {
Text("구글 열기")
}
.navigationDestination(isPresented: $isSafariShow) {
if let targetUrl = targetUrl {
SafariView(url: targetUrl)
}
}
.padding()
Button {
setSafariUrl(.Tistory)
} label: {
Text("티스토리 열기")
}
.navigationDestination(isPresented: $isSafariShow) {
if let targetUrl = targetUrl {
SafariView(url: targetUrl)
}
}
.padding()
}
.padding(60)
//WebView
VStack {
Text("WebView로 열기")
.padding()
.background(.black)
.foregroundColor(.white)
.font(.headline)
.cornerRadius(10)
Button {
setWebUrl(.Naver)
} label: {
Text("네이버 열기")
}
.navigationDestination(isPresented: $isWebShow) {
if let targetUrl = targetUrl {
WebView(url: targetUrl)
}
}
.padding()
Button {
setWebUrl(.Google)
} label: {
Text("구글 열기")
}
.navigationDestination(isPresented: $isWebShow) {
if let targetUrl = targetUrl {
WebView(url: targetUrl)
}
}
.padding()
Button {
setWebUrl(.Tistory)
} label: {
Text("티스토리 열기")
}
.navigationDestination(isPresented: $isWebShow) {
if let targetUrl = targetUrl {
WebView(url: targetUrl)
}
}
.padding()
}
}
}
// Safari로 열릴 페이지 설정
func setSafariUrl(_ pageType:Page) {
guard let url = URL(string: pageType.rawValue) else { return }
targetUrl = url
isSafariShow.toggle()
}
// Web으로 열릴 페이지 설정
func setWebUrl(_ pageType:Page) {
guard let url = URL(string: pageType.rawValue) else { return }
targetUrl = url
isWebShow.toggle()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
- Safari혹은 일반 WebView로 페이지를 여는 화면
- 버튼을 클릭할 때 url을 세팅하고 bool값을 변경시키며 동작하는 형태이다.
참고사이트
728x90
728x90
LIST
'EXPERIENCE > iOS' 카테고리의 다른 글
iOS/Swift 직무를 위한 면접 질문리스트(with. ARC, GCD, Dispatch Queue, 접근제어, 메모리 참조) (1) | 2023.02.27 |
---|---|
[Xcode/iOS] SwiftUI XCTest를 이용하여 기능과 UI 유닛/단위테스트(Unit Test) 구현하기 (with. TDD) (0) | 2023.02.08 |
[Xcode/iOS] SwiftUI 구글(Google)로그인 구현하고 정보 가져오기 (0) | 2023.02.01 |
[Xcode/iOS] CocoaPods pod init, Podfile 생성 시 Error 해결방법 (0) | 2023.01.26 |
[Xcode/iOS] 프로젝트 이름 변경 (with. CocoaPods) (0) | 2023.01.26 |