こんにちは、野口です。
2015年12月にWKWebViewに対応したCordova-iOS 4.0.0が正式にリリースされました。(2016年1月現在、最新はCordova-iOS 4.0.1になっています。)
今回は実際にCordovaでWKWebViewを動かしてみたいと思います。
実行環境
実行環境は以下の通りです。
ホストPC | OS X EL Capitan 10.11.3 |
Xcode | 7.2 |
cordova | 5.4.1 |
iOS | 9.2.1 / 8.3 |
プロジェクトの作成
# プロジェクト作成 # cordova create <<作成先フォルダ名>> <<アプリの識別子>> <<プロジェクト名>> $ cordova create sample jp.co.iti.wkwebview WKWebViewSample $ cd sample/ # iOS 用プロジェクト生成 $ cordova platform add ios@latest Adding ios project... iOS project created with cordova-ios@4.0.1 Discovered plugin "cordova-plugin-whitelist" in config.xml. Installing to the project Fetching plugin "cordova-plugin-whitelist@1" via npm Installing "cordova-plugin-whitelist" for ios # 正しく追加さている確認 $ cordova platform ls Installed platforms: ios 4.0.1 Available platforms: amazon-fireos, android, blackberry10, browser, firefoxos, osx, webos
CordovaでWKWebViewを利用するにはプラグインを追加する必要があるため、プラグインを追加します。
なお、Cordova上でWKWebViewが使用できるのはiOS9のみで、iOS8で動かした場合
はUIWebViewが使われます。
github.com
# WKWebView を利用するためのプラグインを追加 $ cordova plugin add cordova-plugin-wkwebview-engine --save Fetching plugin "cordova-plugin-wkwebview-engine" via npm Installing "cordova-plugin-wkwebview-engine" for ios Saved plugin info for "cordova-plugin-wkwebview-engine" to config.xml
このプラグインを追加すると、以下のファイルが追加されます。
実際にアプリを起動し、どのWebViewが使用されているかを確認します。
iOS9で確認すると、WKWebViewが使用されています。
iOS8で確認すると、UIWebViewが使用されています。
ただ、iOS8で確認した際、Variable ViewにはengineWebViewはUIWebViewとありますが、コンソールを確認すると以下のようなログが出力されてます。
2016-01-26 14:53:55.875 WKWebViewSample[5047:253914] Using WKWebView 2016-01-26 14:53:55.955 WKWebViewSample[5047:253914] Using UIWebView
これは本当にUIWebViewが使われているのか気になるので、Cordovaの実装を見て確認してみます。
- (UIView*)newCordovaViewWithFrame:(CGRect)bounds { NSString* defaultWebViewEngineClass = @"CDVUIWebViewEngine"; NSString* webViewEngineClass = [self.settings cordovaSettingForKey:@"CordovaWebViewEngine"]; if (!webViewEngineClass) { webViewEngineClass = defaultWebViewEngineClass; } // Find webViewEngine if (NSClassFromString(webViewEngineClass)) { self.webViewEngine = [[NSClassFromString(webViewEngineClass) alloc] initWithFrame:bounds]; // if a webView engine returns nil (not supported by the current iOS version) or doesn't conform to the protocol, or can't load the request, we use UIWebView if (!self.webViewEngine || ![self.webViewEngine conformsToProtocol:@protocol(CDVWebViewEngineProtocol)] || ![self.webViewEngine canLoadRequest:[NSURLRequest requestWithURL:self.appUrl]]) { self.webViewEngine = [[NSClassFromString(defaultWebViewEngineClass) alloc] initWithFrame:bounds]; } } else { self.webViewEngine = [[NSClassFromString(defaultWebViewEngineClass) alloc] initWithFrame:bounds]; } if ([self.webViewEngine isKindOfClass:[CDVPlugin class]]) { [self registerPlugin:(CDVPlugin*)self.webViewEngine withClassName:webViewEngineClass]; } return self.webViewEngine.engineWebView; }
ここでは、使用するwebViewEngineを設定しています。CDVWKWebViewEngineもしくはCDVUIWebViewEngineが設定されます。名前の通り、WKWebViewを使用する場合はCDVWKWebViewEngine、UIWebViewを使用する場合はCDVUIWebViewEngineが使用されます。
webViewEngineにまずCDVWKWebViewEngineが設定されますが、その後にWKWebViewが使用できないか判定し、使用できない場合、webViewEngineにCDVUIWebViewEngineが設定されます。
そのため、「Using WKWebView」というログが出た後に、「Using UIWebView」というログが出力されていました。
制約
Cordovaの問題ではなく、WKWebViewの問題になりますが、制約があります。
cordova-plugin-wkwebview-engineのREADMEを確認すると、以下の文言があります。
> you are still not able to use XHR from the file:// protocol without CORS
enabled on your server.
実際に、iOS9でAJAXリクエストを試してみましたが、以下の結果のように上手くいきませんでした。
①ローカルファイル(file://)から、同じく、ローカルファイルへのAJAXリクエスト
var req = new XMLHttpRequest(); req.open("GET", "sub/local.json", true); req.setRequestHeader('Cache-Control','no-cache'); req.send(null);
結果:以下のエラーが出て、リクエスト失敗しました。
「Failed to load resource:Origin null is not allowed by Access-Control-Allow-Origin.」
また、「req.setRequestHeader('Cache-Control','no-cache');」なしで、リクエストを投げたところ、「Cross origin requests are only supported for HTTP.」というエラーになりました。
②ローカルファイル(file://)から、WebサーバーへのAJAXリクエスト
サーバーサイドで「Access-Control-Allow-Origin: *」と設定済み
結果:以下のエラーが出て、リクエスト失敗しました。Access-Control-Allow-Originの設定をしていてもダメなようです。
「Failed to load resource:Origin null is not allowed by Access-Control-Allow-Origin.」
上記のリクエストヘッダ・レスポンスヘッダはOPTIONメソッドで送信されているのでプリフライトリクエストのものと思われます。そこでステータスコード200が返ってきていますが、リソースの読み込みに失敗しています。
iOS8でプラグイン呼び出しに失敗する
cordova-plugin-wkwebview-engineを入れているときに、iOS8でプラグイン呼び出しを行うと、以下のエラーが出て、プラグインを使用することができませんでした。
「TypeError: undefined is not an object (evaluating'window.webkit.messageHandlers')」
Cordova + WKWebView ではNative-WebViewのブリッジの方法がUIWebViewを使用するときとは異なっていました。
しかし、cordova-plugin-wkwebview-engineを入れていると、UIWebViewでもそのWKWebView用の新しい方法でプラグイン呼び出しを行おうとして、失敗していました。
この不具合は既にCordovaのJIRAに登録されているので、次回のアップデートで修正されると思われます。
まとめ
Cordova-iOS 4.0.1 でWKWebViewを試してみましたが、まだ制約や不具合があり、使用するには注意が必要そうです。