2012/10/02更新

[XCODE] UIWebViewでWebページを表示した際にJSのconsole.logの内容を表示する方法

このエントリーをはてなブックマークに追加            

こんにちは、@yoheiMuneです。
今日は、UIWebViewベースのアプリケーションのデバッグに役立つ、 window.cosole.logの内容をXCODEのコンソールに出力する方法を書きたいと思います。

画像



UIWebViewベースのアプリはデバッグしづらい?

UIWebViewベースのアプリを開発する際に、デバッグがしづらいという問題点があります。
通常のWebページ開発では、Chromeのデベロッパーツールや、iPhone用のWebインスペクタ(詳細は、こちらを参照)を用いて開発する事で、効率的にデバッグする事が可能です。

しかしUIWebViewで表示するWebページのデバッグはJSのログとか見えないので、デバッグしづらい。
その解決策はいくつかありますが、今回はJavaScriptのwindow.console.logをXCODEのコンソールに出力して、 デバッグ情報を入手しやすくする方法を紹介したいと思います。

なお以下で紹介する方法は、Stack Overflowで紹介された内容を発展させた内容となります。



JavaScriptで出力するログをXCODEのコンソールに表示する

XCODEのコンソールにJavaScriptのwindow.console.logを出力することで、デバッグをしやすくすることが出来ます。
JavaScriptとObjective-Cで、それぞれ以下の実装を行います。
  • JavaScriptでXCODEでログ出力する為のリクエストを発信する。
  • UIWebViewでログ出力用のリクエストを補足して、内容をコンソールに出力する。


JavaScriptでXCODEでログ出力する為のリクエストを発信する

javaScript側では、以下のように行うことで、UIWebViewに向けたリクエストを発信します。
// window.console.logを上書きすると動かない場合もあるので、
// 今回は新しいメソッドを定義する。
window.log = function(msg) {

  // まずは通常通りのログ出力を行う。
   console.log(msg);

  // UIWebViewを用い手居る場合には、
  // XCODEのコンソールにも出力する仕組みを導入する。
   if (isUIWebView && debug) {
     var iframe = document.createElement("IFRAME");
     iframe.setAttribute("src", "ios-log:#iOS#" + msg);
     document.documentElement.appendChild(iframe);
     iframe.parentNode.removeChild(iframe);
     iframe = null;
   }
}
UIWebViewの場合は。「ios-log:#iOS#xxx」というリクエストを発信します。
上記で「UIWebViewの場合は」という分岐を入れる理由は、 通常だと「ios-log:#iOS#xxx」というリクエストはエラー扱いになってしまい、 その後のJavaScript実行が中止されてしまうので、それを避けるためです。

UIWebViewを利用しているか否かは、UserAgentの上書き(詳しくはこちら)などを利用して判別することが出来ます。



UIWebViewでログ出力用のリクエストを補足して、内容をコンソールに出力する

JavaScriptでUIWebView向けに発信したリクエストをUIWebViewで細くすることで、 リクエストに含まれるログ内容をXCODEのコンソールに出力します。
リクエストを補足するために、UIWebViewのDelegateを利用します。
- (BOOL)webView:(UIWebView *)webView 
  shouldStartLoadWithRequest:(NSURLRequest *)request 
              navigationType:(UIWebViewNavigationType)navigationType {

  // リクエストに「ios-log:#iOS#」が含まれる場合には、リクエストをキャッチする。
  NSString* nextUrl=[[request URL] absoluteString];
  NSRange range;
  if ((range=[nextUrl rangeOfString:@"ios-log:"]).location!=NSNotFound) {

    // リクエスト内容から、ログ内容を取得する。
    NSString *iOSLog = [nextUrl stringByReplacingOccurrencesOfString:@"ios-log:"withString:@""];
    // 文字列はパーセントエスケープされているので、デコードする。
    iOSLog = [iOSLog stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSLog(@"%@",iOSLog);

    // このリクエストは、ここで中断する。
    returnNO;
  }    
    
  // 上記以外のリクエストは、そのまま発信する。  
  return YES;
}
UIWebViewDelegateの「shouldStartLoadWithRequest」のメソッドを利用することで、 実際にサーバーにリクエストを送る前に、内容を精査して中止することが出来ます。
今回はその機能を利用して、ログ出力用のリクエストの場合はキャッチして、XCODEのコンソールにログ出力をします。



エラー情報も出力する

上記でだいぶデバッグしやすくなるのですが、少し足りない。
JSで意図しないエラーが発生した場合(それもwondow.logを仕込んでいない箇所で)に、 ログも出ないし、画面も動かないし、何が悪いのかを特定するのが大変です。
そのため、エラー発生時のログ出力もJS側に実装するといいかと思います。
以下が実装例です。
window.onerror = function(errMsg, url, lineNumber) {
     window.log(errMsg + ", file=" + url + ":" + lineNumber);
}
上記の実装で、エラー原因とエラー箇所がログに出力されるので、デバッグしやすくなります。



最後に

組み込みのプログラムをデバッグすることは、比較的難しい。
こんな感じで少しずつでもデバッグを楽にすることが、作業の効率化に繋がるんだなぁと思っています。

より快適なデバッグ生活を求めて、これからも活動して、良き内容があればまたブログに書きたいと思います。
最後までご覧頂きましてありがとうございました。

 



こんな記事もいかがですか?

RSS画像

もしご興味をお持ち頂けましたら、ぜひRSSへの登録をお願い致します。