読者です 読者をやめる 読者になる 読者になる

ninjinkun's diary

ninjinkunの日記

UIWebViewにプログレスバーを出すためのモジュールを作りました

ninjinkun/NJKWebViewProgress · GitHub

UIWebViewにはロードのプログレスを取れるインターフェイスがありません。恐らく内蔵ブラウザを抱えるアプリを作る開発者はみんな困っているはず。少なくとも自分はずっと困っています。いつか実装されるかなと気長に待っていたのですが、いい加減しびれを切らしたので作りました。iOS 7で追加されて速効ゴミになる可能性もありますが…。

なお、このモジュールはプログレスを返すインターフェイスだけを提供するので、画面に表示するにはUIProgressViewなりを使う必要があります。

プログレスバーはユーザーに進捗をほどよくフィードバックするためのものですが、この辺りの機微が結構難しかったです。*1 最終的にはWebKitの実装を参考にパラメータを決定しました。ロードしたbyte数が取れるWebKitとは違い、ロードが完了したリソースの数しか取れないので、それを使います。そのため、本物のSafariよりも伸びていく間隔が大ざっぱですが、その辺はまあご愛敬。ないよりましということで…。

具体的なパラメータとしては以下の様になります。

  • ロードが始まったら0.1
  • HTMLが見られるようになるまでは最大値0.5でプログレスを追加していく
  • HTMLが見られるようになったら最大値0.9でプログレスを追加していく
  • 全部完了したら1.0

また、WebViewのレンダリング状態には以下のパラメータを使っています。

  • HTMLが見られる状態は document.readyState == 'interactive'
  • 全部完了した状態 はdocument.readyState == 'complete'

導入は以下の様に、WebViewDelegateとViewControllerの間に挟むproxyとして導入します。UIWebViewDeleateのメソッドは全てwebViewProxyDelegateの方にもFowardされるので、既存のコードの変更はここだけで済むはずです。

NJKWebViewProgress *progressProxy = [[NJKWebViewProgress alloc] init];
webView.delegate = progressProxy;
progressProxy.webViewProxyDelegate = self;
progressProxy.progressDelegate = self;

特に黒魔術的なものは使っていないので、レビューも普通に通るはず(未確認)通りました。

まだ作ったばかりなのですが、デモの段階では割と良い感じで使えている気がします。もっとこうした方が正確になるよ、もっと良い感じにフィードバックできるよ、NJKプレフィックスきもいなどご意見ありましたら、ぜひコメントやIssue等で教えてください。

ninjinkun/NJKWebViewProgress · GitHub

*1:個人的にこういうのを空気読み系エンジニアリングと呼んでいる