Attention! Translated article might be found on my English blog.

2015年5月10日日曜日

WebViewでのconsole.log()の内容を取得する

WebView上でconsole.log()を実行した時にWebFrameLoadDelegateのdoConsoleLog:を実行させたい場合を考えます。大雑把な手順と実装例は以下のとおりです。


1. WebViewにWebFrameLoadDelegateをセットする

  詳細割愛。

2. delegateで-[WebFrameLoadDelegate webView:didClearWindowObject:forFrame:]を実装する

- (void)webView:(WebView *)webView didClearWindowObject:(WebScriptObject *)windowObject forFrame:(WebFrame *)frame {
    [windowObject setValue:self forKey:@"console"];
}
おそらくJS上でdelegateをconsoleとして扱うよう設定しているんだと思います。setValue:forKey:はKVC由来でしょうか。なお、CallJSではwebView:windowScriptObjectAvailable:で同様の処理を行っていますが、10.4でdeprecatedになっているようです。

3. delegateで+[NSObject(WebScripting) isSelectorExcludedFromWebScript:]を実装する

+ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector {
    return selector != @selector(doConsoleLog:);
}
doConsoleLog:だけJSから実行可能にしているんだと思います。

4. delegateで+[NSObject(WebScripting) webScriptNameForSelector:]を実装する
+ (NSString *) webScriptNameForSelector:(SEL)sel {
    return (sel == @selector(doConsoleLog:)) ? @"log" : nil;
}
こちらはJSとObjCとの間でメソッドを関連づけているのだと思います。

5. delegateでconsole.log()実行時に呼ばれるメソッドを実装する
- (void)doConsoleLog:(NSString *)message {
    NSLog(@"message:%@", message);
}
console.log()の引数がNSStringとして渡されてきます。

以上でconsole.log()をNSLog()で表示することが出来るようになります。
少しだけObjC-JS間のデバッグが楽になるんじゃないでしょうか…!

参考: CallJS - Apple Developer