エンジニアのはしがき

プログラミングの日々の知見を書き連ねているブログです

WkWebView(Angular)からSwiftの処理を発火させる際に躓いたこと

f:id:tansantktk:20211031185311p:plain

やりたいこと

  • SwiftでWkWebView(Angular)を動作させ、WebView側からSwiftの処理を発火させたい
  • なおかつ普通のブラウザからでもAngularを動作させたい

SwiftでWkWebView(Angular)からの処理を受ける部分

今回Swiftでは下記のようなWkWebViewから処理を受けるコードを書いていました(実際の実装とは一部異なります)

extension WKWebView: WKScriptMessageHandler {
    /// WkWebViewから実行されるpostMessageを有効化。外部のファイルから当メソッドは実行される。
    public func enablePostMessage() {
      configuration.userContentController.add(self, name: "anyActionByWebView")
    }
    /// WkWebViewから実行されるpostMessageのnameから実行処理を判別する。
    public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if(message.name == "anyActionByWebView") {
            print("body: \\(message.body)")
        }
    }
}

WkWebView(Angular)からSwiftへ処理を渡す部分(変更前)

最初、以下のコードを書いていましたがmacOSChromeデバッグしたところうまく動作しませんでした。

declare var webkit;

// Swiftで定義したmessage.nameである"anyActionByWebView"を指定してpostMessage()する。
webkit.messageHandlers.anyActionByWebView.postMessage("post message for swift!");

実行時に下記のエラーが発生します。

Error: Uncaught (in promise): ReferenceError: webkit is not defined
ReferenceError: webkit is not defined
at ItadakimasuCompareService.<anonymous> (itadakimasu-compare.service.ts:31)
...

webkitが未定義と言われました。

macOSChromeで動作させた場合は未定義と言われるのですが、iOSのWkWebViewからこのソースコードを実行するとエラーは出ません。動作させる環境によって実装が異なることが原因のようです。

というわけで、webkitが未実装のケースも想定した次のソースコードに書き替えました。

WkWebView(Angular)からSwiftへ処理を渡す部分(変更後)

// window.webkitの存在チェックをした上でpostMessageする
if ((window as any)?.webkit) {
    (window as any)?.webkit.messageHandlers.anyActionByWebView.postMessage("post message for swift!");
}

これでmacOSからAngularをデバッグした場合はエラーを吐かなくなりました。

Swiftでだけ実行させたい処理があるかは微妙ですが…😑