以下Android公式ドキュメント Migrating to WebView in Android 4.4 の翻訳です。 間違いなどあればぜひご指摘ください。拙いですが誰かの役に立てば幸いです。
Android 4.4(API レベル 19)では、Chrominium ベースの新しい WebView が紹介されました。この変更で、WebView のパフォーマンス向上し、最新の Web ブラウザに追いつくために、HTML5、CSS3やJavaScript を標準サポートします。WebView を使っているアプリは、Android 4.4 以上からはこれらのアップデートの恩恵を受けることになります。
本ドキュメントは WebVeiew の変更点について説明します。なお、その変更は Android 4.4 以上、つまり targetSdkVersion を "19" 以上にした場合です。
Note: targetSdkVersion を "18" 以下にした場合、WebView は以下で述べるような挙動をすることを避けるために、"quirks モード" になります。これは、パフォーマンス向上と Web 標準に対応するためです。 しかし、次の点に注意してください。シングルカラムレイアウトや狭いカラムレイアウト・デフォルトズームレベルは Android 4.4 ではサポートされません。また、以前と関連のない挙動の違いも幾つかあります。そのため、targetSdkVersion を 18 以下にする場合は、Android 4.4 以上でアプリのテストを行ってください。
Android 4.4 で WebView を使うと、デスクトップで Chrome を使ったデバッグが出来るようになります。これを有効にするためには、setWebContentsDebuggingEnabled() を呼び出してください。この新機能は、WebView を実行時の Web コンテンツ・スクリプト・ネットワークアクティビティを調べることができます。もっと詳しく知りたい場合は、"Remote Debugging on Android" を参照してください。
ユーザーエージェントを利用している場合、変更があるため注意してください。Chrome バージョンが追加されます。 Mozilla/5.0 (Linux; Android 4.4; Nexus 4 Build/KRT16H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36 もし、ユーザーエージェントを取得するだけで、保存したり WebView インスタンスを作成しない場合は、static メソッドの getDefaultzuserAgent() を使ってください。ただし、WebView のユーザエージェントを上書きする場合は、 getUserAgentString() を使用してください。
WebView でアプリの UI スレッドでない他のスレッドからメソッドを呼んだ場合、予想外の結果をもたらす場合があります。例えば、複数スレッドを使っている時に、 runOnUiThread() メソッドを、UI スレッド上で実行されるように保証するために使った場合です。
runOnUiThread(new Runnable() {
@Override
public void run() {
// Code for WebView goes here
}
});
また、UI スレッドをブロックしてはいけませんnever block the UI thread。JavaScript のコールバックを待つためにそのような事をする事が考えられます。例えば、以下のようなコードは使っていけません。
// This code is BAD and will block the UI thread
webView.loadUrl("javascript:fn()");
while(result == null) {
Thread.sleep(100);
}
代わりに、新しいメソッドとして [evaluateJavascript()](http://developer.android.com/reference/android/webkit/WebView.html#evaluateJavascript(java.lang.String, android.webkit.ValueCallback<java.lang.String>) を JavaScript を非同期で実行させるために使用してください。
新しい WebView は、カスタム URL スキームを使ったリンクやリソースのリクエストに関して、制限を追加することができます。例えば、もし shouldOverrideUrlLoading() や shouldInterceptRequest() といったコールバックを実装すれば、有効な URL のみ実行することができます。
もし、カスタム URL スキーム・ベース URL・コールバック結果やロード失敗の通知を使う場合、RFC 3986 に則した有効な URL をリクエストすることを保証してください。
例えば、新しい WebView は以下タグから shouldOverrideUrlLoading() が呼ばれます。
<a href="showProfile">Show Profile</a>
リンク等の、ユーザーに寄るクリック結果は色々な結果を起こしうります。
- もし、loadData() や loadDataWithBaseURL() を不正な URL や null のベース URL で実行した場合、 shouldOverrideUrlLoading() コールバックを受け取ることができません。
- Note: loadDataWithBaseURL() を利用している場合や、ベース URL が不正であるか null のばあい場合、そのページでのすべてのリンクが absolute でなければいけません。
- loadUrl() や有効なベース URL を loadDataWithBaseURL() をつかってページをロードした場合、そのページで shouldOverrideUrlLoading() コールバックが返りますが、受け取る URL は absolute で、現在のページと関係がある状態になっています。例えば、"http://www.example.com/showProfile" の時に受け取るのは単に "showProfile" です。
上記に示したサンプルを使う代わりに、以下の様にカスタムスキームを利用することができます。
<a href="example-app:showProfile">Show Profile</a>
以下のように、上記 URL を shouldOverrideUrlLoading() でハンドルすることができます。
// The URL scheme should be non-hierarchical (no trailing slashes)
private static final String APP_SCHEME = "example-app:";
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith(APP_SCHEME)) {
urlData = URLDecoder.decode(url.substring(APP_SCHEME.length()), "UTF-8");
respondToData(urlData);
return true;
}
return false;
}
もし HTML を変更できない場合、 loadDataWithBaseURL() を使って、有効なカスタムスキームとホストで、"example-app://<valid_host_name>/" と言うようににベース URL を設定することができます。 以下例です。
webView.loadDataWithBaseURL("example-app://example.co.uk/", HTML_DATA, null, "UTF-8", null);
有効なホスト名は、RFC 3986 に従っていなければいけません。また、一番最後にスラッシュを追加することも重要です。そうでない場合、ロードされたページからのすべてのリクエストが無視されます。
以前では、WebView は target-densitydpi をサポートしていました。このプロパティは狙った画面解像度にするためのものです。このプロパティはサポートされません。よって、画像を使うか、Pixel-Perfect UI in the WebView を参考に移行してください。
以前は、viewport 設定で width を 320 以下にしていた場合、"device-width" が自動的に設定されていました。また、height が WebView の height 以下の場合は、"device-height" が設定されました。しかし、新しい WebView では width と height の値が適用され、screen width に合うように WebView が拡大されます。
以前は 1 つの WebView に 2 つの viewport タグがあった場合、そのプロパティはマージされていましたが、新しい WebView では一番最後の viewport 設定が利用され、それ以外は無視されます。
初期ズームレベルを設定・取得するための getDefaultZoom() と setDefaultZoom はサポートされません。また、代わりに適切な viewport 設定を Web ページにする必要があります。
Caution: これらの API は Android 4.4 以上ではサポートされません。また、targetSdkVersion が 18 以下であっても、これらの API は影響を受けません。
viewport 設定についての情報は、Pixel-Perfect UI in the WebView を参考にしてください。
もし、HTML に viewport の width を設定できない場合は、 setUserWideViewPort() を呼んでください。これは、大きい viewport 設定がページに確実に適用されるようにするためです。 以下例になります。
WebSettings settings = webView.getSettings();
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
Chrome や他のブラウザは、background を使うと background-size を上書きしています。新しい WebView では background と指定したスタイルであっても、同様に background-size が上書きされてしまいます 。例えば、以下の例では size のプロパティがデフォルトに設定されてしまいます。
.some-class {
background-size: contain;
background: url('images/image.png') no-repeat;
}
これは以下の様に修正してください。
.some-class {
background: url('images/image.png') no-repeat;
background-size: contain;
}
訳者メモ: 参考 https://developer.mozilla.org/ja/docs/Web/CSS/background-size
以前は、window.outterWidth や window.outerHeight という値が 実際の画面ピクセル数を返していました。新しい WebView では、先のメソッドを使うと CSS のピクセル単位の値が取得できます。
実際のピクセル数を計算するなどの方法で、エレメントのサイズを決めるのはバッドノウハウでしたが、zoom をオフにして initial-scale を 1.0 にすれば、window.devicePixelRatio を使って、CSS のピクセルサイズを取得できます。また、WebView から JavaScript のバインド を作成して、ピクセルサイズの問い合わせができるようにもできます。
もっと情報が必要な場合は以下のサイトを参照してください。
http://www.quirksmode.org/blog/archives/2012/03/windowouterwidt.html
新しい WebView では WebSettings.LayoutAlgorithm の NARROW_COLMUNS という値はサポートされません。 Caution: Android 4.4 以上からはこれらの API はサポートされません。たとえ targetSdkVersion が 18 以下であっても、この API は動きません。
この変更には以下の対応ができます。
- 他のスタイルを利用する
- もし HTML や CSS でページをコントロールしているなら、別の方法を使って一番確かな方法でデザインをコントロールできます。例えば、ライセンスに関する部分を表示するとして、テキストを pre タグで囲むことができます。以下のようなスタイルです。
<pre style="word-wrap: break-word; white-space: pre-wrap;">
- viewport 設定を使っていない場合は特に有効な方法でしょう
- TEXT_AUTOSIZING レイアウトアルゴリズムを利用する
- デスクトップ用のコンテンツをモバイル向けに提供している場合や、HTML コンテンツを変更できないために狭いカラムを使っているなら、新しい TEXT_AUTOSIZING アルゴリズムが代わりに使えるでしょう
加えて、すでに deprecated になっている SINGLE_COLUMNG は新しい WebView ではサポートされません。
WebView でのタッチイベントを直接ハンドリングしている場合、touchcancel イベントもハンドルすることに注意してください。touchcancel が呼ばれる場合がいくつか有ります。もし、このイベントを受け取っていなかった場合、問題を引き起こす可能性が有ります。
- エレメントがタッチされて(touchstart と touchmove が呼ばれ)、ページがスクロールされた時、touchcancel イベントが発生します
- エレメントがタッチされ(touchstart が呼ばれ)、しかし、event.preventDefault() が呼ばれない場合は、touchcancel が発生します(WebView はタッチイベントが実行されたくない状況だと判断します)