2025. 1. 30. 12:10ㆍiOS
iOS 앱을 웹뷰(WebView) 기반으로 만들 때 신경 써야 할 주요 사항들을 정리해봅니다.
1. WKWebView vs UIWebView
- UIWebView는 iOS 12부터 deprecated 되었고, iOS 14부터는 완전히 제거되었습니다.
- WKWebView는 성능, 보안, 메모리 관리 측면에서 훨씬 뛰어나므로 반드시 WKWebView를 사용해야 합니다.
2. 네이티브와 웹 간의 통신
웹과 iOS 네이티브 코드가 데이터를 주고받아야 할 경우, WKWebView의 WKScriptMessageHandler를 사용해 JavaScript와 Swift 간의 브릿지를 만들어야 합니다.
2.1. 웹에서 네이티브로 데이터 전달
웹에서 window.webkit.messageHandlers.핸들러이름.postMessage(data)를 호출하면 네이티브에서 받을 수 있습니다.
class WebViewController: UIViewController, WKScriptMessageHandler {
var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
let contentController = WKUserContentController()
contentController.add(self, name: "nativeHandler")
let config = WKWebViewConfiguration()
config.userContentController = contentController
webView = WKWebView(frame: view.bounds, configuration: config)
view.addSubview(webView)
let url = URL(string: "https://example.com")!
webView.load(URLRequest(url: url))
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "nativeHandler", let body = message.body as? String {
print("웹에서 받은 메시지: \(body)")
}
}
}
2.2. 네이티브에서 웹으로 데이터 전달
네이티브에서 웹의 JavaScript를 실행하려면 evaluateJavaScript를 사용하면 됩니다.
let script = "window.someJavascriptFunction('Hello from Swift!')"
webView.evaluateJavaScript(script, completionHandler: nil)
3. 파일 업로드 / 다운로드
3.1. 파일 업로드 지원
WKWebView는 기본적으로 파일 업로드 기능이 제한적이므로, UIDocumentPickerViewController를 사용해서 파일을 선택한 후 JavaScript에 전달하는 방식으로 구현해야 합니다.
let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [.image, .pdf, .plainText])
documentPicker.delegate = self
present(documentPicker, animated: true)
3.2. 파일 다운로드 처리
파일 다운로드를 지원하려면 WKNavigationDelegate의 decidePolicyFor에서 직접 다운로드 요청을 감지하고 처리해야 합니다.
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
if let url = navigationResponse.response.url, let mimeType = navigationResponse.response.mimeType {
if mimeType.contains("application/pdf") {
downloadFile(from: url)
decisionHandler(.cancel)
return
}
}
decisionHandler(.allow)
}
4. 쿠키 / 세션 유지
웹뷰는 기본적으로 WKWebsiteDataStore를 이용해서 쿠키와 세션을 관리하지만, 쿠키를 직접 조작하려면 HTTPCookieStorage와 WKHTTPCookieStore를 활용해야 합니다.
4.1. 웹에서 쿠키 가져오기
if let cookies = HTTPCookieStorage.shared.cookies {
for cookie in cookies {
print("\(cookie.name): \(cookie.value)")
}
}
4.2. 네이티브에서 쿠키를 웹에 주입하기
let script = "document.cookie = 'sessionId=abc123';"
webView.evaluateJavaScript(script, completionHandler: nil)
5. iOS 백그라운드 세션 유지
웹뷰는 앱이 백그라운드로 가면 세션이 끊길 수 있습니다. 이를 방지하려면 앱이 백그라운드에서 돌아왔을 때 WKWebView를 다시 로드하거나, 쿠키를 저장하고 복원하는 방식으로 해결해야 합니다.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
webView.reload()
}
6. 네트워크 연결 상태 확인
웹이 정상적으로 로드되지 않거나 인터넷이 끊길 경우, 사용자가 알 수 있도록 네트워크 상태를 감지해야 합니다.
let monitor = NWPathMonitor()
let queue = DispatchQueue.global(qos: .background)
monitor.pathUpdateHandler = { path in
if path.status == .satisfied {
print("인터넷 연결됨")
} else {
print("인터넷 연결 안됨")
}
}
monitor.start(queue: queue)
7. WebView 캐시 관리
캐시를 삭제해야 하는 경우 WKWebsiteDataStore.default()를 사용해서 삭제할 수 있습니다.
let websiteDataTypes = WKWebsiteDataStore.allWebsiteDataTypes()
WKWebsiteDataStore.default().removeData(ofTypes: websiteDataTypes, modifiedSince: Date.distantPast) {
print("웹뷰 캐시 삭제 완료")
}
8. 다크모드 대응
웹뷰가 다크모드에서 올바르게 보이도록 하려면 CSS와 WKWebView 설정을 신경 써야 합니다.
if traitCollection.userInterfaceStyle == .dark {
let script = "document.body.style.backgroundColor = 'black'; document.body.style.color = 'white';"
webView.evaluateJavaScript(script, completionHandler: nil)
}
9. 보안 고려사항
9.1. HTTP 대신 HTTPS 사용
iOS에서는 보안 정책(ATS, App Transport Security) 때문에 HTTPS가 아닌 HTTP는 기본적으로 차단됩니다. 만약 HTTP 요청을 사용해야 한다면 Info.plist에 예외 설정을 추가해야 합니다.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
하지만 보안 문제 때문에 가능하면 HTTPS를 사용하는 게 좋습니다.
9.2. 자바스크립트 실행 제한
웹뷰에서 악성 JavaScript가 실행되지 않도록 WKPreferences에서 javaScriptEnabled를 적절히 설정해야 합니다.
let preferences = WKPreferences()
preferences.javaScriptEnabled = false
config.preferences = preferences
9.3. 사용자 데이터 보호
웹뷰에서 민감한 데이터를 다룬다면, Private Browsing Mode(비공개 모드)를 사용할 수도 있습니다.
config.websiteDataStore = WKWebsiteDataStore.nonPersistent()
10. 뒤로 가기 / 앞으로 가기 기능
웹뷰 내에서 사용자가 뒤로 가기 버튼을 누를 수 있도록 네비게이션 기능을 구현할 수 있습니다.
@objc func goBack() {
if webView.canGoBack {
webView.goBack()
}
}
@objc func goForward() {
if webView.canGoForward {
webView.goForward()
}
}
11. 웹뷰 퍼포먼스 최적화
웹뷰가 무거워지는 것을 방지하려면 다음을 고려해야 합니다.
- WKProcessPool 공유: 여러 개의 WKWebView를 사용할 때 세션을 공유할 수 있음.
- 메모리 사용량 모니터링: 너무 많은 메모리를 사용할 경우 강제로 reload 호출.
- 불필요한 자바스크립트 줄이기: WKUserScript로 최소화된 스크립트만 로드.
✅ 결론
웹뷰 기반 앱을 만들 때는 성능, 보안, 네이티브 연동 등을 신경 써야 해. 특히 WKWebView를 올바르게 활용하고, 웹과의 데이터 통신 및 세션 관리에 주의하면 더 좋은 사용자 경험을 제공할 수 있습니다. 🚀
'iOS' 카테고리의 다른 글
[Swift] Optional (0) | 2025.02.01 |
---|---|
[iOS] HTTPCookieStorage와 WKHTTPCookieStore 차이 (0) | 2025.01.30 |
[iOS] SwiftUI와 Combine (2) (0) | 2025.01.28 |
[iOS] SwiftUI와 Combine (0) | 2025.01.28 |
[iOS] SwiftUI와 MVVM (0) | 2025.01.27 |