WebKitを試す
iOS8では,WebKitの一部がAPIとして公開された. 元々,OSXではDOMにまでアクセスでき,自由に使えていたWebKitだが,iOSでは,UIWebView程度しか利用できなかった. iOS8では,限定的にWebKitの機能がAPIを一部公開する形で利用できるようになったのである. まず,簡単な機能面から利用できるようになったものを見てみる.
できるようになったこと
- 履歴
- ステータスコード
- 読み込みの進捗状況の推定値
- Javascriptのアラートの受け取り
他にもいくつかあるが,目立ったものをリストにしてみた. OSXなら当たり前にできるのだが,UIWebViewではできなかった機能だ.
WebKitで利用するクラス
WebKitを利用するためのクラスがいくつか公開された.
ドキュメントがあるもの
- WKBackForwardList
- WKBackForwardListItem
- WKFrameInfo
- WKNavigation
- WKNavigationAction
- WKNavigationResponse
- WKPreferences
- WKProcessPool
- WKScriptMessage
- WKUserContentController
- WKUserScript
- WKWebViewConfiguration
- WKWebView
- WKWindowFeatures
ドキュメントがない,あるいはほとんどないもの
- WKUserScript
WKWebViewを使ってみる
WKWebViewは,UIWebViewのようにStoryboard上でコントロールとして追加できない. このため,コードでviewに配置することになる.
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:nil];
webView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:webView];
webView.navigationDelegate = self;
webView.UIDelegate = self;
// Autolayout
NSDictionary *views = NSDictionaryOfVariableBindings(webView);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[webView(>=0)]-0-|"
options:0
metrics:nil
views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[webView(>=0)]-0-|" options:0
metrics:nil
views:views]];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.apple.com"]]];
この辺の使い勝手は,UIWebViewと変わらない.
JavascriptをHTMLに追加してみる
WKWebViewConfigurationオブジェクトを使って,WKWebViewを生成する. このときに,WKWebViewConfigurationオブジェクトにJavascriptを事前にセットしておくと,WKWebViewで読み込んだHTMLにそのJavascriptのコードを読み込ませることができる. まずは,JavascriptをセットしたWKWebViewを生成してみる.
// Create WKWebViewConfiguration object in order to attach javascript to html content.
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
configuration.userContentController = [[WKUserContentController alloc] init];
// Javascript
NSString *src
= @"function hoge() {alert('this is alert message which is defined on Objective-C.');}"
// Create javascript to attach html content.
WKUserScript *script = [[WKUserScript alloc] initWithSource:src
injectionTime:WKUserScriptInjectionTimeAtDocumentStart
forMainFrameOnly:YES];
// Add javascript to configuration object
[configuration.userContentController addUserScript:script];
// Create and add WKWebView to self.view.
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
以上である. WKWebViewConfigurationオブジェクトがWKUserContentControllerプロパティを持ち,WKUserContentControllerオブジェクトがWKUserScriptオブジェクトの追加対象となる. WKUserScriptクラスは,現在ドキュメントがないので,ヘッダファイルを見て,大体の利用方法を類推してみた. WKUserScriptオブジェクトの生成時にJavascript本体,スクリプトを挿入するタイミング,挿入するフレームをメインフレームに限定するかのフラグの3つを指定してWKUserScriptオブジェクトを生成できる.
WKWebViewに,このhogeを実行する,以下のようなHTMLを読み込ませる.
<html>
<script>
function OnButtonClick() {
hoge();
}
</script>
<body>
<font size=20>
<input type="button" value="push" onclick="OnButtonClick();"/>
</font>
</body>
</html>
ボタンを押すと,アラートが表示されるはず・・・・だが,表示されない.なぜだろう.これはWKWebViewを使う場合,Javascriptのアラートを自前で処理しなければならないためである.
WKUIDelegateプロトコル
このプロトコルは,ユーザがWKWebViewを操作したときに,対応するためのプロトコルである.
たとえば,Javascriptからalert(‘hoge’);を実行した場合,webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler;
がコールされる.
ゆえに,上のHTMLコンテンツのボタンを押したタイミングでアラートを表示させるためには,以下のようにコードを書く必要がある.
- (void)webView:(WKWebView *)webView
runJavaScriptAlertPanelWithMessage:(NSString *)message
initiatedByFrame:(WKFrameInfo *)frame
completionHandler:(void (^)())completionHandler {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@""
message:message
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:@"OK", nil];
[alert show];
completionHandler();
}
他には,confirm,promptを使ったユーザインタラクションも同様に以下の二つのWKUIDelegateプロトコルを用いて実装する必要がある.
- (void)webView:(WKWebView *)webView
runJavaScriptConfirmPanelWithMessage:(NSString *)message
initiatedByFrame:(WKFrameInfo *)frame
completionHandler:(void (^)(BOOL result))completionHandler {
completionHandler(YES);
}
- (void)webView:(WKWebView *)webView
runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt
defaultText:(NSString *)defaultText
initiatedByFrame:(WKFrameInfo *)frame
completionHandler:(void (^)(NSString *result))completionHandler {
completionHandler(@"New value set here.");
}
WKUIDelegateには,もう一つメソッドがあり,それは,既存のWKWebView内で新しいウィンドウやフレームを指定してコンテンツが開かれようとしているときに,そのコンテンツを読み込むWKWebViewを生成して,WebKitのランタイムに渡すメソッドである.
- (WKWebView *)webView:(WKWebView *)webView
createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration
forNavigationAction:(WKNavigationAction *)navigationAction
windowFeatures:(WKWindowFeatures *)windowFeatures {
// create new WKWebView
WKWebView *newWebView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
[self.view addSubview:newWebView];
return newWebView;
}
このサンプルは,指定されたConfigurationを使って作成したWKWebViewオブジェクトをそのまま追加するだけのコードであり,厳密には正しくないことを留意して欲しい.
WKWindowFeatures
は,Javascriptのwindow.open
のfeatures
に対応しているようだ.
HTML側でJavascriptを使って開いたウィンドウの設定をここで受け取ることができる.