Slide 1

Slide 1 text

JavaScriptでWebViewをハックする Wataru Mizukami(水上 亘) Shibuya.apk #33

Slide 2

Slide 2 text

自己紹介 - Wataru Mizukami/水上 亘 -         / @tarumzu (たる) - Organization/ sikmi, inc. TOEICテストTEPPAN英単語、好評発売中! (付録のAndroidアプリがおすすめです!)

Slide 3

Slide 3 text

WebViewを使った開発するときに JavaScriptに苦しめられたこと、 ありませんか?

Slide 4

Slide 4 text

初級編 SPAでページの変更を検知する① 通常、WebViewでページの変更を検出する場合は下記を使用す るがReactやVueで作成されたSPAではsubmitが走らないため UrlLoadingを検知できない。 WebViewClient#shouldOverrideUrlLoading

Slide 5

Slide 5 text

初級編 SPAでページの変更を検知する② webview.getSettings().setJavaScriptEnabled(true) webview.setWebViewClient(object : WebViewClient() { override fun doUpdateVisitedHistory(view: WebView, url: String, isReload: Boolean) { Log.d("MainActivity", "doUpdateVisitedHistory url = $url") } })

Slide 6

Slide 6 text

初級編 SPAでページの変更を検知する② webview.getSettings().setJavaScriptEnabled(true) webview.setWebViewClient(object : WebViewClient() { override fun doUpdateVisitedHistory(view: WebView, url: String, isReload: Boolean) { Log.d("MainActivity", "doUpdateVisitedHistory url = $url") } }) doUpdateVisitedHistoryは訪問済みリンクのデータ ベースを更新した際に呼ばれる

Slide 7

Slide 7 text

今回の例は専用のメソッドが用意されれ てたけど、なかった場合どうする? もっと自由にイベントをフックしたくない?

Slide 8

Slide 8 text

上級編 自在にイベントをフックする① webview.setWebViewClient(object : WebViewClient() { override fun onPageFinished(view: WebView, url: String) { webview.loadUrl("javascript:window.addEventListener('popState', function (event) { injectedObj.testFunction(‘test') }, false)") } })

Slide 9

Slide 9 text

上級編 自在にイベントをフックする① webview.setWebViewClient(object : WebViewClient() { override fun onPageFinished(view: WebView, url: String) { webview.loadUrl("javascript:window.addEventListener('popState', function (event) { injectedObj.testFunction(‘test') }, false)") } }) popStateとは JavaScriptのHTML5 HistoryAPIで、 history.back()、history.forward()が実行された 際に呼び出されるイベント

Slide 10

Slide 10 text

上級編 自在にイベントをフックする① webview.setWebViewClient(object : WebViewClient() { override fun onPageFinished(view: WebView, url: String) { webview.loadUrl("javascript:window.addEventListener('popState', function (event) { injectedObj.testFunction(‘test') }, false)") } }) 例えば、JavaScriptのaddEventListenerを使 えばpopStateイベントのリスナーにfunctionを 登録させることが出来る。という事は…

Slide 11

Slide 11 text

上級編 自在にイベントをフックする② class JSObject(private val webview: WebView) { @JavascriptInterface fun testFunction(str: String): String { Log.d("xxx", "hook $str") return "false" } } JSObjectというクラスを用意して…

Slide 12

Slide 12 text

上級編 自在にイベントをフックする③ webview.addJavascriptInterface(JSObject(webview), "injectedObj") webview.setWebViewClient(object : WebViewClient() { override fun onPageFinished(view: WebView, url: String) { webview.loadUrl("javascript:window.addEventListener('popState', function (event) { injectedObj.testFunction(‘test') }, false)") } }) JSObjectクラスをaddJavascriptInterfaceで登録して あげることでpopStateイベントが走った際に自前のメ ソッドが呼ばれるようになる!

Slide 13

Slide 13 text

つまり、WebView側だけの対応で、 Webページを自由自在に操作できる!

Slide 14

Slide 14 text

まとめ - SPAのページ変更検知はdoUpdateVisitedHistoryを使う。 - メソッドが用意されてなくてもJavaScriptを知ることで何でも出 来る。

Slide 15

Slide 15 text

宣伝 4/14開催の技術書典6でSwift/Kotlin愛好会合同執筆本として、 日本で唯一!のRealm Cloud入門書書くのでぜひ買いに来てくだ さい!他にも内容盛りだくさんです。 場所は「け18」よろしくおねがいします! https://techbookfest.org/event/tbf06/circle/71750003

Slide 16

Slide 16 text

ご清聴、ありがとうございました!