SKYPCEでは名刺管理や名刺撮影のために、iOS、Android向けのモバイルアプリを提供しています。 Web画面の処理をモバイルのネイティブアプリに委譲する仕組みとして、WebView機能の使い方を紹介します。
WebViewは、iOSおよびAndroidのネイティブアプリ内でWebコンテンツを表示するためのコンポーネントであり、 JavaScript(TypeScript)を用いることで、ネイティブアプリとWebコンテンツの間でデータの送受信が可能になります。 Webコンテンツからネイティブアプリにメッセージを送信することで、ネイティブアプリの機能を利用することができます。
概要
WKUserContentControllerを用いることで標準化されたJavaScriptのinterfaceを埋め込むことができ、 WebContentsからこのinterfaceを呼ぶことでアプリ側へメッセージを渡すことが可能です。 今回はiOSアプリ向けにこの操作をするための方法を展開します。
実装方法(Swift側)
以下の2ステップでWKUserContentControllerのメッセージ受信が行うことができます。
- コールバックハンドラー登録
- コールバックハンドラー関数の定義
コールバックハンドラー登録
WKWebViewがWKWebViewConfigurationを持っており、その中にWKUserContentControllerがあります。 これにコールバックハンドラーを登録することによりWebContentsにinterfaceが埋め込まれます。
// プロパティの初期化時に実行する。
var webView: WKWebView = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
// viewDidAppearなどで実行する。
webView.configuration.userContentController.add(self, name: "WebViewInterface")
ここで指定する"WebViewInterface"は任意の文字列が設定できます。
この名前でWebContentsから呼び出します。
また、ここで追加したコールバックハンドラーはメモリリークにつながるため、 画面を閉じる際にremoveする必要があります。
// viewDidDisappearなどで実行する。
webView.configuration.userContentController.removeAllScriptMessageHandlers()
コールバックハンドラー関数の定義
WebViewを表示するViewControllerにWKScriptMessageHandlerプロトコルを継承させます。
継承すると必要なデリゲートメソッドがないというエラーが出るのでエラーの[fix]を選択すると、
以下のようにfunc userContentController()が生成されます。
class myWebViewController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
// メッセージの解析処理
}
}
WebContentsからのメッセージはfunc userContentController()のWKScriptMessage型の引数として受信します。 bodyにWebContents側で渡したJSON形式の文字列が格納されており、 連想配列の形でデータを取り出すことが可能です。
以下はメッセージ解析処理のサンプルコードです。
class myWebViewController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
guard let body = message.body as? [String: Any] else {
return
}
guard let command = body["command"] as? String else {
return
}
// 受信したメッセージ処理
if command == "functionA" {
// functionAの処理
if let name = body["name"] as? String,
let parameters = body["parameters"] as? String {
// nameやparameters を使用した処理
}
}
else if command == "functionB" {
// functionBの処理
}
}
}
func userContentController()にこのようなメッセージ解析処理などを追加すれば、 メッセージを受け取る準備が整います。
WKScriptMessageにはnameプロパティがあり、追加したメッセージハンドラーの名前で識別することができます。
class myWebViewController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "WebViewInterface" {
// WebViewInterfaceの処理
}
else if message.name == "WebViewInterface_other" {
// WebViewInterface_otherの処理
}
}
}
実装方法(WebContents側)
Swift側(iOSアプリ側)から埋め込んだコールバックハンドラーを呼び出します。
コールバックハンドラーはJavaScriptのwindow.webkit.messageHandlersに含む形で埋め込まれます。
Swift側で追加した"WebViewInterface"のpostMessageにJSONを渡すことで
Swift側にメッセージを送信することが可能です。
postMessageは標準化されたIFなので変更することはできません。
以下はiOSへメッセージを送信するサンプルコードです。
※割愛していますが、TypeScriptではmessageHandlers関連の型定義が必要です。
const WebViewInterface = window?.webkit?.messageHandlers?.WebViewInterface;
// "WebViewInterface"はSwift側から埋め込むもので、PCでは存在しないオブジェクトになるため存在を確認する。
if (WebViewInterface) {
let name = "任意の文字列1";
let params = "任意の文字列2";
// Call iOS interface
const message = {
command: "functionA",
name: name,
parameters: params
};
// Swift側へメッセージ送信
WebViewInterface.postMessage(message);
}
以上です。本記事が何かのお役に立てれば幸いです。