はじめに
Androidエンジニアの篠本(ささもと)です。
今回は、WebViewにてSPA(Single-page application)の画面遷移を検知する方法について、ご紹介をさせていただきます。
なお、この記事は以下の環境を前提としています。
- Kotlin 1.9.24
- Android APIレベル 35
また、iOSにおけるWebViewでのSPAの画面遷移の検知については、以下の記事にてご紹介しておりますので、気になる方はこちらもご参照いただければ幸いです。
SPAの画面遷移を検知する場合の問題点
WebViewとは、AndroidアプリにてWebアプリを表示するビューになります。
WebViewはWebアプリを表示するだけでなく、WebViewにて表示しているWebアプリの画面遷移を検知する仕組みがあり、画面遷移を検知して何らかの処理を実行することが可能です。
具体的には、WebViewClientのshouldOverrideUrlLoading()(外部リンク)にて画面遷移を検知します。
このメソッドをオーバーライドした独自のWebViewClientをWebViewに設定することで、画面遷移を検知できるようになります。
webView.webViewClient = object : WebViewClient() { override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean { // 画面遷移を検知したときに実行したい処理をここに書く。 return super.shouldOverrideUrlLoading(view, request) } }
上記の検知方法は、MPA(Multi-page application)と呼ばれる、Webアプリが複数のHTMLページにて構成され、ページごとにサーバーからHTMLを取得する場合に、その画面遷移を検知することができます。
しかし、SPA(Single-page application)と呼ばれる、ページごとにサーバーからHTMLを取得することなく、JavaScriptにて動的にコンテンツを書き換えることで画面遷移を実現するWebアプリでは、その画面遷移を検知することができません。
なぜなら、上記のshouldOverrideUrlLoading()はサーバーからHTMLを取得する際に呼ばれるため、JavaScriptにて動的にコンテンツを書き換えられた際には呼ばれないためです。
SPAの画面遷移を検知する方法
WebViewにてSPAの画面遷移を検知する場合、上記でも説明した通り、shouldOverrideUrlLoading()ではSPAにて行われるJavaScriptによる動的なコンテンツ書き換えによる画面遷移を検知することができないため、代わりにdoUpdateVisitedHistory()(外部リンク)を使用します。
doUpdateVisitedHistory()とは、Webアプリの履歴が更新されるときに呼ばれるWebViewClientのコールバックです。
SPAでは一般的に画面遷移を実現する際、Window.historyのpushState()(外部リンク)またはreplaceState()(外部リンク)を使用してWebアプリの履歴を更新し、ブラウザの戻るまたは進むの操作にて画面遷移できるようにします。
doUpdateVisitedHistory()はWindow.historyのpushState()またはreplaceState()によりWebアプリの履歴が更新された際に呼ばれるので、doUpdateVisitedHistory()にてSPAの画面遷移を検知できるようになります。
doUpdateVisitedHistory()では具体的に以下のようなことが可能です。
webView.webViewClient = object : WebViewClient() { override fun doUpdateVisitedHistory(view: WebView?, url: String?, isReload: Boolean) { super.doUpdateVisitedHistory(view, url, isReload) // 画面遷移を検知したときに実行したい処理をここに書く。 // doUpdateVisitedHistory()の引数urlから最新のURLを取得できる handleUrl(url) // WebViewのcopyBackForwardList()にて、更新後のWebアプリの履歴を取得できる val webBackForwardList = view?.copyBackForwardList() // WebBackForwardListのcurrentItemにて現在のWebアプリの情報を取得できる val currentItem = webBackForwardList?.currentItem // WebBackForwardListのgetItemAtIndex()にてインデックスに対応するWebアプリの情報を取得できる val webItem = webBackForwardList?.getItemAtIndex(index) } }
doUpdateVisitedHistory()の引数urlからは、画面遷移後の最新のURLを取得することが可能です。
また、WebViewのcopyBackForwardList()(外部リンク)からWebアプリの履歴が格納されたWebBackForwardList(外部リンク)を取得できるため、doUpdateVisitedHistory()の中でcopyBackForwardList()を呼び出し、画面遷移後のWebアプリの履歴を解析することも可能です。
ただし、一点注意があります。
copyBackForwardList()から取得できるWebBackForwardListはIterable(外部リンク)を継承していないため、Iterableのメソッドは使用できません。
val webBackForwardList = webView.copyBackForwardList() // NG: コンパイルエラー webBackForwardList.forEach { } // OK for (index in 0 until webBackForwardList.size) { }
最後に
WebViewはWebアプリとの連携を実現するビューになるため、このビューを使いこなすためにはAndroidアプリだけではなくてWebアプリの知識も必要になります。今後もWebViewを活用したAndroidアプリを開発するためには、AndroidアプリだけでなくWebアプリの知識もキャッチアップしなければならないと感じました。
今後もローソンデジタルイノベーションでは技術ブログを更新していきますので、是非「読者になる」で応援していただけますと幸いです。