Android 7.0からはChromeがWebViewを提供する みたいのはあちこちでバズってる割に、中身の仕組みをちゃんと書いた記事は殆ど見ません。
個人的にはとても残念に思います。
ということで、中を見てみました。
まずは、Lollipopまでのおさらい
WebViewのAPIを提供するのが、WebViewFactoryProviderで、
WebViewFactory::getProvider
のなかで
- ネイティブ側の準備:libwebviewchromium.soの探索とロード
- パッケージ名はgetWebViewPackageName()で取得
- Java API側の準備:WebviewProviderの生成と初期化
- WebViewChromiumFactoryProviderが内部でWebViewDelegateを実装する
みたいな流れの処理があります。
ソースレベルで見たければこのへん。
- http://tools.oesf.biz/android-5.1.1_r9.0/xref/frameworks/base/core/java/android/webkit/WebView.java
- http://tools.oesf.biz/android-5.1.1_r9.0/xref/frameworks/base/core/java/android/webkit/WebViewFactory.java
- http://tools.oesf.biz/android-5.1.1_r9.0/xref/frameworks/webview/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
- http://tools.oesf.biz/android-5.1.1_r9.0/xref/frameworks/webview/chromium/java/com/android/webview/chromium/WebViewDelegateFactory.java
ポイントとしては、端末ベンダーが R.string.config_webViewPackageName
をオーバーライドして、
デフォルトは com.android.webview
を見にいくのを、ねじ曲げることができるようになっています。
public static String getWebViewPackageName() {
return AppGlobals.getInitialApplication().getString(
com.android.internal.R.string.config_webViewPackageName);
}
Marshmallowでどうなった?
AOSPからChromium WebViewのソースが削除されただけで、WebViewのロード自体は同じような仕組みで動いています。
この時期くらいからGoogleがChromeでWebView機能提供することを考え始めたのか、
ネイティブのパスがLollipopでは libwebviewchromium.so
ってハードコーディングされてたのが、Marshmallowでは パッケージの meta(com.android.webview.WebViewLibrary
)を見るように変わってたりはします。
で、Nougatでどう変わった?
結論から言うと、WebViewロードの仕組みは殆ど変わってません。設定の仕組みが追加されただけでした。
NougatではWebViewを提供するパッケージを開発者向けオプションで設定することができます。
ということは、システム設定に持ってるんですね。そこから辿ってみます。
public static final String ACTION_WEBVIEW_SETTINGS = "android.settings.WEBVIEW_SETTINGS";
なんと、Settings.javaに設定名ではなくて、インテントのアクションの定義が・・・。
設定画面の実装はどこにあるか辿ってみると、
ここです。
mWebViewUpdateService =
IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
try {
WebViewProviderInfo[] providers = mWebViewUpdateService.getValidWebViewPackages();
if (providers == null) {
Log.e(TAG, "No WebView providers available");
finish();
return;
}
String currentValue = mWebViewUpdateService.getCurrentWebViewPackageName();
if (currentValue == null) {
currentValue = "";
}
WebViewの機能を提供するパッケージを探索
↓
ダイアログ表示
↓
Settings.Global.WEBVIEW_PROVIDER
の設定値を更新
↓
WebViewFactory.onWebViewProviderChanged()
という流れです。
NougatではWebViewを提供するパッケージを設定できる仕組みが加わっただけで、WebViewの初期化部分とかって、Lollipopのときと大きくは変わってないんですね。
もしかすると、Marshmallowでも最近のChromeをプリインストールして、'R.string.config_webViewPackageName' を com.google.android.chrome
にして端末を焼けば、NougatみたいにChromeがWebViewを提供するようにできたりするんじゃないかなー、と・・・。(未検証ですw)
ソースレベルで見たければこのへん。
- http://tools.oesf.biz/android-7.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
- http://tools.oesf.biz/android-7.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/webkit/SystemImpl.java
ちなみに開発者向けオプションで変えない場合はどう動作してるの?というと、
http://tools.oesf.biz/android-7.0.0_r1.0/xref/frameworks/base/core/res/res/xml/config_webview_packages.xml
このXMLがWebViewUpdateService起動時に読まれて、適切なWebViewがロードされるようになってます。
このXMLは端末ベンダーがオーバーライド可能なので、NexusではAndroid WebViewではなくChromeが指定されてるという噂があります。
まとめ
NougatではWebViewのProviderを設定できる実装が入っただけで、
WebView実装を含んだAPKを選択的にロードする処理はLollipopからほとんど変わっていませんでした。
完全に余談ですが、
らくらくホン みたいに、今まではOSレベルで魔改造が必要だったWebViewも、今後はAPK載せてconfig変えるだけで動くようになるのはいい仕組みですね。万が一バグっててもGoogle Playアップデートもできるし。