Android の WebView で特定のボタンが押せなくなる場合がある件

周知の通り Android の WebView はバージョン依存が酷く、クセがあります。少し油断するとコードはバッドノウハウの固まりになります。そんなネタの1つがあったのでご紹介します。


拙作の TkMixiViewer では Twitter 連携用 OAuth アクセストークンの取得時に WebView で認証画面を表示しています。具体的には adakoda.com -  を参考に実装しています。

ここで、「連携アプリを認証」ボタンを押すと、通常は WebViewClient.onPageStarted または WebViewClient.shouldOverrideUrlLoading が呼ばれ、URL遷移を判定し、特定のコールバックURLであれば認証成功と見なしてアクセストークンの取得を行うわけですが、どうにも WebViewClient のフック関数が呼ばれないケースがありました。

※おそらく普通に WebView を組み込んだだけのアプリでは発生しません。

具体的には、同アプリ内の別の Activity で WebView を含んでいて、かつその Activity を経由した場合にのみ、フック関数が呼ばれない(認証ボタンが押せない=押しても無反応になる)現象が発生しました。もう1つ加えると、Android 2.3 以降の端末でのみ発生していました。

※上記画像はエミュレータなので認証ボタンが "Authorize app" になっています。

  • (A)トップページ ⇒ ボイスの投稿画面 ⇒ Twitter認証画面
    • このパターンでは発生しない
  • (B)トップページ ⇒ ボイス一覧画面(WebViewを含む) ⇒ ボイスの投稿画面(*) ⇒ Twitter認証画面
    • このパターンでは発生する

上記 (*) の Activity では、WebView の暴走を防ぐ1つの仕掛けを組み込んでいました。
詳細は android - WebView threads never stop (WebViewCoreThread, CookieSyncManager, http[0-3]) - Stack Overflow にあるように、onWindowFocusChanged のタイミングで WebView の onPause/onResume をリフレクションで呼んでいます。内部タイマーも停止・再開していますね。

つまり、(B) の遷移パターンで (*) の Activity からTwitter認証画面(OAuthActivity)に遷移するタイミングで onWindowFocusChanged で WebView.onPause が行われるが、OAuthActivity では WebView.onResume を行っていないため、WebView 内部の動作が停止していたようで、ボタンを押しても反応しない状況となっていました。

OAuthActivity でも WebView.onPause/onResume の処理を加えることで無事、ボタン押下をハンドリングできるようになりました。


WebView の onPause/onResume すら行っていないアプリばかりだと思うので多くのアプリには関係ない話でしょうが、複数の Activity で WebView を持つアプリを作る場合には頭の片隅に置いておくと何かのときに役に立つかもー。


# 本当はもう一歩進んで Gingerbread の WebView のソースコード読むくらいのことしたほうがいいんでしょうけどそこまで体力がないので今日はこの辺で。。。