常時ネット接続を前提とした今日のスマートフォンであるところのiPhoneでは、サーバと通信することが前提のアプリを作ることが多い。
多くのRSSリーダのように、アプリケーション内部で非同期にサーバと通信して情報を取得し、iPhoneのネイティブのUIを使って情報を表示することも多いが、UIWebViewをつかってアプリ内部にWebブラウザ機能を用意し、HTML画面を表示して直接Webサーバとユーザが対話することも可能だ。
この場合問題になるのは、UIWebViewに制御がある間、ユーザの挙動やWeb画面の遷移はアプリがあまり把握できないことだ。
もちろん、ナビゲーションバーなどにボタンを付けておけば、ユーザはアプリの任意の画面に遷移することは可能だ。しかし、その遷移のタイミングをサーバ側で制御したい場合もある。具体的にはWebブラウザ画面上で、特定のリンクをクリックしたら、iPhoneアプリ側のViewコントローラに制御を戻したい場合だ。
これを実現するには、制御させたいクラス(たいていはビューコントローラ)にUIWebViewDelegateプロトコルをインプリメントし、そのクラスをUIWebViewのdelegateに設定し、
webView:shouldStartLoadWithRequest:navigationType:
を実装すれば、Web画面が遷移するタイミングをフックすることができる。
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSString* URLString = [[[request URL] standardizedURL] absoluteString]; NSLog(@"shouldStartLoadWithRequest= %@", URLString ); if( /*何らかのURLパターンマッチングが真*/ ){ // たとえば、ルートビューに戻す [self.navigationController popToRootViewControllerAnimated:YES]; return NO; // httpリクエストを行わない } return YES; }
上の例のように、同メソッドでNOを返すことで、UIWebビューはhttpリクエストを行わない。
アプリ内部からアクセス可能なURLを制限する場合などにも有効だろう。
補記:
XMLHttpRequest()をもちいたJavaScriptからのアクセスでは、同メソッドは呼び出されないようだ。
2012-11-28追記:
続きの応用編を書きました。
UIWebView内の画面遷移をフックする 応用編 - ぽんぽこ日記
2014-09-24追記:
iOS8から導入されたWKWebViewで同様のことをしたい場合について書きました。
【iOS8】 WKWebView内の画面遷移をフックする - ぽんぽこ日記