안드로이드는 JavascriptInterface를 사용하면 쉽게 native -> javascript로 데이터 전송이 가능한 반면,
IOS는 조금 더 설정해주어야 할 부분들이 있어서 정리하였다.
let configuration = WKWebViewConfiguration()
let contentController = WKUserContentController()
configuration.userContentController = contentController
//웹뷰 인스턴스 생성
let webview = WKWebView(frame: .zero, configuration: configuration)
웹뷰 인스턴스를 생성할 때, configuration을 먼저 설정해주어야 한다. 이때 반드시 WKUserContentController 객체를 먼저 생성하고 설정해주어야 late하게 userContentController를 할당해 줄 수 있다.
webview 객체를 먼저 생성하고 추후에 configuration에 controller를 할당하면 제대로 할당되지 않는다!
let wmHandler = WKController(webview)
contentController.add(wmHandler, name: "getDeviceToken")
webview.configuration.userContentController = contentController
class WKController: NSObject ,WKScriptMessageHandler {
var webview: WKWebView
init(_ webview: WKWebView) {
self.webview = webview
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "getDeviceToken" {
let fcmToken = String(UserDefaults.standard.string(forKey: "deviceToken") ?? "")
print("fcmToken :", fcmToken)
let myJsFuncName = "mergeAppUserInfo('\(fcmToken)')"
webview.evaluateJavaScript(myJsFuncName)
}
}
}
WKScriptMessageHandler에서 이전에 생성한 webview 인스턴스를 사용하여 evaluateJavaScript 함수를 호출한다.
위 코드는 Javascript의 'mergeAppUserInfo(arg)'를 호출한다.
이때 "getDivceToken"은 javascript에서 해당 native 코드를 호출하는 이름이 된다.
<script
dangerouslySetInnerHTML={{
__html: `
function mergeAppUserInfo(token){
localStorage.setItem("deviceToken", token);
return token;
};`,
}}
async
></script>
Next.js를 사용중이기 때문에 _document단에 위와같이 전역으로 함수를 작성하였다.
// native에서 js코드를 호출하여 localStorage에 deviceToken을 저장한다.
window.webkit.messageHandlers.getDeviceToken.postMessage();
messageHanlder를 이용하여 native에 작성해두었던 'getDiviceToken'이라는 이름으로 해당 함수를 호출할 수 있다.