原始文章:https://developer.android.com/guide/webapps/migrating.html
Android 4.4(API level 19)引入了基于Chromium的WebView的新版本。这一更改升级了对HTML5、CSS3和JavaScript的WebView性能和标准支持以匹配最新的web浏览器。使用WebView的任何应用程序在运行Android 4.4和更高版本时都将继承这些升级。
该文档描述了对WebView的额外更改,如果您将targetSdkVersion设置为“19”或更高,您应该注意到这一点。
注意:如果你的targetSdkVersion被设置为“18”或更低,WebView在“quirks mode”中运行,以避免下面所描述的一些行为变化,尽可能地保持你的应用程序的性能和网络标准升级。当心,单身, single and narrow column layouts 和 default zoom levels不支持在Android 4.4,可能还有其他行为差异,尚未确定,所以一定要测试你的应用程序在Android 4.4或更高版本,即使你targetSdkVersion设置为“18”或更低。
为了帮助您解决您可能遇到的任何问题当你的应用程序迁移到WebView在Android 4.4中,您可以启用远程调试通过调用setWebContentsDebuggingEnabled Chrome在桌面上()。WebView中的这个新功能允许您在WebView中运行时检查和分析web内容、脚本和网络活动。有关更多信息,请参阅Android上的远程调试
如果您基于用户代理服务于WebView的内容,您应该意识到用户代理字符串已经稍微更改了,现在包括了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,您应该使用静态方法getDefaultUserAgent()。但是,如果您打算在WebView中覆盖用户代理字符串,那么您可能希望使用getUserAgentString()。
如果你从应用程序的UI线程以外的任何线程调用WebView的方法,它会导致意想不到的结果。例如,如果您的应用程序使用多个线程,您可以使用runOnUiThread()方法来确保您的代码在UI线程上执行:
runOnUiThread(new Runnable() {
@Override
public void run() {
// Code for WebView goes here
}
});
还要确保永远不会阻塞UI线程。有些应用程序在等待JavaScript回调时出现了这个错误。例如,不要使用这样的代码:
// This code is BAD and will block the UI thread
webView.loadUrl("javascript:fn()");
while(result == null) {
Thread.sleep(100);
}
您可以使用一个新的方法evaluateJavascript()来异步运行JavaScript。
新的WebView在请求资源和解析使用自定义URL方案的链接时应用了额外的限制。例如,如果实现了shouldOverrideUrlLoading()或shouldInterceptRequest()的回调,那么WebView只调用有效的url。
如果您使用自定义URL方案或基本URL,并注意到您的应用程序在这些回调中收到的调用较少或在Android 4.4上加载资源失败,请确保请求指定符合RFC 3986的有效URL。
例如,新的WebView可能不会像这样的链接调用你的shouldOverrideUrlLoading()方法:
<a href="showProfile">Show Profilea>
用户点击此链接的结果可能有所不同:
注意:当您使用loadDataWithBaseURL()并且基本URL无效或设置为null时,正在加载的内容中的所有链接必须是绝对的。
代替如上所示在链接中使用简单的字符串,您可以使用自定义方案,如下所示:
<a href="example-app:showProfile">Show Profilea>
然后,您可以在您的shouldOverrideUrlLoading()方法中处理此URL,如下所示:
// 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()并设置由自定义方案和有效主机组成的基本URL,例如“example-app:// /”。 例如:
webView.loadDataWithBaseURL("example-app://example.co.uk/", HTML_DATA,
null, "UTF-8", null);
有效的主机名应符合RFC 3986的要求,最后包括尾部斜线,否则可能会丢弃来自加载页面的任何请求
以前,WebView支持一个名为target-densitydpi的属性,以帮助网页指定其预期的屏幕密度。 此属性不再受支持,您应该迁移到使用图像和CSS的标准解决方案,如 完美的WebView UI。
以前,如果将视口宽度设置为小于或等于“320”的值,则将其设置为“device-width”,如果将视口高度设置为小于或等于WebView高度的值 将设置为“device-height”。 但是,当在新的WebView中运行时,会粘贴宽度或高度值,WebView会放大以填充屏幕宽度.
以前,如果在网页中包含多个Viewport标签,WebView将合并所有标签的属性。 在新的WebView中,仅使用最后一个Viewport,并忽略所有其他Viewport。
getDefaultZoom()和setDefaultZoom()用于获取和设置页面上的初始缩放级别已不再受支持,您应该在网页中定义相应的Viewport。
注意:Android 4.4及更高版本不支持这些API。 即使您的targetSdkVersion设置为“18”或更低,这些API也不起作用。
有关如何在HTML中定义视口属性的信息,请参考 完美的WebView UI
如果您无法在HTML中设置Viewport的宽度,那么您应该调用setUseWideViewPort()来确保页面被赋予较大的Viewport。 例如:
WebSettings settings = webView.getSettings();
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
Chrome和其他浏览器已经有这样的行为了一段时间,但是如果您还指定了背景样式,那么WebView也会为background-size重写CSS设置。 例如,这里的大小将重置为默认值:
.some-class {
background-size: contain;
background: url('images/image.png') no-repeat;
}
修复是简单地交换两个属性顺序。
.some-class {
background: url('images/image.png') no-repeat;
background-size: contain;
}
以前,诸如window.outerWidth和window.outerHeight之类的大小参数会返回一个实际的屏幕像素值。 在新的WebView中,这些返回基于CSS像素的值。
通常不好的做法是尝试并使用以像素为单位的物理尺寸来调整元素或其他计算。 但是,如果禁用缩放,并将初始化设置为1.0,则可以使用window.devicePixelRatio获取缩放比例,然后将CSS像素值乘以该像素值。 同时,您还可以创建一个JavaScript绑定来从WebView本身查询像素值。
新的WebView不支持WebSettings.LayoutAlgorithm的NARROW_COLUMNS值。
注意:Android 4.4及更高版本不支持这些API。 即使您的targetSdkVersion设置为“18”或更低,这些API也不起作用。
您可以通过以下方式处理此更改:
如果您在页面中控制HTML和CSS,您可能会发现,更改内容的设计可能是最可靠的方法。 例如,对于您引用许可证的屏幕,您可能需要在< pre>标签内包装文本,您可以使用以下样式:
<pre style="word-wrap: break-word; white-space: pre-wrap;">
如果您尚未定义页面的Viewport属性,这可能会特别有用。
此外,新的WebView中也不支持SINGLE_COLUMN值(以前已被弃用)。
如果您的网页直接处理WebView中的触摸事件,请确保您还处理触摸取消事件。 触摸取消有几种情况将被调用,如果没有调用到可能会导致一些问题:
触摸一个元素(所以touchstart和touchmove被调用),并且页面被滚动,导致touchcancel被抛出。
一个元素被触摸(touchstart被调用),但是event. preventdefault()并没有调用,从而导致了touchcancel被抛出(所以WebView假设你不想使用触摸事件)。