WKWebView
を使用して、3つのボタンを含むHTMLを含むWebサイトを表示しています。特定のボタンがクリックされたときに、ネイティブアプリでSwiftコードを実行したい。
3つのボタンは次のようになります。
<input type="button" value="Edit Info" class="button" onclick="javascript:GotoURL(1)">
<input type="button" value="Start Over" class="button" onclick="javascript:GotoURL(2)">
<input type="button" value="Submit" class="button" onclick="javascript:GotoURL(3)">
呼び出すGotoURL
関数は次のようになります。
function GotoURL(site)
{
if (site == '1')
document.myWebForm.action = 'Controller?op=editinfo';
if (site == '2')
document.myWebForm.action = 'Controller?op=reset';
if (site == '3')
document.myWebForm.action = 'Controller?op=csrupdate';
document.myWebForm.submit();
}
WKWebView
実装WebViewのボタンのいずれかをクリックすると、WKNavigationDelegate
でこの関数が呼び出されます。
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
// ...?
}
しかし、もちろん、navigation
は不透明であるため、ユーザーが3つのボタンのどれをクリックしたかに関する情報は含まれていません。
ユーザーがSubmitをクリックしたときに応答し、他のボタンの押下を無視したい。
Stack OverflowでWKUserContentController
を使用する他のアプローチもいくつかありますが、Webサイトで次のような呼び出しを行う必要があります。
window.webkit.messageHandlers.log.postMessage("submit");
私はこのウェブサイトを管理していないので、ソースコードにこの行を追加することはできません。また、WKWebView
を使用して正しい場所に挿入する最良の方法がわかりません。
ユーザースクリプトは、ドキュメントの読み込みの開始時またはドキュメントの読み込みが完了した後にWebページに挿入するJSです。ユーザースクリプトは、Webページのクライアント側のカスタマイズを許可し、イベントリスナーの挿入を許可し、さらにネイティブアプリにコールバックできるスクリプトの挿入にも使用できるため、非常に強力です。次のコードスニペットは、ドキュメントの読み込みの最後に挿入されるユーザースクリプトを作成します。ユーザースクリプトは、WKWebViewConfigurationオブジェクトのプロパティであるWKUserContentControllerインスタンスに追加されます。
_// Create WKWebViewConfiguration instance
var webCfg:WKWebViewConfiguration= WKWebViewConfiguration()
// Setup WKUserContentController instance for injecting user script
var userController:WKUserContentController= WKUserContentController()
// Get script that's to be injected into the document
let js:String= buttonClickEventTriggeredScriptToAddToDocument()
// Specify when and where and what user script needs to be injected into the web document
var userScript:WKUserScript = WKUserScript(source: js,
injectionTime: WKUserScriptInjectionTime.AtDocumentEnd
forMainFrameOnly: false)
// Add the user script to the WKUserContentController instance
userController.addUserScript(userScript)
// Configure the WKWebViewConfiguration instance with the WKUserContentController
webCfg.userContentController= userController;
_
Webページは、window.webkit.messageHandlers.<name>.postMessage (<message body>)
メソッドを介してネイティブアプリにメッセージを投稿できます。ここで、「名前」は、ポストバックされるメッセージの名前です。 JSは任意のJSオブジェクトをメッセージ本文としてポストバックでき、JSオブジェクトは対応するSwift=ネイティブオブジェクトに自動的にマッピングされます。次のJSコードスニペットは、ボタンクリックイベントが発生したときにメッセージをポストバックしますIDが「ClickMeButton」のボタン。
_varbutton = document.getElementById("clickMeButton");
button.addEventListener("click", function() {
varmessageToPost = {'ButtonId':'clickMeButton'};
window.webkit.messageHandlers.buttonClicked.postMessage(messageToPost);
},false);
_
Webページによって投稿されたメッセージを受信するには、ネイティブアプリがWKScriptMessageHandlerプロトコルを実装する必要があります。プロトコルは、単一の必須メソッドを定義します。コールバックで返されたWKScriptMessageインスタンスは、ポストバックされているメッセージの詳細を照会できます。
_func userContentController(userContentController: WKUserContentController,
didReceiveScriptMessage message: WKScriptMessage) {
if let messageBody:NSDictionary= message.body as? NSDictionary{
// Do stuff with messageBody
}
}
_
最後に、WKScriptMessageHandlerプロトコルを実装するネイティブクラスは、次のように自身をWKWebViewのメッセージハンドラとして登録する必要があります。
_// Add a script message handler for receiving "buttonClicked" event notifications posted
// from the JS document
userController.addScriptMessageHandler(self, name: "buttonClicked")
_
Webビューで evaluateJavaScript(_:)
を使用すると、いつでもソースコードを挿入できます。そこから、ボタンのイベントハンドラーを置き換える(メッセージを投稿してから新しいハンドラーで元の関数を呼び出す)か、ボタンまたはクリックイベントをキャプチャしてメッセージを投稿する先祖要素にイベントハンドラーを追加します。 (元のイベントハンドラも実行されます。)
document.getElementById("submit-button").addEventListener("click", function () {
window.webkit.messageHandlers.log.postMessage("submit");
});
ボタンにIDがない場合、すべての(バブル)クリックイベントをキャプチャし、イベントターゲットに基づいてメッセージを投稿するハンドラーをドキュメントに追加できます(ボタンのテキストまたは場所を決定要因として使用)。
evaluateJavaScript()
関数を使用して、WKWebView
にJSコードを挿入できます。次のJSコードを使用して、onclick
ボタンのクリックのみを検出するすべてのsubmit
イベントをキャプチャできます。元のイベントハンドラーもすべて実行されます-心配しないでください!
document.addEventListener("click", function(e)
{
e = e || window.event;
//if(e.target.value == 'Submit') //you can identify this button like this, but better like:
if(e.target.getAttribute('onclick') == 'javascript:GotoURL(3)')
//if this site has more elements with onclick="javascript:GotoURL(3)"
//if(e.target.value == 'Submit' && e.target.getAttribute('onclick') == 'javascript:GotoURL(3)')
{
console.log(e.target.value);
//if you need then you can call the following line on this place too:
//window.webkit.messageHandlers.log.postMessage("submit");
}
});
//DO NOT add the next line in your code! It is only for my demo - buttons need this in my demo for execution
function GotoURL(site){}//DO NOT add this line! It is only for my demo!
<input type="button" value="Edit Info" class="button" onclick="javascript:GotoURL(1)">
<input type="button" value="Start Over" class="button" onclick="javascript:GotoURL(2)">
<input type="button" value="Submit" class="button" onclick="javascript:GotoURL(3)">