개발
RxSwift로 웹뷰 브릿지 로직 만들기
한번사는인생~키야
2024. 7. 9. 13:03
728x90
RxSwift를 사용한 웹뷰 브릿지 로직 구현
RxSwift를 사용하여 웹뷰와 앱 간의 통신을 위한 브릿지 로직을 간편하고 효율적으로 구현할 수 있습니다.
1. 요구 사항 정의
- 웹뷰에서 JavaScript 함수를 호출하여 앱 내 함수 실행
- 앱 내 함수 실행 결과를 웹뷰에 전달
- 웹뷰에서 발생하는 이벤트를 앱 내에서 처리
2. WKScriptMessage 및 WKUserContentController 설정
- WKUserContentController인스턴스를 생성하고 웹뷰에 설정합니다.
- WKScriptMessage객체를 사용하여 JavaScript 함수 이름과 전달할 데이터를 정의합니다.
- WKUserContentController에 scriptMessageHandler를 설정하여 JavaScript 함수 호출을 처리합니다.
import UIKit
import RxSwift
import WebKit
class WebViewController: UIViewController {
@IBOutlet weak var webView: WKWebView!
private let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
setupWebView()
}
private func setupWebView() {
let userContentController = WKUserContentController()
userContentController.add(self as WKScriptMessageHandler, name: "appFunction") // JavaScript 함수 이름
webView.configuration.userContentController = userContentController
let url = URL(string: "https://www.example.com")!
webView.load(URLRequest(url: url))
}
}
extension WebViewController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "appFunction" { // JavaScript 함수 이름 확인
guard let data = message.body as? String else { return }
// data를 통해 JavaScript 함수에서 전달된 데이터 처리
DispatchQueue.main.async {
// 앱 내 함수 실행 및 결과 처리
let result = self.callAppFunction(data: data) // 앱 내 함수 호출
// 결과를 웹뷰에 전달
self.webView.evaluateJavaScript("window.receiveResult('\(result)')")
}
}
}
// 앱 내 함수 정의
private func callAppFunction(data: String) -> String {
// data를 통해 전달된 데이터를 활용하여 앱 내 로직 수행
// ...
// 결과를 문자열로 반환
return "앱 함수 실행 결과"
}
}
3. RxSwift를 사용한 브릿지 로직 구현
- RxSwift의 Observable을 사용하여 JavaScript 함수 호출 이벤트를 감지하고 처리합니다.
- Subject를 사용하여 앱 내 함수 실행 결과를 웹뷰에 전달합니다.
extension WebViewController {
// JavaScript 함수 호출 이벤트 감지
var appFunctionCall: Observable<String> {
Observable.create { observer in
webView.addObserver(self, forKeyPath: "userContentController.scriptMessageHandler", options: .new, context: nil)
return Disposables.create {
webView.removeObserver(self, forKeyPath: "userContentController.scriptMessageHandler")
}
}
.map { $0.newValue as! WKScriptMessageHandler }
.map { $0 as? WebViewController } // 타입 변환
.filter { $0 != nil }
.flatMap { $0!.appFunctionObservable } // Observable 합병
.share()
}
// 앱 내 함수 실행 결과 전달 Observable
private var appFunctionResultSubject = PublishSubject<String>()
// 앱 내 함수 실행 결과 전달 Observable
var appFunctionResult: Observable<String> {
appFunctionResultSubject.asObservable()
}
// KVO를 통해 JavaScript 함수 호출 이벤트 감지
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "userContentController.scriptMessageHandler" {
let newMessageHandler = change![NSKeyValueChangeNewKey] as! WKScriptMessageHandler
if let newViewController = newMessageHandler as? WebViewController {
appFunctionCall = newViewController.appFunctionCall
newViewController.appFunctionResult = appFunctionResultSubject.asObservable()
}
}
}
}