OS X には今をときめく WebKit が搭載されているので、Web ページを表示するコンポーネントである WebView を使えば、ほとんどコーディングすることなしにウェブブラウザ風のアプリができあがってしまいます。
フェンリルのブラウザ Sleipnir for Mac も WebView を使っています。もしかしたらさっきのような理由で「ブラウザなんて簡単にできるもんね」と思われるかもしれませんが、実際に作っていくとデスクトップのウェブブラウザに求められるごく当たり前の機能も WebView そのままでは動かなかったりして、開発しなければならない部分が山ほどあるのが現実です。
今日は、そんな機能のうちのひとつ「エラーページの表示」について取り上げてみましょう。
たとえば存在しないサーバにアクセスしたら、ブラウザがエラーページを表示するというのはブラウザのごくごく基本的な機能です。でも、WebView をただ貼り付けただけのアプリでは、存在しないサーバにアクセスしてもウンともスンとも言わず、真っ白なページになってしまいます。
エラーページの表示は WebKit のサポート外で、アプリケーション側で実装しなければならないのです。
エラーページは特殊なページ
当たり前と言えば当たり前ですが、エラーページというのはブラウザにとって特殊なページです。
まず、エラーページそのものは履歴に残りません。履歴を前後に移動したらさっき見たエラーページをロードするブラウザがあったら「ちょっと違うよソレ」という感じですよね(同じエラーが発生していたら期待どおりと言えますが)。
一方で、読み込もうとしたアドレスは履歴に残ります。たとえばネットワークエラーでエラーページが表示された場合、いったん戻って、ネットワーク接続が回復したあとに「進む」をしたら、今度はエラーにならずに目的のページが読み込まれてほしいですよね。
つまりエラーページというのは、履歴に残るアドレスと、実際に読み込む内容が違うページなわけです。
どうやって実現するか
こんな特殊なエラーページ、どうやって表示すればいいんでしょうか?履歴をいじくったりしなくてはならないのでしょうか?
いえいえ、そこはさすが今をときめく WebKit フレームワーク。エラーページの表示まではしてくれませんが、表示するための手段はちゃんと用意してくれているのです。
まず、エラーの発生そのものは WebView に設定した WebFrameLoadDelegate に通知されます。ネットワークエラーなど、そもそも読み込み開始できないエラーの場合には
- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame;
が呼び出されます。WebView のメインフレームのロードで失敗してこのメソッドが呼び出された時こそ、エラーページを表示すべき時です(実際はもうちょっといろいろ条件判定がいります)。
そしていざエラーページを表示するためのメソッドは WebView に含まれている WebFrame オブジェクトにあります。
- (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)URL forUnreachableURL:(NSURL *)unreachableURL;
まさにこれです。エラーが起きた unreachable な URL に対して alternate な HTML 文字列をロードしたかったんです、ずっと。しかもこのメソッドのドキュメントにはこんな嬉しい一言が書いてあります。
“the back-forward list is maintained.” (戻る・進む履歴はちゃんと管理されます)
すばらしい。これぞ渡りに舟。というわけで、ズババッと WebFrame にエラーページの HTML 文字列を流し込んであげましょう。さすがにエラーページの HTML 文字列は自分で作らないといけないのでそこはがんばりましょう。
上の 2 つのメソッドを組み合わせたコードは次のようなものになります。
- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { if ([sender mainFrame] == frame) { if (.... // さらに追加で条件判定いろいろ) { NSURL *unreachable = ... // error オブジェクトから元の URL を取得 NSString *html = ... // エラーページの HTML を文字列にしたもの NSURL *base = ... // HTML 文字列から外部参照する場合の baseURL [frame loadAlternateHTMLString:html baseURL:base forUnreachableURL:unreachable]; } } }
Sleipnir のエラーページ
Sleipnir は、エラーページもしっかりとデザインされた美しいものを用意しています。もちろん Retina ディスプレイ対応。まだ実物をご覧になったことがない方は、ぜひ Sleipnir のエラーページも堪能してみてください。
参考リンク
さらに詳しく知りたい方は、Apple の API リファレンスをご覧ください。
では、みなさんが Mac でブラウザを開発する際には、今回の記事を参考にステキなエラーページを表示してくださいね。